{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://ao3575911.github.io/living-repos-protocol/schemas/v0.4.0/manifest.schema.json",
  "title": "Living Repository Manifest",
  "description": "Manifest at .living/manifest.yaml. Defined in docs/spec.md.",
  "type": "object",
  "required": [
    "protocol_version",
    "project_id",
    "agent_capabilities",
    "isolation_profile",
    "state_publication",
    "logging_requirements"
  ],
  "additionalProperties": false,
  "patternProperties": {
    "^x-": {
      "description": "Extension field. Runtimes that do not understand it must ignore it."
    }
  },
  "properties": {
    "protocol_version": {
      "type": "string",
      "pattern": "^v\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z.-]+)?$",
      "description": "Protocol version the manifest targets: v followed by SemVer, for example v0.1.0-draft."
    },
    "project_id": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]{0,62}$",
      "description": "Stable repository identifier: lowercase letters, digits and hyphens, at most 63 characters."
    },
    "agent_capabilities": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "enum": [
          "run_tasks",
          "publish_state",
          "open_pull_requests",
          "snapshot_restore",
          "handoff",
          "read_secrets"
        ],
        "description": "run_tasks, publish_state, open_pull_requests, snapshot_restore, handoff or read_secrets. See docs/spec.md."
      },
      "description": "What the agent may do. A runtime must refuse to start an agent that declares a capability it does not support."
    },
    "isolation_profile": {
      "enum": [
        "dedicated-vm",
        "container",
        "sandbox-process"
      ],
      "description": "How the runtime isolates the agent."
    },
    "state_publication": {
      "type": "object",
      "required": [
        "target"
      ],
      "additionalProperties": false,
      "properties": {
        "target": {
          "enum": [
            "control-process",
            "file",
            "webhook"
          ],
          "description": "control-process, file or webhook."
        },
        "path": {
          "type": "string",
          "minLength": 1,
          "description": "State file path relative to the repository root. Required when target is file."
        },
        "url": {
          "type": "string",
          "pattern": "^https://",
          "description": "https URL that receives state. Required when target is webhook."
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "target": {
                "const": "file"
              }
            }
          },
          "then": {
            "required": [
              "path"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "target": {
                "const": "webhook"
              }
            }
          },
          "then": {
            "required": [
              "url"
            ]
          }
        }
      ],
      "description": "Where the agent publishes its state."
    },
    "logging_requirements": {
      "type": "object",
      "required": [
        "structured"
      ],
      "additionalProperties": false,
      "properties": {
        "structured": {
          "type": "boolean",
          "description": "true means one JSON object per log line."
        },
        "level": {
          "enum": [
            "debug",
            "info",
            "warn",
            "error"
          ],
          "description": "Minimum log level. Default info."
        }
      },
      "description": "How the agent logs."
    },
    "snapshot": {
      "type": "object",
      "description": "What the runtime snapshots and how long it keeps snapshots. Used with the snapshot_restore capability. Optional.",
      "required": [
        "paths"
      ],
      "additionalProperties": false,
      "properties": {
        "paths": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "description": "Paths relative to the repository root to include in each snapshot.",
          "items": {
            "type": "string",
            "minLength": 1,
            "pattern": "^(?!/)(?!.*\\.\\.)",
            "description": "Relative path without .. segments."
          }
        },
        "retention_days": {
          "type": "integer",
          "minimum": 1,
          "description": "Days to keep each snapshot. Default 7."
        }
      }
    },
    "secrets": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "description": "Names of the secrets the agent needs, never their values. Requires the read_secrets capability. Optional.",
      "items": {
        "type": "string",
        "pattern": "^[A-Z][A-Z0-9_]{0,127}$",
        "description": "Secret name: uppercase letters, digits and underscores, starting with a letter."
      }
    }
  },
  "allOf": [
    {
      "if": {
        "required": [
          "secrets"
        ]
      },
      "then": {
        "properties": {
          "agent_capabilities": {
            "contains": {
              "const": "read_secrets"
            }
          }
        }
      }
    }
  ]
}
