{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://wildorder.dev/schemas/pipeline-config.schema.json",
  "title": "Program Pipeline configuration",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schemaVersion",
    "pipelineVersion",
    "visionPath",
    "requireApprovalBeforeBuild"
  ],
  "properties": {
    "schemaVersion": {
      "const": 1
    },
    "pipelineVersion": {
      "type": "string",
      "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?$"
    },
    "visionPath": {
      "type": "string",
      "minLength": 1
    },
    "requireApprovalBeforeBuild": {
      "type": "boolean"
    },
    "agent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["command"],
      "properties": {
        "command": { "type": "string", "minLength": 1 },
        "args": {
          "type": "array",
          "items": { "type": "string" }
        },
        "promptMode": { "enum": ["stdin", "argument"] }
      }
    },
    "recoveryAgent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["command"],
      "description": "Handles build recovery attempts. When absent, recovery reuses the normal build agent; configure a different provider or model to escape primary-agent capacity failures.",
      "properties": {
        "command": { "type": "string", "minLength": 1 },
        "args": {
          "type": "array",
          "items": { "type": "string" }
        },
        "promptMode": { "enum": ["stdin", "argument"] }
      }
    },
    "authorAgent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["command"],
      "description": "Reasons about specs in the convergence loop. Separate from `agent`, because implementing a spec and judging one want different models; without it the loop borrows the build agent, which is often deliberately cheap.",
      "properties": {
        "command": { "type": "string", "minLength": 1 },
        "args": {
          "type": "array",
          "items": { "type": "string" }
        },
        "promptMode": { "enum": ["stdin", "argument"] }
      }
    },
    "replannerAgent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["command"],
      "properties": {
        "command": { "type": "string", "minLength": 1 },
        "args": { "type": "array", "items": { "type": "string" } },
        "promptMode": { "enum": ["stdin", "argument"] }
      }
    },
    "validatorAgent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["command"],
      "description": "The independent second opinion: critic in the spec convergence loop, and reviewer for build-time test critique.",
      "properties": {
        "command": { "type": "string", "minLength": 1 },
        "args": {
          "type": "array",
          "items": { "type": "string" }
        },
        "promptMode": { "enum": ["stdin", "argument"] }
      }
    },
    "models": {
      "type": "object",
      "additionalProperties": { "type": "string", "minLength": 1 }
    },
    "verify": {
      "type": "object",
      "additionalProperties": { "type": "string", "minLength": 1 }
    },
    "contextDocs": {
      "type": "array",
      "items": { "type": "string", "minLength": 1 }
    },
    "build": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "maxRecoveryAttempts": { "type": "integer", "minimum": 0, "default": 1 },
        "verifyRetries": { "type": "integer", "minimum": 0, "default": 0 },
        "logDir": { "type": "string", "minLength": 1 },
        "commit": { "type": "boolean" },
        "critiqueTests": {
          "type": "boolean",
          "description": "Have the validator agent critique the workstream diff's tests before the runner commits. A passing suite proves little when the same agent wrote both the implementation and its tests."
        },
        "requireCriteriaApproval": {
          "type": "boolean",
          "description": "Refuse to build until this program's acceptance criteria have been approved."
        },
        "executionProfile": {
          "type": "object",
          "additionalProperties": false,
          "description": "Provider-neutral working-set limits used to judge whether one agent invocation can safely carry a workstream.",
          "properties": {
            "contextWindowTokens": { "type": "integer", "minimum": 1, "default": 250000 },
            "targetWorkingSetTokens": { "type": "integer", "minimum": 1, "default": 100000 },
            "cautionWorkingSetTokens": { "type": "integer", "minimum": 1, "default": 140000 },
            "hardWorkingSetTokens": { "type": "integer", "minimum": 1, "default": 190000 },
            "toleranceTokens": { "type": "integer", "minimum": 0, "default": 10000 },
            "bytesPerToken": { "type": "number", "exclusiveMinimum": 0, "default": 4 },
            "byteEstimateUncertainty": { "type": "number", "minimum": 0, "exclusiveMaximum": 1, "default": 0.25 },
            "missingNewFileTokens": { "type": "integer", "minimum": 0, "default": 4000 }
          }
        }
      }
    },
    "validate": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "rounds": {
          "type": "integer",
          "minimum": 1,
          "maximum": 3,
          "description": "Rounds of the author/critic convergence loop; 1 reproduces the pre-loop single-critique behavior."
        },
        "strict": {
          "type": "boolean",
          "description": "Fail the gate on major findings, not just blockers. Independent of loop termination, which always tracks blockers and majors."
        },
        "scopeDownAfterRound": {
          "type": "integer",
          "minimum": 2,
          "description": "Rounds through this number always cover the whole program. Scoping earlier would use the declared dependency graph to pick which workstreams to re-check, but finding undeclared dependencies is part of the job."
        }
      }
    }
  }
}
