Operating the Harness¶
Audience: the administrator responsible for what the agents are allowed to do, who can see what, and whether the record can be trusted.
What works today. All of it. The safety model is implemented and tested, the services that expose it are running, and every control below is reachable from the console or the API.
1. What you are administering¶
The harness runs AI agents that investigate security alerts. Your job is the envelope they operate inside: how much autonomy they have, which systems they may touch, and what evidence survives afterwards.
Three things are true by construction and are not settings you can relax:
- No agent can act on operational technology. Power, cooling, building and industrial controls are capped at recommend-only, in platform code.
- Nothing changes state without a human, until that specific action type has earned the right through a clean record.
- Everything is recorded in an append-only, hash-chained log.
2. Autonomy tiers¶
| Tier | The agent | Typical use |
|---|---|---|
| T0 Observe | Reads, analyses, reports | Default for anything physical |
| T1 Recommend | Proposes with evidence; a human decides | High-impact actions |
| T2 Approve-to-act | Executes after a human approves | Contained, reversible actions |
| T3 Autonomous | Acts alone within guardrails | Low-risk only, and earned |
How a tier is decided¶
The effective tier is the lowest of every applicable limit:
effective = min(
what the playbook permits, # customer judgment — a ceiling, never a floor
what the asset class allows, # OT is capped at T1
what the action type has earned # from the autonomy ledger
)
Each limit is a named rule, so every decision records which one bound it. The console
shows that rule to the analyst — "held at T1 by ot-cap" rather than an unexplained
refusal.
Additional limits apply when relevant: a maintenance window holds state-changing actions, and the kill switch drops everything to T0.
Rules you cannot override¶
| Rule id | Effect |
|---|---|
ot-cap |
Anything on an OT-classified asset is capped at T1. |
asset-class-unknown |
An asset that cannot be classified is treated as OT. |
kill-switch |
All agent activity halts. |
maintenance-window |
State-changing actions are held for a human. |
earned-autonomy |
An action type cannot exceed what it has earned. Default T2. |
playbook-max |
The customer's declared ceiling. |
Two of these deserve emphasis because they are deliberately inconvenient:
Unclassified assets are treated as OT. When the asset inventory cannot say what something is, the system assumes the most consequential answer. In production this will occasionally block a legitimate action because the inventory is incomplete. That is the intended trade: not knowing what a target is must never be safer than knowing.
Autonomy defaults to T2, not T3. An action type with no evaluation record waits for a human. Silence from the ledger is not consent.
3. The audit chain¶
Every prompt, tool call, decision, approval, action and model choice is appended to a per-organisation chain. Each event's hash covers its own content plus the previous event's hash, so altering anything invalidates every hash after it.
What it gives you¶
- Tamper detection, located — verification reports the first event that fails.
- Replay — any incident can be walked step by step.
- Attribution — every event names the organisation, the actor and the incident.
- A resume point — events are densely numbered, so a reconnecting client picks up exactly where it left off with no gap and no duplicate.
Be precise about the claim¶
The chain is tamper-evident, not tamper-proof. Someone holding a trusted chain head can prove history was not altered. Without an external anchor, someone with write access to the entire store could rewrite every hash consistently. Anchoring the chain head is planned work, not a current property — describing this as "immutable" would overstate it, and a technical audience will test that claim.
Secrets never reach the chain¶
Payloads carry prompts and tool arguments, so a credential can arrive through entirely ordinary code. Redaction therefore runs before the hash is computed: the stored bytes and the hashed bytes are the same, and there is no window in which an unredacted value exists in the log.
This ordering matters more than it looks. If redaction ran afterwards, removing a leaked
secret would require rewriting the chain — destroying exactly the property the chain
exists to provide. Two independent mechanisms run: known secret values are masked
wherever they appear, and values under sensitive key names (authorization, api_key,
password, token, …) are replaced wholesale.
Verifying¶
Re-walks every tenant's chain and reports the first event that does not hold. Idempotent and safe to run at any time. The console shows the same result as a banner on the Audit & replay screen, so an analyst can see the check pass without taking anyone's word for it.
4. Tenant isolation¶
Each organisation has its own chain, held by the audit-store service — which is
the sole writer, because a chain with two writers is not a chain: the sequence
races and the hash links stop holding. Isolation is
visible rather than inferred — the files are separate, and one organisation's process
never opens another's.
Every request derives its organisation from the authenticated caller. A parameter can narrow that scope but never widen it, which is what makes isolation a structural property rather than a rule each endpoint has to remember.
For a proof of concept this is physical separation. A production system would use logical separation — a shared database with per-organisation schemas or row-level security. The property that survives that change is the chain; the mechanism does not. Worth stating plainly rather than letting a demonstration imply a stronger guarantee than the product will ship.
5. Controls¶
| Control | Effect | Where |
|---|---|---|
| Kill switch | Halts all agent activity. No further work is admitted; an incident already waiting at the approval gate cannot be approved through. | Console status bar, or POST /v1/control/kill |
| Air-gap mode | Blocks all outbound traffic and forces the local model. | ./deploy/bin/harness up-airgap, or HARNESS_AIRGAP |
| Model backend | Switches between stub, recorded, hosted and local. | HARNESS_MODEL_MODE |
| Maintenance window | Holds state-changing actions for a human. | Policy input; not yet surfaced in the console |
"Immediately" for the kill switch means the next admission is refused and no further work starts — asserted as semantics rather than as a wall-clock promise, which would be unfalsifiable on a loaded machine and meaningless on a cluster.
Every one of these is an audited event. Flipping a control is itself part of the record.
Egress¶
Outbound traffic has exactly one path: a proxy that is the only container with a route to the internet. It enforces an allow-list held as data, not code, and logs every attempt — allowed or refused — attributed to an organisation, an agent and an incident.
Air-gap mode is demonstrated three ways, deliberately: the router refuses non-local backends, the proxy denies everything, and in the strongest form the proxy's external network is removed entirely so no container has any route off the host. The first two are operational toggles; the third is architectural. They are different strengths of claim and should be described as such.
6. Routine tasks¶
| Task | How |
|---|---|
| Start, stop, reset | ./deploy/bin/harness up · down · reset |
| Check the stack is the code | ./deploy/bin/harness stale — compares the running version to this working tree. demo refuses if they differ. |
| Put identity back to its file | ./deploy/bin/harness reset-id (or ./deploy/bin/harness reset-identity) — discards every local account, password and session, then re-imports the realm. Asks first. |
| Prove the network topology | ./deploy/bin/harness verify |
| Verify every audit chain | ./deploy/bin/harness verify-chain |
| Show that the chain is tamper-evident | ./deploy/bin/harness verify-tamper — alters an exported copy and names the first event that no longer verifies. The real chain is not touched. |
| Report which acceptance criteria are proven | ./deploy/bin/harness criteria — runs the suite and reports a criterion green only when every proof named for it in eval/criteria.yaml passed in that run |
| Run the demonstration | ./deploy/bin/harness demo |
| Gate it before showing anyone | ./deploy/bin/harness dry-run — three clean runs from reset |
| Go air-gapped | ./deploy/bin/harness up-airgap |
| Fetch local model weights | ./deploy/bin/harness pull-model |
| See what is running | ./deploy/bin/harness ps · logs [svc] · shell <svc> |
| Check the safety model holds | uv run pytest -m "unit or property" |
| Check no customer content is in platform code | python3 tools/boundary-check/boundary_check.py |
| Check an acceptance criterion | uv run pytest -k a4 |
6a. What a reset keeps¶
Two commands, and the difference is what was produced against what was provisioned.
reset |
reset-id |
|
|---|---|---|
| Incidents and the audit chain | discarded | kept |
| Model weights | kept | kept |
| Local accounts, passwords, sessions | kept | discarded |
| The realm | kept as it stands | re-imported from deploy/keycloak/realm-harness.json |
reset keeps identity for the same reason it keeps the model weights: accounts are
something put into the system, not something it produced. An administrator whose
password reverted on every reset would not be an administrator.
The consequence is that the realm file seeds a new database and stops being
authoritative — Keycloak skips the import once the realm exists, which is exactly what
makes a password change persist. reset-id is the way back when the file and reality
have drifted, and it asks first because it discards every local change with them.
7. What this system deliberately does not do¶
Knowing the boundaries is part of operating it safely. In its current proof-of-concept form there is no brokering to an external directory (Keycloak can do it; it is not configured), no user management, registration, password reset or MFA, no role management beyond the three fixed roles, no TLS, no backup or retention policy, no high availability, no metrics stack, and no connectors to real security products. It runs on synthetic data only, and the lab accounts are not credentials.
It is not a production security platform and should not be pointed at one.
Related¶
- Glossary — any term here that did not land the first time
- Installing
- Using the harness — the analyst's view
- Authoring tradecraft
- ADR 0002 — how the boundary is enforced