{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://unpkg.com/context-room@latest/schemas/config.schema.json",
  "title": "Context Room project configuration",
  "description": "Configuration for the local Context Room documentation control room.",
  "type": "object",
  "additionalProperties": true,
  "properties": {
    "$schema": {
      "type": "string",
      "description": "Optional JSON Schema URL for editor autocomplete."
    },
    "title": {
      "type": "string",
      "description": "Display title for this project."
    },
    "projectOnly": {
      "type": "boolean",
      "description": "When true, ordinary project paths must remain physically inside this project root after symbolic links are resolved. Fresh setup writes true. False, or omission in a legacy config, can make configured external symlink targets readable and editable; retain that mode only for trusted established hubs.",
      "default": false
    },
    "allowedPaths": {
      "type": "array",
      "description": "Safety boundary. Context Room can only read/write editable text files inside these project-relative files or folders and explicitly listed ~/... home paths.",
      "items": { "$ref": "#/$defs/allowedPath" },
      "uniqueItems": true,
      "default": ["docs/", "context/", "skills/", "README.md", "AGENTS.md"]
    },
    "readOnlyPaths": {
      "type": "array",
      "description": "Allowed project-relative or explicit ~/... paths that Context Room may display but must never create, edit, or delete. Shared accepted snapshots should be exposed here.",
      "items": { "$ref": "#/$defs/allowedPath" },
      "uniqueItems": true,
      "default": []
    },
    "watchAllow": {
      "type": "array",
      "description": "Files or folders whose current content versions require human verification. A verified content hash leaves the queue; any content change creates a new review. Folder entries use recursive-live behavior: current and future files at any depth can appear for verification.",
      "items": { "$ref": "#/$defs/allowedPath" },
      "uniqueItems": true,
      "default": []
    },
    "watchRules": {
      "type": "array",
      "description": "Explicit folder watch rules covered by allowedPaths. Use these when a folder needs direct-child scope or a frozen current-file snapshot instead of the default recursive-live behavior.",
      "items": { "$ref": "#/$defs/watchRule" },
      "default": []
    },
    "reviewPaths": {
      "type": "array",
      "description": "Deprecated compatibility field. Context Room reads these paths into the unified watched-document scope when allowedPaths covers them, then removes the field on the next human Settings save.",
      "deprecated": true,
      "items": { "$ref": "#/$defs/projectPath" },
      "uniqueItems": true
    },
    "reviewAgentInstructions": {
      "type": "boolean",
      "description": "Deprecated compatibility field. Project AGENTS.md files now follow the same implicit watched-document review rule as every other watched document.",
      "deprecated": true
    },
    "sharedContext": {
      "type": ["object", "null"],
      "description": "Generated shared-context connection summary. Use `context-room shared setup` instead of editing this object directly.",
      "additionalProperties": true,
      "properties": {
        "enabled": { "type": "boolean" },
        "repository": { "type": "string" },
        "projectId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,62}$" }
      }
    },
    "markdownTemplates": {
      "type": "array",
      "description": "Markdown templates available when creating new .md files from the site. Supports {{title}}, {{path}}, and metadata placeholders such as {{scope_yaml}}, {{status_yaml}}, {{canonical_for_yaml}}, {{last_verified_yaml}}, {{sources_inline}}, and {{sources_list}}.",
      "items": { "$ref": "#/$defs/markdownTemplate" },
      "default": []
    },
    "startupContext": {
      "type": "object",
      "description": "Optional scanner for agent instruction files in the project or, when projectOnly is false, its ancestors and explicit global paths. External files stay separate from the normal explorer.",
      "additionalProperties": true,
      "properties": {
        "enabled": { "type": "boolean", "default": false },
        "projectOnly": {
          "type": "boolean",
          "description": "When true, scan only this project root and ignore ancestor and explicit global instruction files.",
          "default": false
        },
        "fileNames": {
          "type": "array",
          "items": { "type": "string", "minLength": 1 },
          "uniqueItems": true,
          "default": ["AGENTS.md", "CLAUDE.md"]
        },
        "globalPaths": {
          "type": "array",
          "description": "Explicit global agent instruction files outside the ancestor chain, such as ~/.codex/AGENTS.md.",
          "items": { "$ref": "#/$defs/homePath" },
          "uniqueItems": true,
          "default": ["~/.codex/AGENTS.md"]
        }
      }
    },
    "startupSkills": {
      "type": "object",
      "description": "Optional scanner for project skill folders or, when projectOnly is false, matching folders in ancestor directories.",
      "additionalProperties": true,
      "properties": {
        "enabled": { "type": "boolean", "default": true },
        "projectOnly": {
          "type": "boolean",
          "description": "When true, scan skill folders only inside this project root instead of every ancestor directory.",
          "default": false
        },
        "folderNames": {
          "type": "array",
          "items": { "type": "string", "minLength": 1 },
          "uniqueItems": true,
          "default": [".agents/skills", "skills"]
        }
      }
    },
    "startupHooks": {
      "type": "object",
      "description": "Optional scanner for hooks and hook-manager files that can affect agent work, commits, or validation.",
      "additionalProperties": true,
      "properties": {
        "enabled": { "type": "boolean", "default": true },
        "projectOnly": {
          "type": "boolean",
          "description": "When true, scan agent hook configuration only inside this project root. Effective Git hooks and project hook-manager files remain project-scoped.",
          "default": false
        },
        "editable": {
          "type": "boolean",
          "description": "When true, Context Room can edit detected hook files. Off by default because hooks execute code.",
          "default": false
        },
        "agentHooks": {
          "type": "boolean",
          "description": "Scan AI coding agent hook configuration and plugin files, including Codex, Claude Code, OpenCode, and compatible tools.",
          "default": true
        },
        "agentHookSources": {
          "type": "array",
          "description": "Configurable AI coding systems to show in Startup hooks. Each source has a label and one or more project-relative config/plugin paths.",
          "items": {
            "type": "object",
            "additionalProperties": true,
            "required": ["label", "paths"],
            "properties": {
              "id": {
                "type": "string",
                "description": "Stable source id used for filtering."
              },
              "label": {
                "type": "string",
                "minLength": 1,
                "description": "Human-readable agent system name, such as Codex or My Agent."
              },
              "paths": {
                "type": "array",
                "items": { "$ref": "#/$defs/projectPath" },
                "minItems": 1,
                "description": "Config files or plugin folders to scan for this agent system."
              }
            }
          },
          "default": [
            { "id": "codex", "label": "Codex", "paths": [".codex/hooks.json"] },
            { "id": "claude-code", "label": "Claude Code", "paths": [".claude/settings.json", ".claude/settings.local.json"] },
            { "id": "opencode", "label": "OpenCode", "paths": [".config/opencode/opencode.json", ".opencode/plugins/"] }
          ]
        },
        "codexHooks": {
          "type": "boolean",
          "description": "Legacy alias for agentHooks. Kept for existing Context Room configs.",
          "default": true
        },
        "gitHooks": {
          "type": "boolean",
          "description": "Scan effective Git hook directories, including .git/hooks and core.hooksPath.",
          "default": true
        },
        "hookManagers": {
          "type": "boolean",
          "description": "Scan common hook-manager files and folders such as Husky, Lefthook, pre-commit, lint-staged, and package.json hook config.",
          "default": true
        },
        "fileNames": {
          "type": "array",
          "items": { "type": "string", "minLength": 1 },
          "uniqueItems": true,
          "default": ["pre-commit", "pre-push", "commit-msg", "prepare-commit-msg"]
        },
        "agentHookPaths": {
          "type": "array",
          "items": { "$ref": "#/$defs/projectPath" },
          "uniqueItems": true,
          "default": [".codex/hooks.json", ".claude/settings.json", ".claude/settings.local.json", ".config/opencode/opencode.json", ".config/opencode/plugin/", ".config/opencode/plugins/", ".opencode/plugin/", ".opencode/plugins/", "opencode.json", "opencode.jsonc"]
        },
        "codexPaths": {
          "type": "array",
          "items": { "$ref": "#/$defs/projectPath" },
          "uniqueItems": true,
          "description": "Legacy alias paths for older configs. Prefer agentHookPaths.",
          "default": [".codex/hooks.json"]
        },
        "managerPaths": {
          "type": "array",
          "items": { "$ref": "#/$defs/projectPath" },
          "uniqueItems": true,
          "default": [".husky/", "lefthook.yml", ".pre-commit-config.yaml", "lint-staged.config.js", "package.json"]
        }
      }
    },
    "hubCards": {
      "type": "object",
      "description": "Legacy card visibility map. Prefer hubSections for new setups.",
      "additionalProperties": { "type": "boolean" }
    },
    "customHubCards": {
      "type": "array",
      "description": "Legacy flat custom card list. Prefer hubSections for new setups.",
      "items": { "$ref": "#/$defs/card" }
    },
    "hubSections": {
      "type": "array",
      "description": "Top-level groups shown in the Context Room hub.",
      "items": { "$ref": "#/$defs/section" }
    },
    "integrations": {
      "type": "object",
      "description": "Optional integrations. Keep false/empty for generic projects.",
      "additionalProperties": true,
      "properties": {
        "hermes": {
          "type": "boolean",
          "description": "Enable Hermes-specific files and external skill paths. Off by default for generic projects.",
          "default": false
        }
      }
    }
  },
  "required": ["title", "allowedPaths", "watchAllow", "hubSections"],
  "$defs": {
    "projectPath": {
      "type": "string",
      "minLength": 1,
      "not": { "pattern": "(^/|^~/|^\\.\\.|/\\.\\./|\\u0000)" },
      "examples": ["README.md", "AGENTS.md", "docs/", "context/architecture.md", "skills/review.md"]
    },
    "homePath": {
      "type": "string",
      "minLength": 1,
      "pattern": "^~/",
      "not": { "pattern": "(/\\.\\./|\\u0000)" },
      "examples": ["~/.codex/AGENTS.md"]
    },
    "allowedPath": {
      "oneOf": [
        { "$ref": "#/$defs/projectPath" },
        { "$ref": "#/$defs/homePath" }
      ]
    },
    "watchRule": {
      "type": "object",
      "additionalProperties": false,
      "required": ["path", "mode"],
      "properties": {
        "path": {
          "$ref": "#/$defs/allowedPath",
          "description": "Allowed folder governed by this rule, conventionally written with a trailing slash. It can be project-relative or an explicit ~/... path already listed in allowedPaths."
        },
        "mode": {
          "type": "string",
          "enum": ["recursive-live", "recursive-current", "direct-current", "direct-live"],
          "description": "recursive-live watches current and future files at any depth; recursive-current snapshots current files at any depth; direct-current snapshots current immediate file children; direct-live watches current and future immediate file children."
        },
        "files": {
          "type": "array",
          "description": "Frozen eligible file paths for a current-file mode. Paths are normally project-relative; configured ~/ integrations are also supported. Context Room populates this list when the rule is created.",
          "items": { "$ref": "#/$defs/allowedPath" },
          "uniqueItems": true
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "mode": { "enum": ["recursive-current", "direct-current"] }
            },
            "required": ["mode"]
          },
          "then": { "required": ["files"] }
        }
      ]
    },
    "section": {
      "type": "object",
      "additionalProperties": true,
      "required": ["id", "title", "cards"],
      "properties": {
        "id": { "$ref": "#/$defs/id" },
        "title": { "type": "string" },
        "description": { "type": "string" },
        "enabled": { "type": "boolean", "default": true },
        "cards": {
          "type": "array",
          "items": { "$ref": "#/$defs/card" }
        }
      }
    },
    "card": {
      "type": "object",
      "additionalProperties": true,
      "required": ["id", "title"],
      "oneOf": [
        { "required": ["path"] },
        { "required": ["paths"] },
        { "required": ["cards"] }
      ],
      "properties": {
        "id": { "$ref": "#/$defs/id" },
        "title": { "type": "string" },
        "description": { "type": "string" },
        "path": { "$ref": "#/$defs/projectPath" },
        "paths": {
          "type": "array",
          "items": { "$ref": "#/$defs/projectPath" },
          "uniqueItems": true
        },
        "enabled": { "type": "boolean", "default": true },
        "autoChildren": {
          "type": "boolean",
          "description": "When true and the card points to a folder, Context Room infers child cards from the folder's immediate files and subfolders.",
          "default": false
        },
        "cards": {
          "type": "array",
          "description": "Nested cards/sub-cards.",
          "items": { "$ref": "#/$defs/card" }
        }
      }
    },
    "markdownTemplate": {
      "type": "object",
      "additionalProperties": true,
      "required": ["id", "title", "content"],
      "properties": {
        "id": { "$ref": "#/$defs/id" },
        "title": { "type": "string" },
        "description": { "type": "string" },
        "enabled": {
          "type": "boolean",
          "description": "When false, keep this template editable in settings but hide it from the apply-template selector.",
          "default": true
        },
        "content": {
          "type": "string",
          "description": "Template body. Supports {{title}}, {{path}}, and metadata placeholders such as {{scope_yaml}}, {{status_yaml}}, {{canonical_for_yaml}}, {{last_verified_yaml}}, {{sources_inline}}, and {{sources_list}}."
        }
      }
    },
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9_-]*$",
      "examples": ["docs", "agent-context", "skills"]
    }
  }
}
