{
  "openapi": "3.1.0",
  "info": {
    "title": "PRAE Command Center API",
    "version": "0.9.2",
    "summary": "The local, self-hosted HTTP API of the PRAE Command Center (`pnpm console`) and of `prae console --serve` (prae-cli).",
    "description": "This document describes the HTTP API that PRAE's self-hosted Command Center serves on the operator's own machine. There is **no hosted public API**: nothing at prae-ai.com answers these routes. The API exists only while an operator runs it locally, and it is bound to loopback (127.0.0.1).\n\nTwo servers answer it:\n\n- **prae-cli: `prae console <ledger.jsonl> --out <dir> --serve [port]`** (the `prae-cli` npm package; port 4180 by default) serves the record API in packages/cli/src/serve.ts: the `record`, `verify`, `compliance` (read) and `redteam` (results on disk) routes. It is read-only by construction: GET and HEAD only.\n- **The Command Center server** (the repository's `pnpm console`, apps/console/server; port `PORT` or 5174) serves those same routes identically and adds the `operator`, `fleet`, red-team run, `trust` and `posture` APIs and the one compliance write (saving the scope). These routes are for the repository and design partners today; they are not yet in prae-cli.\n\nEvery mutation is same-origin only: the server refuses a request whose `Origin` header is not `http://<Host>` or whose `Content-Type` is not exactly `application/json` (403, `{ \"error\": \"Same-origin JSON request required\" }`), refuses a non-loopback `Host` (403), caps body sizes (413) and refuses unknown fields. Operator answers to held calls and fleet steering requests are signed with the operator key, which is sealed at rest in the record and unlocked only in the server's memory for the session of the human who typed its passphrase; the session token travels in the `X-PRAE-Operator-Session` header. None of this is an identity or tenancy claim: the API knows the operator is the person at the local console, nothing more.\n\nEverything the API returns is read from the record's files at request time (`Cache-Control: no-store`). Fields typed here are the TypeScript shapes the console reads; objects marked `additionalProperties: true` are files written by other processes (the red-team runner, the fleet runner, readiness and provenance records) and are passed through verbatim rather than typed here.\n\n## Versioning and deprecation\n\nThe API's version is prae-cli's own semver, and every `/api/*` response names it in the `X-PRAE-API-Version` response header (see `components.headers`). The contract follows that version: a breaking change to a route's shape or meaning bumps the major; additive changes bump the minor. A route on its way out carries `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) response headers for at least one minor release before it is removed, and the OpenAPI document marks it `deprecated: true` in the same release. There is no URL-path version: the servers are loopback-only and pinned to one package version by whoever installs them.\n\n## Rate limits\n\nNone. The servers bind to 127.0.0.1 for one operator; no `RateLimit-*` or `Retry-After` headers are sent because no limit exists. A 409 on a run or attack start means one is already active; wait for it rather than retry.",
    "contact": {
      "email": "thetalosteam@gmail.com",
      "url": "https://prae-ai.com/contact/"
    },
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "externalDocs": {
    "description": "PRAE, in plain text",
    "url": "https://prae-ai.com/llms.txt"
  },
  "servers": [
    {
      "url": "http://localhost:5174",
      "description": "The Command Center server on the operator's machine (repository: `pnpm console`; port `PORT`, 5174 by default), bound to 127.0.0.1. Serves every route in this document. There is no hosted public API."
    },
    {
      "url": "http://localhost:4180",
      "description": "prae-cli on the operator's machine: `prae console <ledger.jsonl> --out <dir> --serve [port]` (port 4180 by default), bound to 127.0.0.1. Serves the record API only (tags record, verify, compliance read, redteam results): read-only, GET and HEAD."
    }
  ],
  "tags": [
    {
      "name": "record",
      "description": "The record's files as JSON: ledger, discovery, report, guardians, pack, status, and a live event stream."
    },
    {
      "name": "verify",
      "description": "Chain and signature verification of the ledger, as `prae verify` does it."
    },
    {
      "name": "operator",
      "description": "Held calls and the operator's signed answers; the operator key's lifecycle."
    },
    {
      "name": "fleet",
      "description": "The simulated fleet the console can start, and the operator's signed interventions on it."
    },
    {
      "name": "redteam",
      "description": "Red-team results on disk, and the fixed set of red-team runs the console can start."
    },
    {
      "name": "trust",
      "description": "The trust center: readiness, build, provenance, sandbox attacks, receipts and the evidence package."
    },
    {
      "name": "posture",
      "description": "The agent's security posture derived from the record, and the findings the operator tracks."
    },
    {
      "name": "compliance",
      "description": "Evidence toward controls, scoped by the record's compliance scope. Evidence, never a compliance claim."
    }
  ],
  "paths": {
    "/api/record": {
      "get": {
        "tags": ["record"],
        "operationId": "getRecord",
        "summary": "The whole record",
        "description": "Every file of the record as one snapshot. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordSnapshot"
                }
              }
            }
          }
        }
      }
    },
    "/api/ledger": {
      "get": {
        "tags": ["record"],
        "operationId": "getLedger",
        "summary": "The ledger rows",
        "description": "Every row of the hash-chained ledger, oldest first. A half-written last line is skipped. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LedgerRow"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery": {
      "get": {
        "tags": ["record"],
        "operationId": "getDiscovery",
        "summary": "The discovery record",
        "description": "What the run discovered about the agent's workspace, or null when none was written. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Discovery"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/report": {
      "get": {
        "tags": ["record"],
        "operationId": "getReport",
        "summary": "The security report",
        "description": "The test suite's report for the record, or null. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Report"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/guardians": {
      "get": {
        "tags": ["record"],
        "operationId": "getGuardians",
        "summary": "The Guardian catalogue",
        "description": "The Guardians attached to the record, or null. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Catalogue"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/pack": {
      "get": {
        "tags": ["record"],
        "operationId": "getPack",
        "summary": "The built-in pack",
        "description": "The record's built-in policy pack, or null. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Pack"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/packs": {
      "get": {
        "tags": ["record"],
        "operationId": "getPacks",
        "summary": "The packs in force",
        "description": "The built-in pack and the workspace's own packs as the gate's loader reads them, each with origin, version, sha256 and rules, plus every workspace pack the loader refused and why. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PacksInForce"
                }
              }
            }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": ["record"],
        "operationId": "getStatus",
        "summary": "The record's files on disk",
        "description": "The record directory and, per file, its size and mtime or null when absent. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordStatus"
                }
              }
            }
          }
        }
      }
    },
    "/api/events": {
      "get": {
        "tags": ["record"],
        "operationId": "streamEvents",
        "summary": "Ledger rows as they are appended (SSE)",
        "description": "A `text/event-stream`. Each `data:` message is a JSON array of the ledger rows appended since the last message (a burst is coalesced into one message, at most four a second). A comment line is sent every two seconds as a keepalive. When the ledger file shrinks (it was replaced), an `event: reset` with `data: {}` is sent and the client should take a fresh snapshot. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "An open server-sent-events stream.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "SSE frames. `data:` frames carry a JSON array of LedgerRow; `event: reset` frames carry `{}`."
                }
              }
            }
          }
        }
      }
    },
    "/api/verify": {
      "get": {
        "tags": ["verify"],
        "operationId": "verifyLedger",
        "summary": "Verify the ledger",
        "description": "Verify the chain, then the signatures against the public key beside the ledger, the way `prae verify` does. Without `tamper` only the rows appended since the last check are verified. With `tamper`, one row's refusal is changed to an allow in memory first and the altered text is what is verified (the forged-copy demonstration); with `repair=1` as well, every hash is recomputed over the altered rows, so the chain agrees again and the signatures are what fails. Nothing on disk changes. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [
          {
            "name": "tamper",
            "in": "query",
            "required": false,
            "description": "The `seq` of the row to alter in memory before verifying. A non-integer is ignored.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "repair",
            "in": "query",
            "required": false,
            "description": "With `tamper`: `1` recomputes every hash over the altered rows. Any other value is ignored.",
            "schema": {
              "type": "string",
              "enum": ["1"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The verification. When there is no ledger: `ok: false`, `entries: 0`, one problem `no ledger`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResult"
                }
              }
            }
          }
        }
      }
    },
    "/api/compliance": {
      "get": {
        "tags": ["compliance"],
        "operationId": "getCompliance",
        "summary": "Evidence toward controls",
        "description": "The scoped assessment and, per built-in control, the evidence the pack and the ledger hold toward it. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Compliance"
                }
              }
            }
          }
        }
      }
    },
    "/api/compliance/scope": {
      "post": {
        "tags": ["compliance"],
        "operationId": "saveComplianceScope",
        "summary": "Save the compliance scope",
        "description": "The one write the Compliance view takes. Frameworks and controls the catalog does not know are dropped before saving. It changes what is assessed, never the ledger. Body limit 256 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ComplianceScope"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The scope was saved; the assessment under it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Compliance"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, or a scope that does not parse; the message says what was wrong.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback. Also returned as `Loopback host required` when the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed: only POST.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/redteam": {
      "get": {
        "tags": ["redteam"],
        "operationId": "getRedteamResults",
        "summary": "Red-team results on disk",
        "description": "The campaign, its runs, steering runs that carry an objective, and the kept crown-jewel history, as the runner wrote them. Record API (packages/cli/src/serve.ts): served by prae-cli (`prae console <ledger.jsonl> --out <dir> --serve [port]`) and identically by the repository's Command Center server (`pnpm console`).",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Read from disk at request time; `Cache-Control: no-store`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Redteam"
                }
              }
            }
          }
        }
      }
    },
    "/api/redteam/run": {
      "get": {
        "tags": ["redteam"],
        "operationId": "getRedteamRun",
        "summary": "The runs the console can start, and the run in progress",
        "description": "The fixed set of tests (each a scenario the runner knows: the crown-jewel red team and three steering runs, all simulated Claude Code sessions through the PRAE gate), the active run if any, and the last one. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The control state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RedteamControl"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["redteam"],
        "operationId": "startRedteamRun",
        "summary": "Start a red-team run",
        "description": "Start one of the fixed tests. The console spawns the runner; every step the Red team tab shows comes from the ledger rows that run seals, never from this process. One run at a time. Nothing the request sends reaches the command line. Body limit 1 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "test": {
                    "type": "string",
                    "enum": [
                      "crown-jewel",
                      "steer-follow",
                      "steer-ignore",
                      "operator-steer"
                    ]
                  }
                },
                "required": ["test"]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The run was started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "active": {
                      "$ref": "#/components/schemas/RedteamRunState"
                    }
                  },
                  "required": ["id", "active"]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, or unknown test.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A red-team run is already in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "active": {
                      "$ref": "#/components/schemas/RedteamRunState"
                    }
                  },
                  "required": ["error", "active"]
                }
              }
            }
          }
        }
      }
    },
    "/api/operator": {
      "get": {
        "tags": ["operator"],
        "operationId": "getOperator",
        "summary": "Held calls and the signing state",
        "description": "The calls paused at a gate now, waiting for the operator, with each one's lifecycle. What is shown as fact (the action, its hash, the session, the row) is rendered from the canonical call the gate wrote and from the ASK row in a verifying ledger, never from the question's own text, which the agent can write. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The queue and the signing state for this session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperatorState"
                }
              }
            }
          },
          "403": {
            "description": "Loopback host required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["operator"],
        "operationId": "operatorAction",
        "summary": "Create, unlock or lock the operator key; answer or dismiss a held call",
        "description": "One operation per request, chosen by the body's shape. An answer (ALLOW, DENY or STEER) is signed with the unlocked operator key over the question id, the exact action's hash and the decision, and relayed into the record where the waiting gate picks it up; the console never drives the agent. The answer is refused (409) when the `actionHash` sent is not the one the server computed from the call now. A dismissal is not an answer: it takes an abandoned question off the queue, and is refused while anything still waits on it. Body limit 8 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OperatorRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`create`, `unlock` and `lock` answer the signing state (with a session token for create/unlock); an answer or dismissal answers `{ \"ok\": true }`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OperatorSession"
                    },
                    {
                      "$ref": "#/components/schemas/Ok"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, a passphrase shorter than 12 characters, a key that could not be made, a missing id, or an invalid answer (decision, instruction).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Wrong passphrase, or no operator key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback. Also returned as `Loopback host required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The record already has an operator key, an earlier key is pinned for it, the held action is not the one shown, there is no such question, or the agent is still waiting on it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator session is required, or the operator key is locked for this session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet": {
      "get": {
        "tags": ["fleet"],
        "operationId": "getFleet",
        "summary": "The fleet, the runner process and the constraints on offer",
        "description": "The runner's fleet file as it is now (with `stopped` set when its runner process is gone), the runner process this console started, the steering constraints an operator may apply, and the signing state for this session. Every count the Fleet screen shows is read from the ledger, not from here. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The fleet control state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetControl"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/start": {
      "post": {
        "tags": ["fleet"],
        "operationId": "startFleet",
        "summary": "Start a fleet",
        "description": "Start the simulated fleet runner with the given number of agents (1 to 1000, default 16). One fleet at a time. The runner's own state appears in `GET /api/fleet` once it has written it. Body limit 16 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "agents": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1000,
                    "default": 16
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The runner is being started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "run": {
                      "$ref": "#/components/schemas/FleetRun"
                    }
                  },
                  "required": ["run"]
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, or `agents` out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A fleet is already running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/stop": {
      "post": {
        "tags": ["fleet"],
        "operationId": "stopFleet",
        "summary": "Stop the running fleet",
        "description": "Signal the runner to halt every session and seal the end. The next start begins a fresh fleet. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "description": "An empty JSON object."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The runner was signalled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "stopping": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": ["stopping"]
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/steer": {
      "post": {
        "tags": ["fleet"],
        "operationId": "steerFleet",
        "summary": "Steer a cohort",
        "description": "Apply one of the offered constraints to the targeted agents: a one-rule policy pack, signed with the operator key, that each targeted gate verifies before adopting.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "targets": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1
                  },
                  "constraint": {
                    "type": "string",
                    "description": "A constraint id from `GET /api/fleet` `constraints`."
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 280
                  },
                  "cohort": {
                    "type": "string",
                    "maxLength": 280
                  }
                },
                "required": ["targets", "constraint"]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/unsteer": {
      "post": {
        "tags": ["fleet"],
        "operationId": "unsteerFleet",
        "summary": "Remove a steer",
        "description": "Ask the gates that adopted an earlier steering intervention to remove it.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "of": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "The id of a `steer` intervention of this fleet."
                  }
                },
                "required": ["of"]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/contain": {
      "post": {
        "tags": ["fleet"],
        "operationId": "containFleet",
        "summary": "Contain agents",
        "description": "End the targeted agents' sessions.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FleetTargets"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/pause": {
      "post": {
        "tags": ["fleet"],
        "operationId": "pauseFleet",
        "summary": "Pause agents",
        "description": "Hold the targeted agents at their next call until resumed; a call already at its gate completes.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FleetTargets"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/resume": {
      "post": {
        "tags": ["fleet"],
        "operationId": "resumeFleet",
        "summary": "Resume agents",
        "description": "Let paused agents go on.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FleetTargets"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/fleet/redteam": {
      "post": {
        "tags": ["fleet"],
        "operationId": "redteamFleet",
        "summary": "Trigger the scenario's red-team event",
        "description": "Put the scenario's untrusted instruction in front of a cohort. The runner decides who it reaches; the request names nobody.\n\nThe request is signed with the operator key unlocked for this session and placed for the fleet runner, which verifies it, seals the intervention in the ledger and delivers it to the targeted gates. The response says only that the request was accepted; what the agents did is read back from the ledger. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "X-PRAE-Operator-Session",
            "in": "header",
            "required": false,
            "description": "The operator session token issued by `POST /api/operator` (`create` or `unlock`). Required for any request that signs with, locks, or dismisses under the operator key.",
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "description": "An empty JSON object."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The signed request was placed for the runner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FleetAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, targets that are not agents of this fleet, an unknown constraint, or no such steering intervention.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No fleet is running, or this fleet's runner is no longer running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "423": {
            "description": "The operator key is locked for this session: unlock it with its passphrase to steer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The fleet request failed; the message says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trust": {
      "get": {
        "tags": ["trust"],
        "operationId": "getTrust",
        "summary": "The trust center snapshot",
        "description": "The last readiness run as `pnpm security:readiness` wrote it (or the file `PRAE_READINESS` names), the build this console runs (version, commit, dirty), the connector's provenance record and SBOM when a local copy is configured (`PRAE_PROVENANCE`), and the sandbox's attacks. Read from files at request time. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrustSnapshot"
                }
              }
            }
          }
        }
      }
    },
    "/api/trust/attack": {
      "get": {
        "tags": ["trust"],
        "operationId": "getTrustAttack",
        "summary": "The sandbox attack in progress, and the last one",
        "description": "Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The active and last attack runs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttackControl"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["trust"],
        "operationId": "startTrustAttack",
        "summary": "Run one sandbox attack",
        "description": "Start one attack from the fixed set in `GET /api/trust` `attacks`: the runner puts one tool call to the PRAE gate as it ships, with this record's pack, and seals the decision into this record's ledger. Nothing the call names is carried out. The run reports `recorded` only after the console has read the sealed rows back from the ledger itself. One at a time. Nothing the request sends reaches the command line. Body limit 1 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "attack": {
                    "type": "string",
                    "description": "An attack id from `GET /api/trust`."
                  }
                },
                "required": ["attack"]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The attack was started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "active": {
                      "$ref": "#/components/schemas/AttackRun"
                    }
                  },
                  "required": ["active"]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, or unknown attack.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "An attack is already running.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "active": {
                      "$ref": "#/components/schemas/AttackRun"
                    }
                  },
                  "required": ["error", "active"]
                }
              }
            }
          }
        }
      }
    },
    "/api/trust/receipt": {
      "get": {
        "tags": ["trust"],
        "operationId": "getTrustReceipt",
        "summary": "One row as a prae/1 receipt",
        "description": "The row, its signature and the record's public key, verified here with the ledger's own code. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "seq",
            "in": "query",
            "required": true,
            "description": "The row's `seq`.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt and its verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiptResponse"
                }
              }
            }
          },
          "404": {
            "description": "No such row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trust/export": {
      "get": {
        "tags": ["trust"],
        "operationId": "exportTrustEvidence",
        "summary": "The security evidence package",
        "description": "One deterministic JSON document built from the readiness record, the provenance record, the ledger's verification and the build, and from nothing else. Sent as an attachment (`Content-Disposition: attachment; filename=\"prae-evidence-<id>.json\"`). Its id is the sha256 of its own text without the id: it identifies the content, it is not a signature. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The package, as an attachment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvidencePackage"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trust/file/{name}": {
      "get": {
        "tags": ["trust"],
        "operationId": "getTrustFile",
        "summary": "The local provenance record or SBOM",
        "description": "Only the two files beside the configured provenance record (`PRAE_PROVENANCE`), sent as attachments; nothing else is served from this route. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "The file.",
            "schema": {
              "type": "string",
              "enum": ["provenance.json", "connector.cdx.json"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file, as an attachment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "The file's own JSON (SLSA provenance or CycloneDX SBOM), verbatim."
                }
              }
            }
          },
          "404": {
            "description": "Not configured, not present, or not one of the two names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/posture": {
      "get": {
        "tags": ["posture"],
        "operationId": "getPosture",
        "summary": "The agent's posture and tracked findings",
        "description": "The posture derived from the record now (discovery records reachability, policy records constraints; neither proves use), the operator's state for that agent (findings, snapshots, audit trail, recommendations) and whether a workspace is configured for rechecks. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The posture.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureResponse"
                }
              }
            }
          },
          "403": {
            "description": "Loopback host required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Posture evidence could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["posture"],
        "operationId": "postureAction",
        "summary": "Capture a snapshot, update a finding, recheck credentials, or act on a recommendation",
        "description": "One action per request. Every action but `capture` must cite the current `revision` from the last GET; a stale revision is refused (409). Body limit 8 KiB. Served only by the Command Center server (repository / design partners: `pnpm console`, apps/console/server), not yet in prae-cli. `prae console --serve` is read-only by construction and does not mount this route.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostureRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The posture after the action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostureResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or unavailable evidence. Owner and reason are required for finding changes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Refused: the request is not a same-origin JSON request (the `Origin` header must equal `http://<Host>` and `Content-Type` must be exactly `application/json`), or the Host is not loopback. Also returned as `Loopback host required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "State changed; refresh and retry. Or: no agent workspace configured for rechecks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": ["error"],
        "description": "Every refusal and failure is a JSON object with one `error` sentence. (The Command Center host answers a wrong `Host` header with an empty 403 before any route runs.)"
      },
      "Verdict": {
        "type": "string",
        "enum": ["allow", "deny", "ask", "correct"]
      },
      "TraceStep": {
        "type": "object",
        "properties": {
          "rule": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "effect": {
            "type": "string"
          },
          "because": {
            "type": "string"
          }
        },
        "required": ["rule", "effect", "because"]
      },
      "LedgerRow": {
        "type": "object",
        "properties": {
          "seq": {
            "type": "integer"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "session": {
            "type": "string"
          },
          "tool": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "capability": {
            "type": "string"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "rule": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "trace": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceStep"
            }
          },
          "pack": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              },
              "sha256": {
                "type": "string",
                "description": "sha256 of the pack's exact bytes."
              },
              "origin": {
                "type": "string",
                "enum": ["workspace", "builtin"]
              }
            },
            "required": ["name", "version"]
          },
          "micros": {
            "type": "integer"
          },
          "secrets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rule": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "line": {
                  "type": "integer"
                },
                "confidence": {
                  "type": "number"
                }
              },
              "required": ["rule", "type", "line", "confidence"]
            }
          },
          "phase": {
            "type": "string",
            "enum": ["output"]
          },
          "shadow": {
            "type": "boolean",
            "description": "Shadow mode: the verdict was sealed and the call proceeded anyway."
          },
          "command": {
            "type": "object",
            "properties": {
              "program": {
                "type": "string"
              },
              "hash": {
                "type": "string"
              }
            },
            "required": ["program", "hash"]
          },
          "screening": {
            "type": "object",
            "additionalProperties": true,
            "description": "Content screening of a tool result: engine, answers, latency, outcome. Never the content itself."
          },
          "steer": {
            "type": "object",
            "properties": {
              "reason": {
                "type": "string"
              },
              "constraint": {
                "type": "string"
              },
              "suggested_next_step": {
                "type": "string"
              }
            },
            "required": ["reason", "constraint", "suggested_next_step"]
          },
          "afterSteer": {
            "type": "integer"
          },
          "steerOf": {
            "type": "integer"
          },
          "nextAction": {
            "type": "object",
            "additionalProperties": true
          },
          "actor": {
            "type": "string",
            "description": "Who answered, when a human did: an assertion, never an identity."
          },
          "operator": {
            "type": "object",
            "properties": {
              "decision": {
                "type": "string",
                "enum": ["allow", "deny", "steer", "dismiss"]
              },
              "instruction": {
                "type": "string"
              },
              "paused": {
                "type": "integer"
              },
              "question": {
                "type": "string"
              },
              "untaken": {
                "type": "string",
                "enum": ["allow", "deny", "steer"]
              }
            },
            "required": ["decision"]
          },
          "hash": {
            "type": "string"
          },
          "prev": {
            "type": "string"
          },
          "sig": {
            "type": "string",
            "description": "Ed25519 signature over `hash`, base64, when the row was signed."
          }
        },
        "required": [
          "seq",
          "at",
          "tool",
          "verdict",
          "trace",
          "pack",
          "hash",
          "prev"
        ],
        "description": "One sealed decision, as the gate wrote it to the hash-chained ledger (JSON Lines on disk)."
      },
      "VerifyResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "entries": {
            "type": "integer"
          },
          "problems": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "line": {
                  "type": "integer"
                },
                "message": {
                  "type": "string"
                }
              },
              "required": ["line", "message"]
            }
          },
          "tampered": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The row altered in memory before verifying, when `tamper` was given; otherwise null."
          },
          "repaired": {
            "type": "boolean",
            "description": "Whether the hashes were recomputed over the altered rows (`repair=1`)."
          },
          "signatures": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "checked": {
                    "type": "integer"
                  },
                  "failed": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "fingerprint": {
                    "type": "string"
                  }
                },
                "required": ["checked", "failed", "fingerprint"]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "ok",
          "entries",
          "problems",
          "tampered",
          "repaired",
          "signatures"
        ],
        "description": "The chain and the signatures, as `prae verify` checks them. `signatures` is null when no public key sits beside the ledger."
      },
      "Pack": {
        "type": "object",
        "properties": {
          "prae": {
            "type": "string"
          },
          "pack": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "baseline": {
            "type": "object",
            "properties": {
              "capabilities": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": ["capabilities"]
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackRule"
            }
          }
        },
        "required": ["prae", "pack", "version", "baseline", "rules"],
        "additionalProperties": true
      },
      "PackRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "when": {
            "type": "object",
            "additionalProperties": true
          },
          "effect": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string"
              },
              "because": {
                "type": "string"
              }
            },
            "required": ["kind", "because"]
          },
          "frameworks": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "required": ["id", "when", "effect"]
      },
      "PacksInForce": {
        "type": "object",
        "properties": {
          "packs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "file": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "version": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "owner": {
                  "type": "string"
                },
                "sha256": {
                  "type": "string"
                },
                "origin": {
                  "type": "string",
                  "enum": ["workspace", "builtin"]
                },
                "rules": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "kind": {
                        "type": "string"
                      },
                      "because": {
                        "type": "string"
                      }
                    },
                    "required": ["id", "kind", "because"]
                  }
                }
              },
              "required": [
                "file",
                "name",
                "version",
                "sha256",
                "origin",
                "rules"
              ]
            }
          },
          "rejected": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "file": {
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                }
              },
              "required": ["file", "reason"]
            }
          }
        },
        "required": ["packs", "rejected"],
        "description": "The packs in force for the record, and every workspace pack the loader refused, with why."
      },
      "Guardian": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "attaches": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "reason": {
            "type": "string"
          },
          "watches": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "armed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "policy": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "minItems": 2,
              "maxItems": 2
            }
          }
        },
        "required": ["id", "name", "attaches", "reason", "watches", "rules"]
      },
      "Catalogue": {
        "type": "object",
        "properties": {
          "prae-guardians": {
            "type": "string"
          },
          "pack": {
            "type": "string"
          },
          "guardians": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Guardian"
            }
          }
        },
        "required": ["prae-guardians", "pack", "guardians"]
      },
      "Skill": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "enum": ["workspace", "user"]
          },
          "description": {
            "type": "string"
          },
          "integrity": {
            "type": "object",
            "properties": {
              "hash": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": ["verified", "modified"]
              }
            },
            "required": ["hash", "status"]
          },
          "declared": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "observed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mismatches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "capability": {
                  "type": "string"
                },
                "detail": {
                  "type": "string"
                }
              },
              "required": ["capability"]
            }
          },
          "risk": {
            "type": "string",
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
          },
          "trusted": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "source",
          "scope",
          "integrity",
          "declared",
          "observed",
          "mismatches",
          "risk",
          "trusted"
        ]
      },
      "Discovery": {
        "type": "object",
        "properties": {
          "at": {
            "type": "string"
          },
          "agent": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "runtime": {
                "type": "string"
              },
              "workspace": {
                "type": "string"
              }
            },
            "required": ["name", "runtime", "workspace"]
          },
          "workspace": {
            "type": "object",
            "properties": {
              "files": {
                "type": "integer"
              },
              "bytes": {
                "type": "integer"
              },
              "dirs": {
                "type": "object",
                "additionalProperties": {
                  "type": "integer"
                }
              }
            },
            "required": ["files", "bytes", "dirs"]
          },
          "filesystem": {
            "type": "object",
            "properties": {
              "read": {
                "type": "boolean"
              },
              "write": {
                "type": "boolean"
              },
              "paths": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": ["read", "write", "paths"]
          },
          "network": {
            "type": "object",
            "properties": {
              "fetch": {
                "type": "boolean"
              },
              "destinations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "host": {
                      "type": "string"
                    },
                    "paths": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "approved": {
                      "type": "boolean"
                    }
                  },
                  "required": ["host", "paths", "files", "approved"]
                }
              },
              "apis": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": ["fetch", "destinations", "apis"]
          },
          "process": {
            "type": "object",
            "properties": {
              "spawn": {
                "type": "boolean"
              },
              "commands": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "packageManager": {
                "type": "string"
              }
            },
            "required": ["spawn", "commands"]
          },
          "mcp": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "servers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "tools": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": ["name", "tools"]
                }
              }
            },
            "required": ["enabled", "servers"]
          },
          "secrets": {
            "type": "object",
            "properties": {
              "detected": {
                "type": "boolean"
              },
              "files": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "file": {
                      "type": "string"
                    },
                    "types": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "findings": {
                      "type": "integer"
                    }
                  },
                  "required": ["file", "types", "findings"]
                }
              },
              "environmentNames": {
                "type": "integer"
              }
            },
            "required": ["detected", "files", "environmentNames"]
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string"
                },
                "where": {
                  "type": "string"
                },
                "files": {
                  "type": "integer"
                }
              },
              "required": ["category", "where", "files"]
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "skills": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Skill"
            }
          },
          "git": {
            "type": "object",
            "properties": {
              "repository": {
                "type": "boolean"
              }
            },
            "required": ["repository"]
          }
        },
        "required": [
          "at",
          "workspace",
          "filesystem",
          "network",
          "process",
          "mcp",
          "secrets",
          "data",
          "tools",
          "skills",
          "git"
        ],
        "description": "What the run discovered about the agent's workspace: reachability, never proof of use."
      },
      "ReportResult": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "given": {
            "type": "string"
          },
          "when": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "verdict": {
            "$ref": "#/components/schemas/Verdict"
          },
          "rule": {
            "type": "string"
          },
          "guardian": {
            "type": "string"
          },
          "owasp2026": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "executed": {
            "type": "boolean"
          },
          "pass": {
            "type": "boolean"
          },
          "failures": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "group": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "given",
          "when",
          "owasp2026",
          "pass",
          "failures",
          "group"
        ]
      },
      "Report": {
        "type": "object",
        "properties": {
          "suite": {
            "type": "string"
          },
          "pack": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "at": {
            "type": "string"
          },
          "scenarios": {
            "type": "integer"
          },
          "prevented": {
            "type": "integer"
          },
          "decisions": {
            "type": "integer"
          },
          "allowed": {
            "type": "integer"
          },
          "blocked": {
            "type": "integer"
          },
          "signatures": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "credentialLinesChecked": {
            "type": "integer"
          },
          "credentialLinesLeaked": {
            "type": "integer"
          },
          "discovery": {
            "type": "object",
            "properties": {
              "files": {
                "type": "integer"
              },
              "apis": {
                "type": "integer"
              },
              "hosts": {
                "type": "integer"
              },
              "mcpTools": {
                "type": "integer"
              },
              "credentialFiles": {
                "type": "integer"
              },
              "skills": {
                "type": "integer"
              },
              "mismatches": {
                "type": "integer"
              }
            },
            "required": [
              "files",
              "apis",
              "hosts",
              "mcpTools",
              "credentialFiles",
              "skills",
              "mismatches"
            ]
          },
          "events": {
            "type": "integer"
          },
          "skills": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Skill"
            }
          },
          "guardians": {
            "type": "object",
            "properties": {
              "attached": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "interventions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "interventions": {
                      "type": "integer"
                    }
                  },
                  "required": ["name", "interventions"]
                }
              }
            },
            "required": ["attached", "interventions"]
          },
          "threatPath": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "session": {
            "type": "string"
          },
          "run": {
            "type": "integer"
          },
          "cumulative": {
            "type": "object",
            "additionalProperties": true
          },
          "groups": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "pass": {
                  "type": "boolean"
                }
              },
              "required": ["name", "pass"]
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReportResult"
            }
          },
          "result": {
            "type": "string",
            "enum": ["PASS", "FAIL"]
          }
        },
        "required": [
          "suite",
          "pack",
          "key",
          "at",
          "scenarios",
          "prevented",
          "decisions",
          "allowed",
          "blocked",
          "signatures",
          "credentialLinesChecked",
          "credentialLinesLeaked",
          "discovery",
          "events",
          "skills",
          "guardians",
          "threatPath",
          "groups",
          "results",
          "result"
        ],
        "description": "The security report the test suite wrote for the record."
      },
      "RecordSnapshot": {
        "type": "object",
        "properties": {
          "ledger": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LedgerRow"
            }
          },
          "discovery": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Discovery"
              },
              {
                "type": "null"
              }
            ]
          },
          "report": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Report"
              },
              {
                "type": "null"
              }
            ]
          },
          "guardians": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Catalogue"
              },
              {
                "type": "null"
              }
            ]
          },
          "pack": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Pack"
              },
              {
                "type": "null"
              }
            ]
          },
          "crownJewel": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true,
                "description": "The asset a crown-jewel run attacks, when one wrote `crown-jewel.json`."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "ledger",
          "discovery",
          "report",
          "guardians",
          "pack",
          "crownJewel"
        ],
        "description": "Every file of the record, read from disk at request time. A file that is missing or not JSON is null."
      },
      "RecordStatus": {
        "type": "object",
        "properties": {
          "dir": {
            "type": "string",
            "description": "The record directory on the operator's machine."
          },
          "files": {
            "type": "object",
            "description": "Per record file (ledger, discovery, report, guardians, pack, packs, publicKey, redteam): its size and mtime, or null when absent.",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "size": {
                      "type": "integer"
                    },
                    "mtime": {
                      "type": "number",
                      "description": "Milliseconds since the epoch."
                    }
                  },
                  "required": ["size", "mtime"]
                },
                {
                  "type": "null"
                }
              ]
            }
          }
        },
        "required": ["dir", "files"]
      },
      "Redteam": {
        "type": "object",
        "properties": {
          "campaign": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true,
                "description": "The campaign summary (`campaign.json`), as the runner wrote it."
              },
              {
                "type": "null"
              }
            ]
          },
          "runs": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "One red-team run result file, as the runner wrote it."
            }
          },
          "steering": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "A steering run that carries an `objective`."
            }
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "A kept crown-jewel run, newest first."
            }
          }
        },
        "required": ["campaign", "runs", "steering", "history"],
        "description": "The red-team results directory, as the runner wrote it. Each item is a result file read verbatim; its shape is the runner's, not this API's, so it is not typed here."
      },
      "RedteamTest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "crown-jewel",
              "steer-follow",
              "steer-ignore",
              "operator-steer"
            ]
          },
          "run": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "agent": {
            "type": "object",
            "additionalProperties": true,
            "description": "The agent under test, as the scenario classifies it."
          },
          "crownJewel": {
            "type": "string"
          },
          "objective": {
            "type": "string"
          },
          "successConditions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["id", "run", "title", "successConditions"]
      },
      "RedteamRunState": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "test": {
            "type": "string"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "phase": {
            "type": "string",
            "enum": ["preparing", "running", "finished"]
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "exitCode": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "output": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The runner's last lines (at most 40), without colour codes."
          }
        },
        "required": ["id", "test", "startedAt", "phase", "output"]
      },
      "RedteamControl": {
        "type": "object",
        "properties": {
          "active": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RedteamRunState"
              },
              {
                "type": "null"
              }
            ]
          },
          "last": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RedteamRunState"
              },
              {
                "type": "null"
              }
            ]
          },
          "tests": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RedteamTest"
            }
          }
        },
        "required": ["active", "last", "tests"]
      },
      "HeldCall": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "at": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": ["held", "answer-sent", "abandoned"]
          },
          "alive": {
            "type": "boolean",
            "description": "Something is still waiting to take an answer."
          },
          "because": {
            "type": "string",
            "description": "Abandoned: why nothing will take an answer."
          },
          "answered": {
            "type": "string",
            "enum": ["allow", "deny", "steer"],
            "description": "An answer written and not yet taken."
          },
          "tool": {
            "type": "string"
          },
          "action": {
            "type": "string",
            "description": "The call as a reader would say it, rendered by the server from the canonical call the gate wrote. For a question with no canonical call this is a fixed sentence saying it cannot be approved."
          },
          "actionHash": {
            "type": "string",
            "description": "The hash the server computed from the canonical call: what an answer must cite and is signed over. Absent when the question carries no canonical call."
          },
          "reason": {
            "type": "string",
            "description": "The ASK row's reason from a verifying ledger, or a fixed sentence saying the call is unverified / suspect."
          },
          "seq": {
            "type": "integer"
          },
          "agent": {
            "type": "string",
            "description": "The asking session."
          }
        },
        "required": ["id", "at", "state", "alive", "tool", "action", "reason"],
        "description": "A call paused at the gate, waiting for the operator."
      },
      "Signing": {
        "type": "string",
        "enum": ["none", "locked", "unlocked"],
        "description": "`none`: the record has no operator key. `locked`: a sealed key exists but is not unlocked for this operator session. `unlocked`: the caller presents a valid `X-PRAE-Operator-Session` and the key is unlocked in the server's memory."
      },
      "OperatorState": {
        "type": "object",
        "properties": {
          "pending": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HeldCall"
            }
          },
          "signing": {
            "$ref": "#/components/schemas/Signing"
          },
          "minPassphrase": {
            "type": "integer",
            "description": "Minimum passphrase length when creating an operator key (12)."
          },
          "signingAs": {
            "type": "string",
            "description": "Fingerprint of the unlocked operator key. Only when `signing` is `unlocked`."
          }
        },
        "required": ["pending", "signing", "minPassphrase"]
      },
      "OperatorRequest": {
        "description": "Exactly one of the operations below. Lock, dismiss and answer require the `X-PRAE-Operator-Session` header once an operator key exists.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "create": {
                "type": "string",
                "minLength": 12,
                "description": "Create the record's operator key with this passphrase (fresh record only), seal it at rest and unlock it for this session."
              }
            },
            "required": ["create"],
            "title": "Create key",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "unlock": {
                "type": "string",
                "description": "Unlock the sealed operator key with its passphrase; a new session token is issued."
              }
            },
            "required": ["unlock"],
            "title": "Unlock",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "lock": {
                "type": "boolean",
                "const": true
              }
            },
            "required": ["lock"],
            "title": "Lock",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "The held question."
              },
              "dismiss": {
                "type": "boolean",
                "const": true
              }
            },
            "required": ["id", "dismiss"],
            "title": "Dismiss an abandoned question",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "The held question."
              },
              "decision": {
                "type": "string",
                "enum": ["allow", "deny", "steer"]
              },
              "instruction": {
                "type": "string",
                "maxLength": 1000,
                "description": "Required for `steer`."
              },
              "actionHash": {
                "type": "string",
                "description": "Must equal the `actionHash` the server showed for this question; otherwise nothing is signed (409)."
              }
            },
            "required": ["id", "decision", "actionHash"],
            "title": "Answer",
            "additionalProperties": false
          }
        ]
      },
      "OperatorSession": {
        "type": "object",
        "properties": {
          "signing": {
            "$ref": "#/components/schemas/Signing"
          },
          "session": {
            "type": "string",
            "description": "Hex token for the `X-PRAE-Operator-Session` header. Held in the browser tab's memory only."
          }
        },
        "required": ["signing"]
      },
      "Ok": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        },
        "required": ["ok"]
      },
      "FleetConstraint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "guardian": {
            "type": "string"
          },
          "asset": {
            "type": "string"
          },
          "effect": {
            "type": "string",
            "enum": ["deny", "ask"]
          },
          "kind": {
            "type": "string",
            "enum": ["capability", "resource"]
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expected": {
            "type": "string",
            "description": "What the operator is told will happen, before confirming."
          }
        },
        "required": [
          "id",
          "code",
          "label",
          "guardian",
          "asset",
          "effect",
          "kind",
          "tools",
          "expected"
        ]
      },
      "FleetAgent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "team": {
            "type": "string"
          },
          "environment": {
            "type": "string"
          },
          "surface": {
            "type": "string"
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "crownJewels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "state": {
            "type": "string",
            "enum": ["starting", "running", "finished", "contained"]
          },
          "cohort": {
            "type": "string"
          },
          "compromised": {
            "type": "boolean"
          },
          "product": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": ["agent", "custom-agent"]
          },
          "where": {
            "type": "string"
          },
          "runtime": {
            "type": "string"
          },
          "workload": {
            "type": "string"
          },
          "identity": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "unit": {
            "type": "string"
          },
          "session": {
            "type": "string"
          },
          "pid": {
            "type": "integer"
          },
          "startedAt": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string"
          },
          "exitCode": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "limits": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "held": {
            "type": "object",
            "additionalProperties": true
          },
          "now": {
            "type": "object",
            "additionalProperties": true,
            "description": "What it is doing right now, written by the runner per step."
          },
          "last": {
            "type": "object",
            "additionalProperties": true
          },
          "redirected": {
            "type": "object",
            "additionalProperties": true
          },
          "suspended": {
            "type": "object",
            "additionalProperties": true
          },
          "runtimeSecret": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "role",
          "team",
          "environment",
          "surface",
          "tools",
          "crownJewels",
          "state"
        ],
        "additionalProperties": true
      },
      "FleetIntervention": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": ["steer", "unsteer", "contain", "pause", "resume"]
          },
          "at": {
            "type": "string"
          },
          "seq": {
            "type": "integer"
          },
          "operator": {
            "type": "string",
            "description": "Fingerprint of the operator key that signed the request."
          },
          "constraint": {
            "type": "string"
          },
          "cohort": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "of": {
            "type": "string"
          },
          "previous": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "effect": {
            "type": "object",
            "additionalProperties": true
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "agent": {
                  "type": "string"
                },
                "session": {
                  "type": "string"
                },
                "delivered": {
                  "type": "boolean"
                },
                "why": {
                  "type": "string"
                }
              },
              "required": ["agent", "delivered"]
            }
          }
        },
        "required": ["id", "kind", "at", "seq", "operator", "targets"]
      },
      "FleetState": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "crownJewel": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "startedAt": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string"
          },
          "stopped": {
            "type": "boolean",
            "description": "Set by the server when the runner process is gone: the fleet will take no request."
          },
          "stoppedAt": {
            "type": "string"
          },
          "fromSeq": {
            "type": "integer"
          },
          "operator": {
            "type": "string"
          },
          "constraints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetConstraint"
            }
          },
          "resources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "redTeam": {
            "type": "object",
            "additionalProperties": true
          },
          "agents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetAgent"
            }
          },
          "interventions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetIntervention"
            }
          }
        },
        "required": [
          "id",
          "title",
          "crownJewel",
          "model",
          "startedAt",
          "fromSeq",
          "operator",
          "constraints",
          "agents",
          "interventions"
        ],
        "additionalProperties": true,
        "description": "The runner's `fleet.json`, read at request time. Which agents exist and which interventions were sealed; what the agents did is read from the ledger, not from here."
      },
      "FleetRun": {
        "type": "object",
        "properties": {
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "agents": {
            "type": "integer"
          },
          "phase": {
            "type": "string",
            "enum": ["preparing", "running", "finished"]
          },
          "exitCode": {
            "oneOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "output": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The runner's last lines (at most 40), without colour codes."
          },
          "stopping": {
            "type": "boolean"
          }
        },
        "required": ["startedAt", "agents", "phase", "output"],
        "description": "The runner process this console started."
      },
      "FleetControl": {
        "type": "object",
        "properties": {
          "fleet": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FleetState"
              },
              {
                "type": "null"
              }
            ]
          },
          "run": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FleetRun"
              },
              {
                "type": "null"
              }
            ]
          },
          "active": {
            "type": "boolean",
            "description": "Whether this console has a runner process now."
          },
          "constraints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetConstraint"
            }
          },
          "signing": {
            "$ref": "#/components/schemas/Signing"
          }
        },
        "required": ["fleet", "run", "active", "constraints", "signing"]
      },
      "FleetTargets": {
        "type": "object",
        "properties": {
          "targets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "description": "Agent ids of the running fleet."
          },
          "reason": {
            "type": "string",
            "maxLength": 280
          },
          "cohort": {
            "type": "string",
            "maxLength": 280,
            "description": "How the operator chose the cohort, in words."
          }
        },
        "required": ["targets"]
      },
      "FleetAccepted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The intervention's id. The request was signed and placed for the runner; its effect is read later from the ledger."
          }
        },
        "required": ["id"]
      },
      "TrustAttack": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "attack": {
            "type": "string"
          },
          "call": {
            "type": "object",
            "properties": {
              "tool": {
                "type": "string"
              },
              "args": {
                "type": "object",
                "additionalProperties": true
              }
            },
            "required": ["tool", "args"]
          },
          "expected": {
            "type": "string"
          },
          "kernel": {
            "type": "boolean"
          },
          "needs": {
            "type": "string"
          }
        },
        "required": ["id", "title", "attack", "call", "expected", "kernel"]
      },
      "TrustSnapshot": {
        "type": "object",
        "properties": {
          "now": {
            "type": "string",
            "format": "date-time"
          },
          "readiness": {
            "type": "object",
            "properties": {
              "record": {
                "description": "The readiness record as read (parsed JSON), or null."
              },
              "sha256": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "path": {
                "type": "string"
              },
              "error": {
                "type": "string"
              }
            },
            "required": ["record", "sha256", "path"]
          },
          "build": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string"
              },
              "commit": {
                "type": "string"
              },
              "dirty": {
                "type": "boolean"
              }
            },
            "required": ["version", "commit", "dirty"]
          },
          "provenance": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "record": {
                "description": "The provenance record as read (parsed JSON), or null."
              },
              "sha256": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "error": {
                "type": "string"
              },
              "sbom": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "file": {
                        "type": "string"
                      },
                      "sha256": {
                        "type": "string"
                      }
                    },
                    "required": ["file", "sha256"]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "files": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": ["provenance.json", "connector.cdx.json"]
                }
              }
            },
            "required": ["configured", "record", "sha256", "sbom", "files"]
          },
          "attacks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrustAttack"
            }
          }
        },
        "required": ["now", "readiness", "build", "provenance", "attacks"]
      },
      "SealedRow": {
        "type": "object",
        "properties": {
          "seq": {
            "type": "integer"
          },
          "hash": {
            "type": "string"
          },
          "prev": {
            "type": "string"
          },
          "tool": {
            "type": "string"
          },
          "verdict": {
            "type": "string"
          },
          "rule": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "signed": {
            "type": "boolean"
          }
        },
        "required": ["seq", "hash", "prev", "tool", "verdict", "rule", "signed"]
      },
      "AttackRun": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "attack": {
            "type": "string"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "phase": {
            "type": "string",
            "enum": ["starting", "evaluating", "decided", "recorded", "failed"]
          },
          "phases": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "phase": {
                  "type": "string"
                },
                "at": {
                  "type": "string"
                }
              },
              "required": ["phase", "at"]
            }
          },
          "session": {
            "type": "string"
          },
          "agent": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "simulated": {
                "type": "boolean"
              }
            },
            "required": ["name", "type", "simulated"]
          },
          "tool": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "decision": {
            "type": "object",
            "properties": {
              "verdict": {
                "type": "string"
              },
              "reason": {
                "type": "string"
              }
            },
            "required": ["verdict", "reason"]
          },
          "held": {
            "type": "string"
          },
          "replayed": {
            "type": "string"
          },
          "answer": {
            "type": "string"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SealedRow"
            },
            "description": "The rows the runner sealed, present only once read back from the ledger and matched by hash."
          },
          "error": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "output": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["id", "attack", "startedAt", "phase", "phases", "output"]
      },
      "AttackControl": {
        "type": "object",
        "properties": {
          "active": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AttackRun"
              },
              {
                "type": "null"
              }
            ]
          },
          "last": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AttackRun"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": ["active", "last"]
      },
      "Receipt": {
        "type": "object",
        "properties": {
          "receipt": {
            "type": "string",
            "const": "prae/1"
          },
          "entry": {
            "$ref": "#/components/schemas/LedgerRow"
          },
          "signature": {
            "type": "string"
          },
          "publicKey": {
            "type": "string",
            "description": "PEM, SPKI."
          }
        },
        "required": ["receipt", "entry", "signature", "publicKey"]
      },
      "ReceiptVerdict": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "ok": {
                "type": "boolean",
                "const": true
              }
            },
            "required": ["ok"]
          },
          {
            "type": "object",
            "properties": {
              "ok": {
                "type": "boolean",
                "const": false
              },
              "reason": {
                "type": "string"
              }
            },
            "required": ["ok", "reason"]
          }
        ]
      },
      "ReceiptResponse": {
        "type": "object",
        "properties": {
          "receipt": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Receipt"
              },
              {
                "type": "null"
              }
            ]
          },
          "verified": {
            "$ref": "#/components/schemas/ReceiptVerdict"
          }
        },
        "required": ["receipt", "verified"],
        "description": "`receipt` is null, with `verified.ok` false, when the row is unsigned or no public key sits beside the ledger."
      },
      "LedgerSummary": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "integer"
          },
          "chain": {
            "type": "string",
            "enum": ["verified", "failed", "empty"]
          },
          "problems": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "line": {
                  "type": "integer"
                },
                "message": {
                  "type": "string"
                }
              },
              "required": ["line", "message"]
            }
          },
          "signatures": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "checked": {
                    "type": "integer"
                  },
                  "failed": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "fingerprint": {
                    "type": "string"
                  }
                },
                "required": ["checked", "failed", "fingerprint"]
              },
              {
                "type": "null"
              }
            ]
          },
          "head": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "first": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "last": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "entries",
          "chain",
          "problems",
          "signatures",
          "head",
          "first",
          "last"
        ]
      },
      "EvidencePackage": {
        "type": "object",
        "properties": {
          "schema": {
            "type": "string",
            "const": "prae.trust-package/1"
          },
          "id": {
            "type": "string",
            "description": "sha256 of the package text without the id: it identifies the content, it is not a signature."
          },
          "exportedAt": {
            "type": "string",
            "format": "date-time"
          },
          "statement": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "object",
            "additionalProperties": true
          },
          "build": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string"
              },
              "commit": {
                "type": "string"
              },
              "dirty": {
                "type": "boolean"
              }
            },
            "required": ["version", "commit", "dirty"]
          },
          "validation": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "validationError": {
            "type": "string"
          },
          "coverage": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "limitations": {},
          "provenance": {
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "provenanceNote": {
            "type": "string"
          },
          "signature": {
            "type": "string"
          },
          "sbom": {
            "type": "object",
            "properties": {
              "reference": {},
              "local": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "file": {
                        "type": "string"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "matchesProvenance": {
                        "type": "boolean"
                      }
                    },
                    "required": ["file", "sha256", "matchesProvenance"]
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": ["reference", "local"]
          },
          "ledger": {
            "$ref": "#/components/schemas/LedgerSummary"
          },
          "hashes": {
            "type": "object",
            "properties": {
              "readiness": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "provenance": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "sbom": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "ledgerHead": {
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": ["readiness", "provenance", "sbom", "ledgerHead"]
          }
        },
        "required": [
          "schema",
          "id",
          "exportedAt",
          "statement",
          "status",
          "build",
          "validation",
          "coverage",
          "limitations",
          "provenance",
          "provenanceNote",
          "signature",
          "sbom",
          "ledger",
          "hashes"
        ],
        "description": "The security evidence package: deterministic, keys sorted at every depth. Sent as an attachment."
      },
      "Finding": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": ["credential", "environment", "mismatch", "destination"]
          },
          "asset": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": ["high", "medium"]
          },
          "title": {
            "type": "string"
          },
          "evidence": {
            "type": "string"
          },
          "remedy": {
            "type": "string"
          },
          "owner": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": ["open", "in progress", "fixed", "accepted risk"]
          },
          "due": {
            "type": "string"
          },
          "resolution": {
            "type": "string",
            "enum": ["manual", "verified"]
          },
          "lastEvidenceAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "kind",
          "asset",
          "severity",
          "title",
          "evidence",
          "remedy",
          "owner",
          "status",
          "due"
        ]
      },
      "PostureView": {
        "type": "object",
        "properties": {
          "agent": {
            "type": "string",
            "description": "The agent's key: name, runtime and workspace as one JSON string."
          },
          "name": {
            "type": "string"
          },
          "observedAt": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "policy": {
            "type": "string"
          },
          "sessions": {
            "type": "integer"
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Finding"
            }
          },
          "sensitiveData": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "declared": {
                  "type": "string"
                },
                "granted": {
                  "type": "string"
                },
                "attempts": {
                  "type": "integer"
                },
                "authorized": {
                  "type": "integer"
                },
                "used": {
                  "type": "null",
                  "description": "Use is never inferred: always null."
                },
                "last": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id",
                "declared",
                "granted",
                "attempts",
                "authorized",
                "used",
                "last"
              ]
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "evidence": {
                  "type": "string"
                },
                "automatic": {
                  "type": "boolean",
                  "const": false
                }
              },
              "required": ["id", "title", "evidence", "automatic"]
            }
          }
        },
        "required": [
          "agent",
          "name",
          "observedAt",
          "policy",
          "sessions",
          "findings",
          "sensitiveData",
          "capabilities",
          "recommendations"
        ],
        "description": "Derived from the record: discovery records reachability, policy records constraints; neither proves use."
      },
      "PostureState": {
        "type": "object",
        "properties": {
          "revision": {
            "type": "integer",
            "description": "Optimistic-concurrency revision: a mutation must cite the current one."
          },
          "workspace": {
            "type": "string"
          },
          "findings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Finding"
            }
          },
          "snapshots": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "at": {
                  "type": "string"
                },
                "policy": {
                  "type": "string"
                },
                "high": {
                  "oneOf": [
                    {
                      "type": "integer"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "medium": {
                  "oneOf": [
                    {
                      "type": "integer"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "kind": {
                  "type": "string",
                  "enum": ["discovery", "credential recheck"]
                },
                "scope": {
                  "type": "string"
                },
                "complete": {
                  "type": "boolean"
                }
              },
              "required": [
                "id",
                "at",
                "policy",
                "high",
                "medium",
                "kind",
                "scope",
                "complete"
              ]
            }
          },
          "audit": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "at": {
                  "type": "string"
                },
                "finding": {
                  "type": "string"
                },
                "action": {
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                },
                "actor": {
                  "type": "string",
                  "description": "An assertion typed at the console, never an authenticated identity."
                },
                "changes": {
                  "type": "object",
                  "additionalProperties": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              },
              "required": ["id", "at", "finding", "action", "reason", "actor"]
            }
          },
          "recommendations": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "action": {
                  "type": "string",
                  "enum": ["dismiss", "create finding"]
                },
                "reason": {
                  "type": "string"
                }
              },
              "required": ["action", "reason"]
            }
          }
        },
        "required": [
          "revision",
          "findings",
          "snapshots",
          "audit",
          "recommendations"
        ]
      },
      "PostureResponse": {
        "type": "object",
        "properties": {
          "view": {
            "$ref": "#/components/schemas/PostureView"
          },
          "state": {
            "$ref": "#/components/schemas/PostureState"
          },
          "canRescan": {
            "type": "boolean",
            "description": "Whether an agent workspace is configured (`PRAE_WORKSPACE`) for credential rechecks."
          }
        },
        "required": ["view", "state", "canRescan"]
      },
      "PostureRequest": {
        "description": "One action. Unknown fields are refused (400). Every action except `capture` must cite the current `revision` (409 otherwise). String fields are at most 2000 characters.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "const": "capture"
              }
            },
            "required": ["action"],
            "title": "Capture a snapshot",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "const": "update"
              },
              "id": {
                "type": "string"
              },
              "revision": {
                "type": "integer"
              },
              "owner": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": ["open", "in progress", "fixed", "accepted risk"]
              },
              "reason": {
                "type": "string"
              },
              "due": {
                "type": "string"
              }
            },
            "required": [
              "action",
              "id",
              "revision",
              "owner",
              "status",
              "reason",
              "due"
            ],
            "title": "Update a finding",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "const": "rescan"
              },
              "revision": {
                "type": "integer"
              }
            },
            "required": ["action", "revision"],
            "title": "Recheck credentials in the workspace",
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "const": "recommend"
              },
              "id": {
                "type": "string"
              },
              "revision": {
                "type": "integer"
              },
              "choice": {
                "type": "string",
                "enum": ["dismiss", "create finding"]
              },
              "reason": {
                "type": "string"
              }
            },
            "required": ["action", "id", "revision", "choice", "reason"],
            "title": "Act on a recommendation",
            "additionalProperties": false
          }
        ]
      },
      "ControlEvidence": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "asks": {
            "type": "string"
          },
          "framework": {
            "type": "string"
          },
          "frameworkName": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": ["covered", "partial", "absent"]
          },
          "note": {
            "type": "string"
          }
        },
        "required": ["id", "asks", "framework", "state", "note"],
        "additionalProperties": true
      },
      "Period": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "all"
              }
            },
            "required": ["kind"]
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "days"
              },
              "days": {
                "type": "integer"
              }
            },
            "required": ["kind", "days"]
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "custom"
              },
              "from": {
                "type": "string"
              },
              "to": {
                "type": "string"
              }
            },
            "required": ["kind", "from", "to"]
          }
        ]
      },
      "ComplianceScope": {
        "type": "object",
        "properties": {
          "frameworks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Framework ids from the catalog."
          },
          "controls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Control keys, `<framework id>:<control id>`."
          },
          "agents": {
            "oneOf": [
              {
                "type": "string",
                "const": "all"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "sessions": {
            "oneOf": [
              {
                "type": "string",
                "const": "all"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "period": {
            "$ref": "#/components/schemas/Period"
          }
        },
        "required": ["frameworks", "controls", "agents", "sessions", "period"],
        "description": "Which frameworks, controls, agents, sessions and period the Compliance view assesses. It chooses what is read; it never changes a ledger row."
      },
      "EvidenceRow": {
        "type": "object",
        "properties": {
          "seq": {
            "type": "integer"
          },
          "at": {
            "type": "string"
          },
          "tool": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "verdict": {
            "type": "string"
          },
          "rule": {
            "type": "string"
          },
          "session": {
            "type": "string"
          },
          "agent": {
            "type": "string"
          },
          "hash": {
            "type": "string"
          }
        },
        "required": ["seq", "at", "tool", "verdict", "agent", "hash"]
      },
      "AssessedControl": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "asks": {
            "type": "string"
          },
          "inScope": {
            "type": "boolean"
          },
          "state": {
            "type": "string",
            "enum": ["covered", "partial", "absent", "not-in-scope"]
          },
          "note": {
            "type": "string"
          },
          "rules": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "evidence": {
            "type": "object",
            "properties": {
              "count": {
                "type": "integer"
              },
              "rows": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EvidenceRow"
                },
                "description": "The newest rows, at most 50."
              }
            },
            "required": ["count", "rows"]
          }
        },
        "required": [
          "key",
          "id",
          "asks",
          "inScope",
          "state",
          "note",
          "rules",
          "evidence"
        ]
      },
      "AssessedFramework": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "custom": {
            "type": "boolean",
            "const": true
          },
          "selected": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "inScope": {
            "type": "integer"
          },
          "covered": {
            "type": "integer"
          },
          "partial": {
            "type": "integer"
          },
          "absent": {
            "type": "integer"
          },
          "controls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssessedControl"
            }
          }
        },
        "required": [
          "id",
          "name",
          "selected",
          "total",
          "inScope",
          "covered",
          "partial",
          "absent",
          "controls"
        ]
      },
      "Assessment": {
        "type": "object",
        "properties": {
          "scope": {
            "$ref": "#/components/schemas/ComplianceScope"
          },
          "frameworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssessedFramework"
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "frameworks": {
                "type": "integer"
              },
              "controls": {
                "type": "integer"
              },
              "withEvidence": {
                "type": "integer"
              },
              "covered": {
                "type": "integer"
              },
              "partial": {
                "type": "integer"
              },
              "absent": {
                "type": "integer"
              }
            },
            "required": [
              "frameworks",
              "controls",
              "withEvidence",
              "covered",
              "partial",
              "absent"
            ]
          },
          "dimensions": {
            "type": "object",
            "properties": {
              "agents": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "sessions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "rows": {
                      "type": "integer"
                    },
                    "first": {
                      "type": "string"
                    },
                    "last": {
                      "type": "string"
                    }
                  },
                  "required": ["id", "rows", "first", "last"]
                }
              },
              "environment": {
                "type": "string"
              }
            },
            "required": ["agents", "sessions", "environment"]
          },
          "rows": {
            "type": "object",
            "properties": {
              "admitted": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              }
            },
            "required": ["admitted", "total"]
          },
          "saved": {
            "type": "boolean",
            "description": "Whether a scope file is saved for this record (otherwise the default scope is in force)."
          },
          "catalogError": {
            "type": "string",
            "description": "Why the record's own `compliance-catalog.json` was not used, when it did not parse."
          }
        },
        "required": [
          "scope",
          "frameworks",
          "totals",
          "dimensions",
          "rows",
          "saved"
        ]
      },
      "Compliance": {
        "type": "object",
        "properties": {
          "assessment": {
            "$ref": "#/components/schemas/Assessment"
          },
          "controls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControlEvidence"
            }
          }
        },
        "required": ["assessment", "controls"],
        "description": "Evidence toward each control, from the pack and the ledger as they are now. Framed as evidence, never as compliance: an auditor decides."
      }
    },
    "headers": {
      "X-PRAE-API-Version": {
        "description": "The prae-cli version whose contract answered. Sent on every /api/* response by prae console --serve and by the Command Center server.",
        "schema": {
          "type": "string",
          "examples": ["0.9.2"]
        }
      },
      "Deprecation": {
        "description": "RFC 9745. Present only on a route that will be removed; the value is the date the deprecation took effect.",
        "schema": {
          "type": "string"
        }
      },
      "Sunset": {
        "description": "RFC 8594. Present only on a deprecated route; the earliest date it may stop answering, at least one minor release after Deprecation.",
        "schema": {
          "type": "string"
        }
      }
    }
  },
  "x-versioning": {
    "scheme": "package-semver",
    "header": "X-PRAE-API-Version",
    "deprecation": ["Deprecation", "Sunset"],
    "notice": "at least one minor release",
    "path-version": false
  }
}
