For the skeptic

We can't certify an agent is right. No one can.

So we don't sell proof of correctness. We make what an answer stood on — and what it skipped — visible, recomputable, and attributable, instead of hidden behind a checkmark the model gave itself. Trust status is a pure function of the evidence: status = f(evidence, …), recomputable by anyone, at a boundary the agent can't cross.

Recomputable

Every verdict re-derives from published evidence to the same answer on any machine, or it's a bug. No LLM judge, no score, no vibes.

Captured, not narrated

Results come from the log the harness wrote while the command ran (real exit codes), never from the model's story about the run.

Refuses or escalates

A turn structurally cannot end on unbacked "done": it refuses, or it escalates to you. It never silently proceeds.

The bypass list

Three ways to cheat it — and who catches each one.

We publish our bypass list — because "trust the boundaries, not the claimants" only means something if you can see where the boundaries are.

01

Tamper with it locally.

Caught

Edit the bundle, the logs, or the workflow state on your own machine. Locally, the evidence is a tamper-evident hash chain — break a link and the chain no longer verifies. But the authoritative catch isn't local: with the Trust Verify job wired in as a required check — the way the Flow Agents repo itself runs it — every pull request re-runs the real verification fresh in a clean environment the agent can't pre-disable, and reconciles your bundle against its own results. CI never trusts your bundle as a source of truth — it only uses it to detect divergence. A claimed pass that CI shows failing, or a command CI never ran, fails the job.

Honest residual: a determined agent can still flip a local kill-switch through its own shell. That's exactly why the authority lives in CI, not in the local gate. And the CI catch is only authoritative once you make the check required — installing the tool doesn't configure your branch protection for you.

02

Forge the content.

Caught

Fabricate a green result, or launder the exit code (npm test || true). The local gate rejects a verify command carrying ||, and CI re-runs your declared checks itself — then, with signing enabled (one flag on the action; on where we build Flow Agents, off by default), signs the result with a keyless Sigstore identity that only exists inside CI. An agent on your laptop has no such identity — it cannot mint that signature, no matter how clever the prompt. A fabricated "green" simply can't be signed.

Precise words: tamper-evident locally, tamper-resistant up to the CI identity boundary — never "tamper-proof."

03

Bypass as an admin.

Named, not caught

Force-merge past branch protection, or approve your own malicious change. Nothing machine-side stops this. It is the irreducible human boundary — the one place the whole model depends on trusting a person, not a proof. We name it in the open instead of hiding it. The mitigation is ordinary and honest: branch protection with enforced admins, code-owner review on the gate and CI config, and a human who declines the --admin shortcut.

Receipt: the layered defense and this exact residuals list are published in Flow Agents' anti-gaming trust security model (ADR 0017), and enforced by a required anti-gaming regression suite that turns CI red if any gate is weakened.

The objection

But isn't that what CI does?

For a code change that has a test, CI is a real backstop — it reruns the suite fresh and the PR goes red on a failure. We don't claim otherwise. The gap is around that.

01

CI is green on what nobody wrote a check for.

CI answers exactly one question — did the declared checks pass? — and is silent on the claim with no test behind it ("added validation and tested it," "verified the migration is reversible," "no security regression"). CI can't turn red on a claim it can't execute. We surface what was skipped, not just what passed.

02

We run inside CI too.

Wire the reconcile job in as a required check and it re-runs your declared checks, reconciling them against what the agent claimed it ran — if they diverge, CI goes red on the discrepancy itself — and, with signing on, signs the result with an identity that only exists inside CI, which an agent on a laptop cannot forge. CI's ephemeral green becomes a portable, independently recomputable receipt of what passed and what it stood on.

03

Before CI, in the loop.

The check fires while the agent works, not after a push, a PR, and a CI cycle — so a real failure surfaces before anything leaves the laptop. If the agent claims a check passed but nothing captured shows it ran, the gate doesn't take the claim on faith — it re-runs the project's own declared check itself, right there, and a real result stands in place of the claim. And if the agent tries to launder the exit code (npm test || true), the local gate rejects it as evidence on the spot — the same thing CI would catch on the PR, just earlier, before a push ever happens.

And every objection here assumes there's a CI at all. Research agents, support agents, records agents — none have one. For any agent that isn't code, this is the only check there is.

Signing is a dial, not a gate

Turn up assurance as the stakes rise.

Start unsigned and local in five minutes. Turn the dial to keyless CI identity, then to organization-held keys, as the stakes rise. The dial changes how much you can trust where a bundle came from — never how it was derived. An unsigned bundle recomputes to exactly the same verdict as a signed one.

L0 — Unsigned, local.

Recomputes identically to any other bundle; provenance is unverified. Five minutes to your first receipt.

L1 — Keyless CI identity.

CI signs its own fresh results with a short-lived OIDC identity — optionally anchored in a public transparency log anyone can inspect.

L2 — Organization-held keys.

Signing bound to keys your organization controls, for the highest-stakes work.

Assurance caps trust in provenance, never in derivation.

Receipt: the L0/L1/L2 assurance levels are defined in the open Hachure specification, with in-toto/DSSE and transparency-log interop.

Honest badging

Enforcement isn't uniform. Here's exactly where it blocks.

"Gates are laws" is only true where a runtime actually hands the gate real exit codes. Where it doesn't yet, we say so. A plain table, not a green blur.

Runtime Enforcement What it means
Claude Code Blocking The Stop hook refuses or escalates on unbacked "done."
Codex Blocking Same blocking path, mapped to Codex agent definitions.
Kiro Advisory / opt-in block Full blocking capability is wired, but the shipped default warns instead of blocking — set FLOW_AGENTS_GOAL_FIT_MODE=block to enforce.
opencode Advisory / partial Stop-goal-fit reports but can't block there; config protection still blocks at tool-call time.
pi Advisory / partial No stop hook — the done-check can't run; config protection still blocks at tool-call time.
AWS Strands (Python & TS) Advisory / partial Official framework adapters: config protection blocks at tool-call time; steering, quality, and stop policies are telemetry- or shim-only so far.
Other harnesses Spec-only The open format runs; no runtime hook yet.

Blocking means the turn cannot end on unproven work — it refuses or escalates to you, never silently proceeds. Advisory means the same evidence is computed and surfaced, but the decision stays with you. We badge the difference; we don't blur it.

Receipt: the runtime hook surface is documented in the Flow Agents README / runtime-hook-surface spec. That spec grades adapters on its own L0–L2 conformance scale — a different dial from the signing assurance levels above.

When it mattered

Two times the boundary held.

The agent that refused its own admin powers

Two green pull requests couldn't merge because branch protection demanded up-to-date branches, and the tooling offered --admin to force it. The agent declined — admin bypass is the one boundary the whole trust model names as irreducible, and an agent using it would hollow out every other guarantee. The branches were updated properly and CI re-certified before merge. Slower, and the only version of the story worth telling.

Receipt: the session's merge transcripts; ADR 0017's residuals naming admin bypass as the irreducible human boundary.

The security fix that almost shipped its own backdoor

Fixing a capture bug (failing commands recorded as passes on one runtime), the first patch opened a new critical hole: its parser could be fooled by a command that merely printed "Process exited with code 0." The mandatory adversarial re-review built a working exploit, confirmed it, and blocked the delivery before commit. The fix was re-planned, hardened, re-attacked (five fresh bypass attempts, all defeated), and merged only after CI independently re-ran and reconciled every claim.

Receipt: Flow Agents PR #475; the review artifacts show iteration-1 FAIL → iteration-2 PASS, with the Trust Reconcile check green.

Check the receipts yourself → Get early access →