A ledger is the permanent, append only book of every transaction: what, when, who, how much. Entries are never edited; a mistake gets a correcting entry. A log is something you write for yourself and can lose. A ledger is something another party can audit later and trust.
The Ledger
The record, read as evidence.
Which agent, model, and version made each change. Which person reviewed it. Signed, chained, anchored outside the repository, and verified offline by whoever asks.
1
What the Ledger is
A bookkeeper's word, and a promise with three parts.
The Ledger is not a second product. It is the same record the Board reads, kept in your own git, with three things the Board does not need: identity per session, a human review record per agent authored commit, and tamper evidence.
Signed
Every entry is signed by the identity that made it.
Chained
Entries are chained, so removing or altering one is detectable.
Anchored
The chain is anchored outside the repository, so the audited party cannot rewrite its own history. Without this it is a log with extra steps, and an assessor will say so.
2
What it records
Two records the Board never needed: who ran each session, and who reviewed each commit.
Per session
When a coding session starts, the hook in the agent runtime writes who directed it (the person, matched from git and the team file) and what ran it: runtime, version, model, model version, the tools it was granted, and its permission mode. Every field comes from the runtime, never typed by a person. If the runtime cannot say, the field is null and the board shows "not reported".
{
"startedAt": "2026-09-18T18:24:25.497Z",
"endedAt": null,
"agent": {
"runtime": "claude-code",
"runtimeVersion": "2.1.277",
"model": "claude-fable-5-1",
"modelVersion": null,
"tools": null,
"permissions": "default",
"policyHash": null
}
}Per commit
Each commit is attached to the session that made it, so direction is known. The Ledger adds a review record: a signed statement that a named human reviewed the commit, distinct from authoring it. It is captured where review already happens, an approved pull request, or written from the terminal with one command for teams that ship straight to main. The reviewer is never the session's director unless the team turns self review on, off by default and shown as a caveat when on.
{
"commit": "3f1c9a2e",
"reviews": [
{
"reviewer": "maya",
"reviewedAt": "2026-09-19T16:10:00.000Z",
"source": "pull_request",
"pullRequest": 42
}
]
}3
Tamper evidence
Three mechanisms, all on by default once the Ledger is enabled.
Signed commits
Every tracker commit is signed, with Sigstore by default so no key management is needed, or GPG where a team already has keys. The validator checks every tracker commit and fails the build on an unsigned one from the day signing was required.
The nightly chain
The close writes one entry per day holding the hash of every record file it wrote and the hash of the previous day's entry. One line per day, and the validator walks the whole chain.
External anchoring
The close publishes the day's chain hash to a transparency log outside the repository: Sigstore Rekor, OpenTimestamps as a second anchor, or your own endpoint. The receipt is stored beside the entry. Without one the Ledger says "not anchored" in every view and export.
{
"day": "2026-09-18",
"hash": "e8c90d286937e151125c531c6b0cd6c6ccc98e6279710c8612b6d4bdff6419a2",
"previous": null,
"anchors": [
{
"kind": "rekor",
"at": "2026-09-18T18:01:47.879Z"
},
{
"kind": "opentimestamps",
"at": "2026-09-18T18:01:49.597Z"
}
]
}4
Verify
One command replays the chain, checks every signature and every anchor, offline, and prints a verdict. An assessor runs it, not us.
$ npx @truestate/cli verify --offlineverify 2026-09-18 to 2026-09-18, 1 day, offline, zone America/New_Yorkok 2026-09-18 chain ok, 1 file intact | signed 4/14, 10 unsigned (not required then) | anchored: rekor #2886802074 (receipt present, not re fetched offline); opentimestamps proof from a.pool.opentimestamps.org (172 bytes; the Bitcoin attestation is not checked here)verdict: VERIFIED: 1 days chained, signed as required, and anchored outside the repository
Our own transcript, committed with the record on the first anchored day.
5
The control map
We say evidence for, never compliant with.
Each line names the control, what the record provides, what our own record shows right now, and the ordinary case in which the evidence is insufficient.
| Control (NIST SP 800-53 rev 5) | The Ledger provides | Our record, now | Insufficient when |
|---|---|---|---|
| AU-10 Non repudiation | signed commits bound to a person or an agent identity, reviewer identity bound separately | signing required; run truestate verify for the count per day | signing not enforced; agents share a credential |
| AU-9 Protection of audit information | chained daily hashes anchored outside the repository | 2 of 3 closed days chained, 2 anchored outside the repository | no external anchor; the anchor is run by the same people |
| AU-3 Content of audit records | actor, time, event, outcome, model, version, session, reviewer per commit | 1 of 7 sessions carry the runtime and model | fields not reported by the runtime |
| AU-2, AU-6, AU-12 Event logging, review, generation | a defined event set and a queryable record | 101 entries across 3 closed days, every one queryable | the organisation never defines events or reviews the record |
| CM-3 Configuration change control | a review decision distinct from the change, per agent authored commit | 0 of 147 commits reviewed by a named person, 0 self reviewed, 147 unreviewed | self review; no impact analysis |
| CM-5 Access restrictions for change | branch protection and the review rule recorded | the review rule is recorded; branch protection is read from the repository host in a later item | one identity can author and merge |
| SA-10 Developer configuration management | the signed record of authorised changes across the build | signing required; run truestate verify for the count per day | no CM plan; the repository itself unprotected |
| SA-11 Developer testing | test results tied to commits when captured from CI, never from the agent's own report | test results from CI are a later item; nothing self reported counts | tests are self reported |
| SR-4 Provenance | which runtime, model, and version produced each change, at a point in time | 1 of 7 sessions carry the runtime and model | fields null |
| IA-9 Service identification and authentication | a distinct identity per agent session | 1 of 7 sessions carry the runtime and model | agents share a generic credential |
| AC-6 Least privilege | the tool permissions granted per session, recorded | 1 of 7 sessions record the permission mode | recorded but not enforced (see Policy) |
Control map version 2026-09-18. The map is a file in the repository so it can be revised when NIST publishes the agent overlays, and the evidence export always ships the current version.
Where the same controls sit in other frameworks
The families above are referenced, not redefined, by the frameworks a federal or defence buyer will name. The mapping is by control family; the buyer's assessor decides sufficiency.
| Row above | CMMC 2.0 (Level 2 practices, from NIST SP 800-171 rev 2) | FedRAMP (Moderate and High baselines) |
|---|---|---|
| AU-10 | 3.3.2 Ensure actions can be traced to individual users | AU-10 in the High baseline; not selected in Moderate |
| AU-9 | 3.3.8 Protect audit information and tools from unauthorized access, modification, deletion; 3.3.9 Limit management of audit logging to privileged users | AU-9, with AU-9(2) off system backup in High |
| AU-3 | 3.3.1 Create and retain audit records with the content needed to monitor and investigate | AU-3, AU-3(1) additional content |
| AU-2, AU-6, AU-12 | 3.3.1, 3.3.3 Review and update logged events, 3.3.5 Correlate audit review | AU-2, AU-6, AU-12 |
| CM-3 | 3.4.3 Track, review, approve or disapprove, and log changes | CM-3, CM-3(2) test and validate in Moderate and High |
| CM-5 | 3.4.5 Define, document, approve, and enforce physical and logical access restrictions for change | CM-5, CM-5(1) automated access enforcement in High |
| SA-10 | not a Level 2 practice; relevant to Level 3 through 800-172 | SA-10 |
| SA-11 | not a Level 2 practice | SA-11 |
| SR-4 | not a Level 2 practice; supply chain under 800-172 | SR-4 in the High baseline |
| IA-9 | 3.5.1 Identify system users, processes acting on behalf of users, and devices | IA-9 was withdrawn into IA-3 and IA-8 in rev 5 baselines; cite the session identity under those |
| AC-6 | 3.1.5 Employ the principle of least privilege | AC-6 and its enhancements |
What the map does not claim
- No row means a control is satisfied. The third column names the ordinary case in which it is not.
- Tests are evidence only when they come from CI, never from what an agent wrote in a commit message or a session.
- A chain without an external anchor is labelled "not anchored" in every view and export; AU-9 is not met by it.
- Policy (25-the-record.md section 8) records the rules a session ran under; it is not a control plane and the map does not present it as one.
6
Evidence export
One command writes an evidence package for a period. Names become roles and hours stay out unless the exporter asks for them.
$ npx @truestate/cli export --ledger --from 2026-09-01 --to 2026-09-30truestate-export-2026-09-01-2026-09-30/
ledger.json
Sessions, agents, commits, reviewers, days, the chain, and the verdict, machine readable.
verify.txt
The verification transcript, one line per day.
control-map.md
The map at the version the export was made.
ledger.pdf
The same, for a reader.
The export never includes note screenshots, Ask threads, or emails.
7
Where it fits
Runtime observability watches agents in production. Nobody watches the agents that write the software.
The Ledger records what agents did while the software was being built, inside your boundary, and it will export sessions and commits as OpenTelemetry spans so both sit in one dashboard. In the category a reader searches for, this is the build time record for AgentOps and agentic engineering; on this site it is the Ledger.
Coming next The OpenTelemetry export.
8
Deploying it
The record lives in your git either way. The question is only what reads it and what leaves.
Hosted
The hosted board reads your repository through a GitHub App your organization installs once, with three permissions: contents read and write, issues read and write, metadata read. Accounts and an audit log live in our database; the record never does.
What leaves the boundary
One hash per day, sent to a public transparency log, and the receipt that comes back. Nothing else. An enterprise can point that anchor at its own log instead.
Self hosted and air gapped Coming next
The same app pointed at your own git host, with your own anchor, as a template.
The full boundary in plain words is on the security page.
9
Talk to us
Tell us the project and the assessment it faces. A person replies, with an evidence package for a period of your own record if you want to see one first.
Or write to hello@truestate.space. Pricing for the Ledger and Enterprise tiers is on the home page.