# Excubitor changelog What changed in each release of the self-hosted edition: the image, both charts and the `excubitor-sdk` package. The release notes on GitHub carry the section for their version, above the signed artifacts. ## Excubitor 0.2.10 ### The self-hosted console never opens without sign-in - The console read API now refuses to start unless sign-in through Aurakore or a read token (`EXCUBITOR_API_TOKEN`) is configured. It prints what to set and stops. Before this release, a read API started with neither served every record and every export to anyone who could reach it. - Every read and every export needs a valid token. A request without one is refused, including on `/health`. - For development on your own machine only, `EXCUBITOR_CONSOLE_INSECURE_LOCAL=1` starts it without sign-in. It then answers only requests made on that machine itself, refuses anything that came through a proxy or from another address, logs every request it serves, and says "insecure local mode" on `/health`. It is ignored as soon as sign-in or a token is configured. Never set it on a deployment. - The console chart no longer offers `readApi.auth.allowUnauthenticated`. It needs sign-in through Aurakore (`aurakore.deploymentId`) or a read token secret, and will not install without one. - A valid token reads everything in its deployment. Access by role (who may see what, and who may export) applies on the hosted console. ### If you upgrade - Already using sign-in through Aurakore or a read token: nothing to change. - Running the read API with neither: configure one before upgrading, or the read API will not start. ## Excubitor 0.2.9 ### Every agent has an owner, or is listed - An agent Excubitor has never been told about is unclaimed from its first call. The console lists it with when it was first seen, what it called and from which application; a person claims it (naming its owner) or freezes it. `agent.claim` and `agent.unclaim` on the write surface, for the people named in `EXCUBITOR_CONTAINMENT_RELEASERS`. - `EXCUBITOR_UNCLAIMED=refuse` refuses every call from an agent nobody has claimed. The default, `observe`, records them and refuses nothing. Claim the agents you know before switching it on. - A claim counts only when the console wrote it: a record that arrived through ingest cannot claim its own agent. ### Find the AI you were not told about - `excubitor-discover code .` lists the MCP servers, model clients and agent frameworks a repository uses, each marked protected or not. - `excubitor-discover gcp --project ID` reads a Google Cloud project's audit logs for the identities calling its AI services, and how often. - Read-only and run by you. Each run can be recorded as one signed record: what was found and where, never file contents, keys or arguments. ### Records from outside the stack, on your own console - The write surface answers `POST /api/v1/excubitor/ingest`, the same contract as the hosted console: per-deployment bearer credentials, the application and deployment taken from the credential, batches of up to 500, idempotent by record id. Off until a credential is configured. - For Excubitor for Browsers on employees' laptops, and for applications using `HttpLedgerStore` with no route to the database. Ingested records are signed onto the deployment's own chain. - Credentials are configuration, kept as hashes only: `python -m excubitor.receiver new --app browser` prints the secret once and the entry for `EXCUBITOR_INGEST_CREDENTIALS` (Helm: `ingest.credentialsSecret`). Browser extensions are allowed by exact origin (`EXCUBITOR_INGEST_ORIGINS`, Helm: `ingest.origins`). - Claims and signature decisions that arrive through ingest are ignored on a self-hosted stack too, as they are on the hosted console. - Not yet on this endpoint: filing a CI gate report's findings under Code Review, and running the containment rules over an ingested call as it arrives. The records land in the ledger and the console reads them. ## Excubitor 0.2.8 ### Prove one record without the rest - Each signed checkpoint now carries the root of an RFC 6962 Merkle tree over its batch (the records since the previous checkpoint). One record can be shown with a short audit path and the signed checkpoint, and checked offline with the public key alone: `python -m excubitor.merkle check proof.json --key key.pem`. - One tree per batch, so retention prunes whole batches without breaking the proofs for what is kept. ### Red team on your schedule, with probe packs - `excubitor-redteam` probes a staging agent (an HTTP endpoint or a Python callable) from your own CI or cluster and records the scored report in your ledger. It asks something harmless first and sends nothing if the agent does not answer, refuses to run with nowhere to record, and exits 2 if the console did not take the report. Weekly templates for GitHub Actions and Kubernetes. - Probe packs: JSON files of extra probes, such as a Shield assessment's findings, validated before anything is sent. Also in the standing job (`EXCUBITOR_REDTEAM_PACKS`, Helm `redteam.packsConfigMap` and `redteam.packs`). - Every report names the agent, the schedule, each pack and the probe ids that ran. Never prompts or answers. ### Learned signatures - A probe that got through becomes a signature that flags the same wording the next time it reaches an agent. It refuses only after a person promotes it (`signature.enforce`); `signature.flag` and `signature.retire` undo it. - Signatures are records in the ledger and reach every default detection pipeline: from the hosted containment feed, or self-hosted from the deployment's own ledger. On a hosted console, a decision that arrived through ingest does not count. - A signature catches the same wording, not attacks that merely resemble it. ### Session review - A model reads each finished session's record, out of band, and writes a signed review: nothing unusual, worth a look, or concerning, with findings that must cite records in the session. It reads the record, never content, and stops nothing. - Self-hosted, the jobs sidecar runs it hourly on your own model (`EXCUBITOR_REVIEW_MODEL_URL`), so it works air-gapped with a local model. ### Network policy below the process - `excubitor-netpolicy` keeps one network policy per agent on Kubernetes in step with containment: allowed destinations normally, only DNS and the console once contained. Cilium (host names) or plain NetworkPolicy (address ranges). `deploy/k8s-excubitor-netpolicy.yaml` runs it with RBAC limited to network policies in the agents' namespace. ### Also - The AI register: a report of every agent, its applications, what it did and what was flagged, refused, held or contained, anchored to the ledger record it was computed through, with a SHA-256 digest anyone can recompute. - Decision Replay reads as a story: one card per step, oldest first, with the time and the step that caused it. Replay records carry their time. ## Excubitor 0.2.7 ### MCP, spoken properly The gateway used to accept only `POST /mcp/tools/{tool}`, a convention of Aurakore's own tool services, so a standard MCP server could not sit behind it. Excubitor now speaks the protocol (JSON-RPC 2.0): - The gateway serves Streamable HTTP on `/mcp`: JSON and event-stream answers, sessions, the server's own stream and session end. The client's token is never passed to the server; `upstream_token_provider` supplies the gateway's own. - `excubitor-mcp` wraps a server the client runs as a local process (stdio). - Both go through one `MCPGuard`: tool descriptions are scanned before the agent sees them (a poisoned tool is withheld), definitions are fingerprinted so a later change is reported, calls are refused for containment, policy, withheld or unoffered tools, rate limits, schema and injected arguments, and an answer carrying hidden instructions is withheld. Refusals are failed tool results the agent's model can read. - Tested with the official MCP SDK, 1.x and 2.x, over both transports. - Resources and prompts get the same checks: a resource read or a prompt fetched that carries hidden instructions is withheld (or reported), and a resource, template or prompt whose description hides instructions is taken out of its listing. - `StdoutJsonSink(stream=...)` writes elsewhere than stdout. ## Excubitor 0.2.6 ### Circuit breakers Two containment rules act on what the ledger shows, as it happens: - `identity_spread` contains an agent when three flagged identity alerts for the same subject arrive within an hour. - `destination_burst` contains an agent that sends 120 calls to one destination within ten minutes. `IdentityWatch` raises the burst alert itself, so the rule fires on the call that crosses the line. Both are in `DEFAULT_RULES`, in the same form as the hosted service. ### Delegation records A handoff from one agent to another is its own record (`phase: delegation`), naming who handed the work on, who received it, how, the run it came from and the run it started. What was handed on is recorded as a hash, never the text. - The ADK adapter records the framework's agent transfer and an agent used as a tool on its own. - `record_delegation(...)` records anything else. - The `delegation` report is exported at `/export/delegation`. ### Retention and the standing red team, on a schedule - `python -m excubitor.retention prune` removes the oldest part of the chain, up to a cutoff, and writes the prune into the ledger as a signed record. What remains still checks end to end from the new floor. - Unset, or 0, keeps everything. - `--dry-run` shows what would go. - `python -m excubitor.redteam run` runs the standing red team against a non-production agent and writes its report to the ledger. An unreachable target writes no report. - The console chart runs both in a `jobs` sidecar: - Retention runs daily when `retention.keepDays` is set. - The red team runs weekly when `redteam.targetUrl` is set. - `/api/retention` reports the retention in force. ### The offline bundle `excubitor-offline-0.2.6.tar.gz` is attached to this release for a network with no route out. It holds: - the image exactly as signed (amd64, arm64), - both charts, - the package with every wheel it needs for Linux, - `install-offline.sh`. `SHA256SUMS` inside it is signed with the release key, so the bundle checks with openssl alone.