How do you keep an AI agent's decisions honest after the evidence changes?
Today I am releasing Bellbook 0.3.0, the evolution epoch of the open-source Rust library for tamper-evident, replay-verifiable records of captured AI agent activity.
The first release answered a question about deeds: can we turn “the agent says it did X” into evidence another party can verify without trusting the agent or the system that produced it? This release answers the harder question that comes right after it, about decisions.
Agents do not only act. They choose. A coding agent generates a handful of candidate changes, runs a benchmark over them, and picks the one that scored best. It continues from that choice, builds on it, ships it. The record of what it did is honest and intact.
Then, weeks later, someone finds the benchmark was measuring the wrong thing.
Every candidate chosen on the strength of that benchmark is now suspect, and so is everything built on top of it. But which candidates, exactly, and to what depth? And the part that usually gets skipped: how do you correct the record without lying about it?
When the evidence a decision rested on turns out to be wrong, how do you fix the record - mechanically, verifiably, and without erasing what happened?
Bellbook 0.3.0 is my attempt at a small, precise answer.
Recording the decision, not just the deed
The v0.2 kernel recorded requests, authority, actions, and results. v0.3 adds three record kinds so the agent’s choices are written down with the same discipline:
- A Candidate is a proposed source state, bound to a Git tree. It is the content, not the commit message: two commits with the same tree are the same candidate.
- An Evaluation judges exactly one candidate under exactly one criterion - “benchmark-suite: passed”, “manual-review: passed”, a bounded score. One criterion per record is deliberate, and it is about to matter.
- A Selection is a set-valued decision: these candidates survive, under this objective, resting on this evaluation evidence.
The agent’s choice is no longer implicit in a diff. It is a record that says,
verifiably, “I selected candidate B over A, to meet objective O, because of
evaluation E.” The whole line of work - this candidate continues from that
selection, that one is derived from this candidate - is written down as typed
links between records, the same Cause, Use, Require, and Replace
relationships the kernel already used.
That is enough structure to answer the hard question by replay, instead of by hand.
Standing: which choices still rest on ground that holds
When the benchmark is found broken, you do not delete anything. You retract its evaluation: an append-only record stating the earlier content was wrong. The evaluation stays in the log forever. It is simply marked.
Two things then happen on the next replay, and both are computed from the log rather than asserted by anyone.
Taint follows the existing v0.2 rule. The retraction poisons every record
that epistemically depended on the retracted evaluation, so the Selection that
Used it becomes tainted. Taint follows use and requirement, not cause: a
repair merely motivated by the broken benchmark, but deriving its content
from a candidate that still stands, is not tainted. Motivation is not
contamination.
Standing is the new part. It is a replay-derived answer to one question, asked of every candidate: does its place in a chosen line still rest on states and decisions that stand? A candidate whose anchoring selection is now unsound is compromised - and so is everything that continues from it or derives from it, transitively, at any depth. The report lists them.
The load-bearing word is derived. Standing is not a flag someone sets. It is a pure function of the accepted records at the end of replay, recomputed from scratch by anyone who validates the receipt, exactly as forgery-resistant as the taint set because there is nothing to forge. The producer cannot declare its line sound. The replay decides.
And because retraction is record-granular and evaluations carry one criterion, you can retract just the broken benchmark metric without erasing a manual review that also passed. That surviving evidence is what recovery is built on.
Correction without amnesia
Here is what keeps the cascade from being a permanent alarm. The team re-runs a surviving evaluation - a criterion the broken harness never touched - and commits one reaffirming Selection: it replaces the old, now-unsound decision, re-selecting the same line on evidence that still holds. On the next replay, standing shows the whole descendant subtree restored. One record, any depth.
Nothing was erased to get there. The retraction is still on the record. The taint is still on the record. The window during which the line was compromised is still on the record. What changed is that the line now visibly rests on a decision and an evaluation that stand, and that is on the record too, permanently and verifiably.
That is the difference between hiding a mistake and correcting one. The cascade reads as actionable state, not as a scar you either erase or live with forever.
The whole episode runs as a worked example that prints the standing section changing at each step:
cargo run --example broken_benchmark
# baseline chosen on a benchmark -> line built on it -> benchmark retracted
# -> descendants compromised at every depth -> one reaffirmation -> restored
What this does not prove
The boundaries matter as much as the mechanism, so they are stated directly in the specification rather than left for a reader to discover.
Consistency, not completeness. Bellbook proves the recorded decisions are intact and their consequences correctly derived. Whether the agent recorded every decision it made depends on how the host instruments its runtime.
Producer discipline is load-bearing. A candidate’s basis, its parent, and its links are producer claims. A host that records what is really a continuation as an unrelated derivation escapes the standing cascade, and no verifier can detect that, because intent is not checkable. Standing verifies the consequences of the recorded structure; it does not verify that the structure was recorded honestly.
Integrity, not source contents. A receipt carries no source bytes. A candidate’s Git identifiers are pointers the repository resolves. A reported binding is a verifiable record of an unverified claim; a manifest binding lets a party holding the tree recompute the hash and bind the receipt to actual contents.
These are not hedges bolted on at the end. They are the line between what the system enforces and what it merely records, drawn on purpose, because a verification system becomes dangerous when its claims outrun its guarantees.
The old epoch still stands
v0.3 is a new compatibility epoch, and the previous one does not move. The v0.2 artifacts are frozen, the published 0.2.0 crate remains their validator, and a continuous-integration check installs that published validator on every commit and confirms the frozen v0.2 receipts still validate identically under it. A v0.3 validator rejects a v0.2 receipt with a clear unsupported-version report, so the two epochs never quietly blur together. Existing users on v0.2 are not carried anywhere they did not ask to go.
Open, and independently reproducible
If Bellbook’s value is that you do not have to trust the producer, then standing cannot be allowed to live inside one codebase either. The from-scratch Python implementation of the verifier, which shares no code with the Rust crate, now re-derives the standing section as well, and agrees with the Rust reference byte-for-decision across the whole v0.3 conformance corpus, including the deliberately corrupted and forged cases it rejects exactly where Rust does.
When two independent implementations agree on a receipt’s standing, the result is a fact about the specification, not a quirk of one author’s code.
Try it, inspect it, break it
Bellbook 0.3.0 is available under MIT or Apache-2.0:
The useful questions are still the concrete ones. Where can a producer record a lineage that escapes the cascade? Which retraction or recovery case is not covered? Can an independent implementation reproduce the same standing section on the same receipt? Where does the specification leave room for two validators to disagree about which decisions still stand?
The goal of this release is not to declare the decision-trust problem solved. It is to put a precise, testable answer in public - what an agent chose, and which of those choices still stand once the evidence moves - and let others examine whether it holds.