{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://capsule.spec/manifest/v0.3.0",
  "title": "Capsule Manifest v0.3.0",
  "description": "Schema for the capsule-manifest section of a Capsule.",
  "type": "object",
  "required": [
    "spec_version",
    "uuid",
    "title",
    "description",
    "type",
    "created_at",
    "generator",
    "source",
    "privacy",
    "capabilities"
  ],
  "anyOf": [
    {"required": ["capsule_version"]},
    {"required": ["artifact_version"]}
  ],
  "properties": {
    "spec_version": {
      "type": "string",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "description": "Capsule spec version. Semver."
    },
    "capsule_id": {
      "type": "string",
      "pattern": "^capsule:.+$",
      "description": "DEPRECATED in v0.3.0. Optional human-readable slug (e.g., capsule:tn_visa_briefing). The UUID is the canonical machine identity, and slugs aren't guaranteed unique — two unrelated conversations can produce the same slug. The slug is fully derivable from `title` (slugify it at display time), so storing it is redundant. Still accepted in v0.3 for backward compatibility; planned for removal in v0.4. New capsules should rely on `uuid` and `title` only."
    },
    "capsule_version": {
      "type": "string",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "description": "Instance version. Semver. Introduced in v0.2.0; replaces the legacy artifact_version field."
    },
    "artifact_id": {
      "type": "string",
      "pattern": "^artifact:.+$",
      "description": "DEPRECATED in v0.2.0. Legacy alias for capsule_id. Still accepted; new capsules should use capsule_id."
    },
    "artifact_version": {
      "type": "string",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "description": "DEPRECATED in v0.2.0. Legacy alias for capsule_version. Still accepted; new capsules should use capsule_version."
    },
    "uuid": {
      "type": "string",
      "format": "uuid",
      "description": "UUIDv4. Globally unique per compilation. The canonical machine identifier for the capsule (as of Core v0.1.5)."
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "description": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000
    },
    "type": {
      "type": "string",
      "description": "Free-form artifact type. Recommended values: interactive_report, decision_board, assessment, reference, dashboard, learning_object, collection, form, narrative, summary, briefing, custom. LLMs producing capsules in the wild often reach for 'summary' or 'briefing' which are now recommended values."
    },
    "profile": {
      "type": "string",
      "enum": ["static", "interactive", "data"],
      "description": "Optional validation overlay for how the fixed five-block envelope is used. Profiles do not make any required block optional."
    },
    "presentations": {
      "type": "array",
      "description": "Declared capsule-owned presentation views. Hosts may surface these views, but should not infer undeclared views from layout or styling. Capsule presentation entries are fragment selectors that resolve to element ids inside the same HTML file.",
      "items": {
        "type": "object",
        "required": ["id", "profile", "entry"],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_-]*$",
            "description": "Unique stable id for this declared presentation."
          },
          "profile": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$",
            "description": "Core presentation profile (reader, mobile, print-letter, slides, reel, interactive) or namespaced extension such as x-domain.view or org.example.view."
          },
          "entry": {
            "type": "string",
            "pattern": "^#[A-Za-z][A-Za-z0-9_.:-]*$",
            "description": "Fragment selector resolving to an element id in this Capsule. Relative file paths belong to Bundle, not single-file Capsule."
          },
          "required": {
            "type": "boolean",
            "description": "Whether this presentation is part of the capsule's required contract. Broken required presentations fail validation."
          },
          "media": {
            "type": "string",
            "description": "Optional media context, e.g. print."
          },
          "navigation": {
            "type": "string",
            "enum": ["scroll", "paged", "step", "sequence"],
            "description": "Optional navigation model for this presentation."
          },
          "chrome": {
            "type": "string",
            "enum": ["capsule", "host", "none"],
            "description": "Optional control/chrome ownership hint. 'capsule' means the declared DOM owns its own controls and hosts should recede; 'host' means the host may supply presentation controls around the declared entry; 'none' means the entry is content-only."
          },
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string",
            "maxLength": 1000
          }
        },
        "additionalProperties": false
      }
    },
    "created_at": {
      "type": "string",
      "format": "date-time"
    },
    "audience": {
      "type": "string",
      "maxLength": 200,
      "description": "Intended recipient or group. Distinct from privacy.visibility (access control); audience describes intent."
    },
    "generator": {
      "type": "object",
      "required": ["name", "version", "kind"],
      "properties": {
        "name": { "type": "string" },
        "version": { "type": "string" },
        "kind": {
          "type": "string",
          "enum": ["compiler", "llm", "human", "hybrid"],
          "description": "What kind of process produced the HTML. Adjusts validator and registry trust expectations."
        },
        "spec_provided": {
          "type": "boolean",
          "description": "For kind: llm — whether the producer was given the spec as context."
        },
        "spec_version_used": {
          "type": "string",
          "description": "The spec version the producer targeted."
        }
      },
      "additionalProperties": false
    },
    "synthesis": {
      "type": ["object", "null"],
      "description": "Present when an LLM or other process synthesized the data content. Absent or null when data came from a structured source.",
      "required": ["kind", "model", "human_reviewed"],
      "properties": {
        "kind": {
          "type": "string",
          "description": "Recommended values: ai_extraction, ai_summarization, ai_generation, llm_summary, llm_synthesis, other. Free-form."
        },
        "model": { "type": "string" },
        "source_input": { "type": "string" },
        "human_reviewed": { "type": "boolean" },
        "synthesized_at": { "type": "string", "format": "date-time" },
        "notes": { "type": "string", "maxLength": 2000 }
      },
      "additionalProperties": false
    },
    "source": {
      "type": "object",
      "required": ["origin", "snapshot_type", "snapshot_id", "included_records"],
      "properties": {
        "origin": {
          "type": "string",
          "description": "Where the data came from. Recommended values: private_database, web_research, public_documents, ai_synthesis, user_input, observation. Free-form to accommodate the LLM-in-the-wild case which has no private database."
        },
        "snapshot_type": {
          "type": "string",
          "description": "Recommended values: portable_excerpt, full_table, computed, summary, synthesis, aggregation, capture. Free-form to accommodate AI-synthesized capsules."
        },
        "snapshot_id": {
          "type": "string",
          "pattern": "^snapshot:.+$"
        },
        "included_records": {
          "type": "integer",
          "minimum": 0
        },
        "source_schema_version": {
          "type": "string"
        },
        "spec_received": {
          "type": "string",
          "maxLength": 200,
          "description": "Version string of the Core spec the producer was given (e.g., 'v0.1.0 · 2026-05-16'). Optional but encouraged for LLM-produced capsules — lets future readers correlate output with the spec version that produced it."
        },
        "prompt_received": {
          "type": "string",
          "maxLength": 5000,
          "description": "Verbatim prompt the producer was given. Optional but encouraged for LLM-produced capsules — turns the manifest into a self-documenting research record."
        },
        "references": {
          "type": "array",
          "description": "Individual upstream sources this capsule draws from.",
          "items": {
            "type": "object",
            "required": ["id", "title"],
            "properties": {
              "id": { "type": "string" },
              "title": { "type": "string" },
              "hash": { "type": "string", "pattern": "^(sha256|sha384|sha512):[a-f0-9]+$" }
            },
            "additionalProperties": false
          }
        }
      },
      "additionalProperties": false
    },
    "privacy": {
      "type": "object",
      "required": [
        "visibility",
        "contains_private_data",
        "redaction_applied",
        "external_dependencies"
      ],
      "properties": {
        "visibility": {
          "type": "string",
          "enum": ["private", "shared", "public"]
        },
        "contains_private_data": {
          "type": "boolean"
        },
        "redaction_applied": {
          "type": "boolean"
        },
        "redaction_method": {
          "type": "string",
          "enum": ["field_removal", "value_masking", "aggregation", "none"]
        },
        "redaction_profile": {
          "type": "string",
          "description": "Named profile identifier. Rules live in the private system; the capsule records which profile was applied."
        },
        "reviewed_by": {
          "type": "string"
        },
        "reviewed_at": {
          "type": "string",
          "format": "date-time"
        },
        "external_dependencies": {
          "type": "boolean",
          "const": false
        }
      },
      "additionalProperties": false
    },
    "integrity": {
      "type": "object",
      "required": ["content_hash", "hash_scope"],
      "properties": {
        "content_hash": {
          "type": "string",
          "pattern": "^(sha256|sha384|sha512):[a-f0-9]+$"
        },
        "hash_scope": {
          "type": "string",
          "enum": ["data+manifest", "full_document", "data_only"]
        }
      },
      "additionalProperties": false
    },
    "capabilities": {
      "type": "array",
      "minItems": 2,
      "items": {
        "type": "string",
        "pattern": "^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$",
        "description": "Core capability, restricted declaration, or namespaced extension. Capabilities are declarations, not permissions. network.request is prohibited by the Capsule validator because Capsules have no network dependency."
      },
      "contains": { "const": "about" },
      "description": "Must include 'about' and at least one export capability. Core capabilities are controlled names; restricted declarations are host-denied unless explicitly allowed; extension capabilities use x-* or dotted/reverse-DNS namespacing."
    },
    "expires_at": {
      "type": ["string", "null"],
      "format": "date-time"
    },
    "parents": {
      "type": "array",
      "description": "Provenance: capsules this one was forked from. A new capsule records each upstream capsule that informed it (one parent if continuing a single capsule, multiple if combining/comparing). Each entry is a hard machine-actionable pointer (UUID + denormalized title for human readability). Introduced in v0.3.0.",
      "items": {
        "type": "object",
        "required": ["uuid", "title"],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "The parent capsule's UUID (v4). Machine-actionable provenance reference."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The parent capsule's title at the time of forking. Denormalized for human readability so readers don't have to dereference the UUID to know what the parent was. Frozen at fork-time; doesn't update if the parent is later re-compiled."
          }
        },
        "additionalProperties": false
      }
    },
    "derived_from": {
      "type": "array",
      "description": "Non-Capsule provenance: datasets, documents, chats, screenshots, photographs, Bundles, and other sources this Capsule depends on or references. Use parents[] only for Capsule-to-Capsule lineage.",
      "items": {
        "type": "object",
        "required": ["type", "title"],
        "properties": {
          "type": {
            "type": "string",
            "minLength": 1,
            "description": "Short source kind such as chat, dataset, document, screenshot, photograph, survey, webpage, book, article, or domain-specific values."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "Human-readable source label."
          },
          "reference": {
            "type": ["string", "null"],
            "description": "URL, URN, DOI, local/private reference, or null when the source has no stable identifier."
          },
          "role": {
            "type": "string",
            "maxLength": 300,
            "description": "How this source informed the Capsule."
          },
          "hash": {
            "type": "string",
            "pattern": "^(sha256|sha384|sha512):[a-f0-9]+$"
          },
          "date": {
            "type": "string",
            "description": "ISO 8601 date or datetime for the source when known."
          }
        },
        "additionalProperties": true
      }
    },
    "related": {
      "type": "array",
      "description": "DEPRECATED in v0.3.0 and planned for removal in v0.4. Was intended for soft associations between capsules (sibling, supersedes, related) but was unused in practice. Hard provenance now lives in `parents` (UUID-based). Soft associations belong in capsule prose, not in structured metadata — schema fields invite the AI to fabricate edges that aren't load-bearing.",
      "items": {
        "type": "object",
        "required": ["capsule_id", "title", "relationship"],
        "properties": {
          "capsule_id": { "type": "string", "pattern": "^capsule:.+$" },
          "title": { "type": "string" },
          "relationship": {
            "type": "string",
            "enum": ["parent", "sibling", "supersedes", "related"]
          },
          "uuid": { "type": "string", "format": "uuid" }
        },
        "additionalProperties": false
      }
    },
    "compilation": {
      "type": "object",
      "properties": {
        "compiled_at": { "type": "string", "format": "date-time" },
        "source_query": { "type": "string" },
        "compilation_duration_ms": { "type": "integer", "minimum": 0 },
        "warnings": {
          "type": "array",
          "items": { "type": "string" }
        },
        "output_size_bytes": { "type": "integer", "minimum": 0 }
      },
      "additionalProperties": false
    }
  },
  "patternProperties": {
    "^x-": {
      "description": "Extension fields. Capsule authors may add x-prefixed top-level properties to carry experimental, domain-specific, or vendor-specific metadata without forking the schema. Standard consumers should ignore unknown x- fields."
    }
  },
  "additionalProperties": false
}
