{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://discern.sh/schema/v1/discern-config.schema.json",
  "x-discern-compatibility-policy": "config-input",
  "title": "discern.toml configuration",
  "type": "object",
  "properties": {
    "project": {
      "description": "The project's identity and the paths discern keeps for it.",
      "default": {},
      "type": "object",
      "properties": {
        "name": {
          "default": "",
          "description": "Display name, free text, used when compiled instructions address the project. Empty falls back to the slug.",
          "type": "string"
        },
        "slug": {
          "default": "",
          "description": "Short, lowercase, dash-separated identity, used in worktree, site, and branch names.",
          "type": "string"
        },
        "gotchas_doc": {
          "default": "",
          "description": "The doc the gate points an agent at when a stage fails in a non-obvious way. Keep it current with your stack's traps; empty disables the pointer.",
          "type": "string"
        },
        "todo": {
          "default": "discern/TODO.md",
          "description": "The deferred-work ledger: the running TODO list agents read and maintain, relative to the project root.",
          "type": "string",
          "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
        },
        "record_logbook": {
          "default": true,
          "description": "When true, record one line of local, metadata-only history per verb run: timings, outcomes, and names, with no code or output. Files stay under .git, outside commits and any network; false stops all writes.",
          "type": "boolean"
        },
        "agents": {
          "description": "Which agent integrations to enable: claude_code, codex, gemini, cursor, copilot. Omit the key for the default pair (claude_code, codex); an explicit empty list emits for no agent.",
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "claude_code",
              "codex",
              "gemini",
              "cursor",
              "copilot"
            ]
          }
        }
      },
      "additionalProperties": false
    },
    "repository": {
      "description": "Policy every checkout of this repository shares.",
      "default": {},
      "type": "object",
      "properties": {
        "trunk": {
          "default": "main",
          "description": "The shared branch the gate compares against and completed work lands on. Detected at setup; DISCERN_TRUNK overrides it per invocation.",
          "type": "string"
        },
        "branch_prefix": {
          "default": "agent/",
          "description": "Branch prefix for worktrees created by discern, e.g. \"agent/my-feature\".",
          "type": "string"
        },
        "proof_notes_mode": {
          "default": "local",
          "description": "Both modes record landed Proof notes locally. \"fetch\" also manages fetch-only transport. Publishing remains an explicit owner action; there is no off mode.",
          "type": "string",
          "enum": [
            "local",
            "fetch"
          ]
        },
        "ensure": {
          "default": [],
          "description": "Idempotent commands that make any checkout usable for its tracked tree, such as installing dependencies from a lockfile. They run in order on every worktree pass and after a landing.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "map": {
      "description": "Where the project map lives.",
      "default": {},
      "type": "object",
      "properties": {
        "dir": {
          "default": "discern/map",
          "description": "Where the project map lives, relative to the project root. `discern setup begin` scaffolds it here and `discern map` browses it.",
          "type": "string",
          "pattern": "^(?!.*\\s\\/?$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*\\/?$"
        }
      },
      "additionalProperties": false
    },
    "instructions": {
      "description": "The instruction sources discern compiles into each agent's file.",
      "default": {},
      "type": "object",
      "properties": {
        "sources": {
          "default": [
            "discern/instructions.md"
          ],
          "description": "Instruction source files or globs, relative to the project root. Missing files are skipped; `discern setup begin` seeds the default source.",
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "(?:^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$)|(?:[*?[\\]{}])"
          }
        }
      },
      "additionalProperties": false
    },
    "skills": {
      "description": "Where your authored skills live, and which skills to leave out.",
      "default": {},
      "type": "object",
      "properties": {
        "dir": {
          "default": "discern/skills",
          "description": "Where your authored skills live, relative to the project root. Read only when present, so a project with no authored skills uses the built-ins.",
          "type": "string",
          "pattern": "^(?!.*\\s\\/?$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*\\/?$"
        },
        "exclude": {
          "default": [],
          "description": "Skill names, bundled or authored, to leave out of materialization. Each materialized skill occupies context in every agent session, so exclude what this project never needs; an unknown name warns and never fails.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "jobs": {
      "description": "The commands the gate runs, in one namespace.",
      "default": {},
      "allOf": [
        {
          "type": "object",
          "propertyNames": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "additionalProperties": {}
        },
        {
          "type": "object",
          "properties": {
            "format": {
              "description": "A formatter or codemod. Mutating, so it runs first and serially.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "build": {
              "description": "Produce the artifacts later stages read: compile, bundle.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "lint": {
              "description": "Read-only static analysis.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "typecheck": {
              "description": "Read-only type checking.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "test": {
              "description": "The test suite.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "smoke": {
              "description": "A fast, side-effect-light readiness check: the app boots with real config in this checkout. `discern done` and `discern test` run it in the same fail-fast test group, so a quick failure cancels slower siblings.",
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                {
                  "type": "object",
                  "properties": {
                    "run": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ],
                      "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
                    },
                    "timeout": {
                      "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                      "type": "number",
                      "minimum": 0
                    },
                    "inputs": {
                      "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                      "minItems": 1,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1
                      }
                    },
                    "needs": {
                      "description": "Producer selectors that must finish successfully before this producer runs.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                      }
                    },
                    "artifacts": {
                      "description": "Project-relative outputs captured into immutable attempt storage after production.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    },
                    "environment": {
                      "description": "Environment variable names whose effective values enter evidence identity as digests.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                      }
                    },
                    "toolchain": {
                      "description": "Project-relative identity files for the applicable toolchain.",
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                      }
                    }
                  },
                  "required": [
                    "run"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "stage": {
                "type": "string",
                "enum": [
                  "fix",
                  "build",
                  "check",
                  "test"
                ],
                "description": "The gate stage this job runs in: fix, build, check, or test."
              },
              "run": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                ],
                "description": "The command(s) to run. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
              },
              "inputs": {
                "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "needs": {
                "description": "Producer selectors that must finish successfully before this producer runs.",
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
                }
              },
              "artifacts": {
                "description": "Project-relative outputs captured into immutable attempt storage after production.",
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                }
              },
              "environment": {
                "description": "Environment variable names whose effective values enter evidence identity as digests.",
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                }
              },
              "toolchain": {
                "description": "Project-relative identity files for the applicable toolchain.",
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
                }
              },
              "provides": {
                "description": "A free-text label for humans and audit.",
                "type": "string"
              },
              "timeout": {
                "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
                "type": "number",
                "minimum": 0
              }
            },
            "required": [
              "stage",
              "run"
            ],
            "additionalProperties": false,
            "description": "A custom job. Its name is open, but its stage and command are explicit."
          }
        }
      ]
    },
    "setup": {
      "description": "Known jobs that do not apply to this project.",
      "default": {},
      "type": "object",
      "properties": {
        "not_applicable": {
          "default": [],
          "description": "Known jobs this project's lifecycle does not have. A job listed here cannot also be configured under [jobs].",
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "format",
              "build",
              "lint",
              "typecheck",
              "test",
              "smoke"
            ]
          },
          "uniqueItems": true
        }
      },
      "additionalProperties": false
    },
    "scopes": {
      "default": {},
      "description": "Named regions of the repository.",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]+$"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The globs that define the scope: a directory prefix (src/**), a standard glob (src/**/*.ext, src/*), a *.ext suffix at any depth, a /seg/ segment, or an exact path. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
          },
          "neutral": {
            "default": false,
            "description": "true: changes here need no gate, as for documentation and agent instructions.",
            "type": "boolean"
          },
          "preview": {
            "description": "A read-only command an agent can run from this worktree to preview a change in this scope. discern reports this action but never executes it. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "inputs": {
            "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "needs": {
            "description": "Producer selectors that must finish successfully before this producer runs.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
            }
          },
          "artifacts": {
            "description": "Project-relative outputs captured into immutable attempt storage after production.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
            }
          },
          "environment": {
            "description": "Environment variable names whose effective values enter evidence identity as digests.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
            }
          },
          "toolchain": {
            "description": "Project-relative identity files for the applicable toolchain.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
            }
          },
          "gate": {
            "description": "A command `discern done` runs when this scope changed: a sub-component's own self-contained gate. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "timeout": {
            "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "paths"
        ],
        "additionalProperties": false
      }
    },
    "generated": {
      "default": {},
      "description": "Committed artifacts that one generator owns.",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]+$"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The scope-paths globs naming the committed artifacts this generator wholly owns: a directory prefix (`reference/**`), a standard glob (`reference/**/*.md`, `reference/*`), a `*.ext` suffix at any depth, a `/seg/` segment, or an exact path. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
          },
          "run": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "The deterministic command(s) that rewrite this group's artifacts: the same tree must produce the same bytes, and the generator must remove orphaned artifacts it no longer emits. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched."
          },
          "linguist_generated": {
            "default": false,
            "description": "true marks the group's paths generated for GitHub through the `linguist-generated` attribute: hidden in diffs by default and excluded from language statistics.",
            "type": "boolean"
          },
          "timeout": {
            "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "paths",
          "run"
        ],
        "additionalProperties": false
      }
    },
    "acceptance": {
      "description": "Standing grants for landing without a conversation.",
      "default": {},
      "type": "object",
      "properties": {
        "pre_authorized": {
          "default": [],
          "description": "Scope names whose changes may land without a per-landing conversation. An owner decision recorded on the trunk: widening a named scope widens its grant. Empty means every landing needs the owner's acceptance.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "worktree": {
      "description": "The isolated-worktree workflow.",
      "default": {},
      "type": "object",
      "properties": {
        "root": {
          "default": "",
          "description": "Where per-worktree checkouts are created. Empty means a sibling of the repository, \"<repo>.worktrees\", outside the checkout. A relative path resolves against the repo root; absolute is used as-is.",
          "type": "string"
        },
        "inherit_env": {
          "default": [],
          "description": "Names copied from the main checkout's declared env files. A value fills an empty entry or the first file's `<file>.example` default. A missing first file is created at mode 0600; existing modes stay unchanged.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "env_files": {
          "default": [
            ".env",
            ".env.local"
          ],
          "description": "Env files read and written in order: the last definition wins; new values use the first existing file. Inheritance alone may create the first file. Managed values share one scoped marker.",
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
          },
          "uniqueItems": true
        },
        "export_port": {
          "default": false,
          "description": "When true, setup writes DISCERN_WORKTREE_PORT to configured env files, hooks warn when a sibling uses the derived port, and status shows it. The port exists either way, and `discern identity --port` always reports it.",
          "type": "boolean"
        },
        "track_ignored_drift": {
          "default": true,
          "description": "Track ignored files at worktree setup and report the top-level ignored paths that changed before the worktree is removed. Turn it off when ignored outputs churn too much to be useful.",
          "type": "boolean"
        },
        "resources": {
          "default": {},
          "description": "External resources provisioned per worktree.",
          "type": "object",
          "propertyNames": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "additionalProperties": {
            "type": "object",
            "properties": {
              "create": {
                "default": "",
                "description": "Command run once at worktree setup. discern records cleanup intent before running it and skips it only after readiness is recorded. An empty command is a clean no-op.",
                "type": "string"
              },
              "destroy": {
                "default": "",
                "description": "Command run once at teardown. Author it idempotent (it may re-run via worktree prune) and cwd-independent.",
                "type": "string"
              },
              "ensure": {
                "default": "",
                "description": "Idempotently reconcile drift or re-readiness at session start.",
                "type": "string"
              },
              "required": {
                "default": true,
                "description": "false makes a create failure non-fatal, so setup continues.",
                "type": "boolean"
              },
              "retries": {
                "default": 0,
                "description": "Retry create/destroy this many times.",
                "type": "integer",
                "minimum": 0,
                "maximum": 5
              },
              "prunable": {
                "default": true,
                "description": "false exempts the resource from orphan pruning, for data-loss-sensitive resources that only teardown may remove.",
                "type": "boolean"
              }
            },
            "additionalProperties": false
          }
        },
        "setup": {
          "description": "Commands that ready a linked worktree.",
          "default": {},
          "type": "object",
          "properties": {
            "steps": {
              "default": [],
              "description": "Commands run once at worktree creation, in order, after the resources exist: one-shot scaffolding such as seeding fixtures.",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "ensure": {
              "default": [],
              "description": "Commands run on every linked-worktree pass: creation, session start, and after `discern update`. For convergence that depends on worktree identity, ports, or resources; the main checkout never runs them.",
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "standards": {
      "default": {},
      "description": "Quality numbers that can never get worse.",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]+$"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "metric": {
            "description": "The metric name the run emits. Defaults to the standard's name.",
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "up",
              "down"
            ],
            "description": "\"up\" when the value should rise, so the limit is a floor; \"down\" when it should fall, so the limit is a ceiling."
          },
          "limit": {
            "type": "number",
            "minimum": -9007199254740991,
            "description": "The floor or ceiling, compared with the trunk's: a floor may only rise and a ceiling may only fall."
          },
          "run": {
            "description": "This standard's producer command. Emits DISCERN_METRIC <metric> <number>; cannot accompany producer.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              }
            ]
          },
          "producer": {
            "description": "Consume an existing job, scope gate, or standard producer instead of running a separate producer.",
            "type": "string",
            "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
          },
          "extract": {
            "description": "Extract readings from captured producer output on stdin; this is a separate operation from run.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              }
            ]
          },
          "artifact": {
            "description": "Declared producer artifact supplied on stdin to extract; requires extract.",
            "type": "string",
            "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
          },
          "inputs": {
            "description": "Complete input closure as scope globs; omission binds evidence to the candidate.",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "needs": {
            "description": "Producer selectors that must finish successfully before this producer runs.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?:jobs\\.[A-Za-z0-9_-]+|scopes\\.[A-Za-z0-9_-]+\\.gate|standards\\.[A-Za-z0-9_-]+)$"
            }
          },
          "artifacts": {
            "description": "Project-relative outputs captured into immutable attempt storage after production.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
            }
          },
          "environment": {
            "description": "Environment variable names whose effective values enter evidence identity as digests.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
            }
          },
          "toolchain": {
            "description": "Project-relative identity files for the applicable toolchain.",
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
            }
          },
          "per": {
            "description": "Divide the metric to hold a rate rather than a raw count, so the number does not rise because the project grew: a second metric the run emits, or a built-in extent discern measures itself, per = { words = \"${map.dir}**\" } (files, lines, words, or bytes over a git pathspec). Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "properties": {
                  "files": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "minItems": 1,
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ]
                  },
                  "lines": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "minItems": 1,
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ]
                  },
                  "words": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "minItems": 1,
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ]
                  },
                  "bytes": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "minItems": 1,
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    ]
                  }
                },
                "additionalProperties": false
              }
            ]
          },
          "scale": {
            "default": 1,
            "description": "Multiply the rate so the limit reads in human units; scale = 1000 reads as per 1,000.",
            "type": "number",
            "exclusiveMinimum": 0
          },
          "margin": {
            "default": 0,
            "description": "Headroom `discern standards --pin` leaves when it tightens the limit to the measured value. Give a metric that drifts on unrelated changes, such as a size or a coverage percentage, a margin so a pinned limit is not tripped by ordinary fluctuation.",
            "type": "number",
            "minimum": 0
          },
          "timeout": {
            "description": "Time budget in seconds for this job alone, replacing [gate].timeout; 0 removes the bound. Omit to inherit the global budget.",
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "direction",
          "limit"
        ],
        "additionalProperties": false
      }
    },
    "checkpoints": {
      "default": {},
      "description": "Change-triggered review rules.",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]+$"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "scope": {
            "description": "Selector: a configured [scopes.<name>] whose paths choose the matched set. Prefer this over repeating the scope's globs in `paths`; a checkpoint takes one selector.",
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "paths": {
            "description": "Selector globs in the scope dialect: prefix, standard glob, suffix, segment, or exact path. Use either `scope` or `paths`. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "include_generated": {
            "description": "true includes paths a [generated.<name>] group owns; the default evaluates authored change only.",
            "type": "boolean"
          },
          "exclude_paths": {
            "description": "Globs removed after selection and before every predicate, subject, evidence, and `when`. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unless_changed": {
            "description": "Hold fire when any changed path matches one of these globs or scope names: flag this change class unless its counterpart moved too. Registered path references (${map.dir}, ${skills.dir}, ${scripts.dir}, ${project.todo}, ${project.gotchas_doc}) resolve from this config before matching or execution; unregistered braced forms stay untouched.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "kinds": {
            "description": "Narrow changed evidence to the named Git kinds: \"added\", \"modified\", or \"deleted\".",
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "added",
                "modified",
                "deleted"
              ]
            }
          },
          "adds_matching": {
            "description": "Narrow text evidence to files with an added line containing any configured case-sensitive literal UTF-8 byte substring. Accepts up to 16 distinct patterns of 1–128 UTF-8 bytes; NUL, CR, and LF are invalid.",
            "minItems": 1,
            "maxItems": 16,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "removes_matching": {
            "description": "Narrow text evidence to files with a removed line containing any configured case-sensitive literal UTF-8 byte substring. Accepts up to 16 distinct patterns of 1–128 UTF-8 bytes; NUL, CR, and LF are invalid.",
            "minItems": 1,
            "maxItems": 16,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "new_directory": {
            "description": "Narrow to added files whose parent directory held no admitted file at the merge-base; root-level additions never qualify.",
            "type": "boolean"
          },
          "binary": {
            "description": "Narrow to binary changes when true or text changes when false.",
            "type": "boolean"
          },
          "min_changed_files": {
            "description": "Fire only when at least this many matched files changed. Omit for no threshold (any matched change fires).",
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "min_changed_lines": {
            "description": "Require this many added-plus-removed text lines across the final narrowed evidence; binary files contribute zero.",
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "deletion_dominant": {
            "description": "Fire only when the matched change is deletion-dominant: line removals clearly outweigh additions and exceed a fixed floor, so a large cut is reviewed and an ordinary edit or balanced refactor is not.",
            "type": "boolean"
          },
          "similar_new_file": {
            "description": "Fire only when the change adds a file whose name closely resembles an existing sibling in the same directory, the signature of a parallel implementation growing beside the original.",
            "type": "boolean"
          },
          "min_commits": {
            "description": "Require this many commits in merge-base..HEAD, including merge commits; uncommitted work adds no commit.",
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "when": {
            "description": "Final executable condition: exit 0 fires, exit 10 passes; every other outcome is indeterminate. `DISCERN_MATCH <path>` narrows the structural matches.",
            "type": "string"
          },
          "mode": {
            "description": "\"stop\" (the default): the gate refuses to run until the agent declares the question met or unmet. \"advise\": the question and its evidence are delivered through the advisory channel and nothing blocks.",
            "type": "string",
            "enum": [
              "stop",
              "advise"
            ]
          },
          "question": {
            "description": "Inline judgment prose. A project checkpoint needs this or `question_file`; a built-in inherits unless overridden. Review surfaces serve it. Do not include secrets.",
            "type": "string"
          },
          "question_file": {
            "description": "Repository-relative Markdown path from the governing merge-base Git tree. Mutually exclusive with `question`; built-ins may inherit. Must be a regular Git blob, valid UTF-8, and at most 65536 bytes. Text can appear in terminal, MCP, CI, Proof, and landing review; repository access is its only privacy. Do not include secrets.",
            "type": "string",
            "pattern": "^(?!.*\\s$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*$"
          },
          "teach": {
            "description": "Optional lesson prose carried into renderings: why the question matters and what good looks like.",
            "type": "string"
          },
          "reference": {
            "description": "Optional displayed pointer. discern performs no content loading or execution. Review surfaces may show it. Do not include secrets.",
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    },
    "gate": {
      "description": "How `discern done` runs its parallel stages.",
      "default": {},
      "type": "object",
      "properties": {
        "stream_output": {
          "default": false,
          "description": "false groups each job's complete output in a static transcript; true streams prefixed lines. Live terminals always show the gate frame's bounded tail; CI, pipes, and --plain are static.",
          "type": "boolean"
        },
        "fail_fast": {
          "default": true,
          "description": "Cancel the in-flight sibling commands the moment one fails; an agent-driven gate wants a fast abort. false runs every job and shows all failures in one pass.",
          "type": "boolean"
        },
        "timeout": {
          "default": 600,
          "description": "Time budget in seconds for every command the gate runs. A command that overruns is tree-killed and the stage fails with a timeout diagnostic, so a watch-mode runner cannot hang the gate. 0 removes the bound.",
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        },
        "concurrent_test_runs": {
          "default": 1,
          "description": "How many test stages may run on this machine at once; the rest wait for a slot. Fresh projects use 1; 0 is uncapped. `discern queue -- <command>` shares the cap.",
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        }
      },
      "additionalProperties": false
    },
    "coupling": {
      "description": "Co-change detection from git history.",
      "x-discern-stability": "evolving",
      "default": {},
      "type": "object",
      "properties": {
        "report_in_gate": {
          "default": true,
          "description": "Surface coupling findings as trailing hints in `discern done` and `discern prepare`, while the change is hot. false keeps coupling available through `discern coupling` alone.",
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "scripts": {
      "description": "Where your executable project scripts live.",
      "default": {},
      "type": "object",
      "properties": {
        "dir": {
          "default": "discern/scripts",
          "description": "Where your project scripts live, relative to the project root. The default works with no config; point it elsewhere, such as \"tools/\", if you prefer.",
          "type": "string",
          "pattern": "^(?!.*\\s\\/?$)(?:\\.\\/)*(?![~\\s])(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ](?:\\/(?!(?:\\.{1,2}|\\.[gG][iI][tT])(?:\\/|$))(?!(?:(?:[cC][oO][nN]|[pP][rR][nN]|[aA][uU][xX]|[nN][uU][lL]|[cC][oO][mM][1-9]|[lL][pP][tT][1-9]))(?:\\.|\\/|$))[^<>:\"\\\\|?*\\u0000-\\u001F/]*[^<>:\"\\\\|?*\\u0000-\\u001F/. ])*\\/?$"
        }
      },
      "additionalProperties": false
    },
    "meta": {
      "description": "Project setup and adoption evidence.",
      "default": {},
      "type": "object",
      "properties": {
        "managed_version": {
          "description": "Highest discern release whose successful setup or upgrade adopted managed material. Project evidence, independent of installed binaries, schema, and content currency.",
          "readOnly": true,
          "type": "string"
        },
        "schema_version": {
          "description": "The install schema version. `discern upgrade` bumps it; never edit it by hand.",
          "readOnly": true,
          "type": "integer",
          "minimum": 1,
          "maximum": 9007199254740991
        },
        "bootstrapped": {
          "default": false,
          "description": "true once `discern setup` has completed, which retires the one-time setup redirect.",
          "readOnly": true,
          "type": "boolean"
        },
        "setup_completion": {
          "description": "Evidence recorded for the setup completion event: proven by the gate, or explicitly completed unproven.",
          "readOnly": true,
          "type": "string",
          "enum": [
            "proven",
            "unproven"
          ]
        },
        "setup_model": {
          "default": "",
          "description": "The model the agent declared at `discern setup begin --model`. Recorded for support triage; advisory, since discern cannot verify it.",
          "readOnly": true,
          "type": "string"
        },
        "setup_version": {
          "default": "",
          "description": "The discern version that ran setup, recorded for support triage.",
          "readOnly": true,
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": [
        "schema_version"
      ]
    }
  },
  "additionalProperties": false,
  "required": [
    "meta"
  ]
}
