ledger
Observability tools show you what your agent did. ledger lets you prove it.
Every record is hash-chained to the one before it. Edit a row, delete one, or
reorder history, and every later link breaks — verify names the exact line.
You own the record, and you can prove it wasn't altered. Zero dependencies, one
JSONL file, two verbs.
from ledger import Ledger
log = Ledger("agent.log.jsonl")
log.append({"tool": "web.search", "query": "weather in LA", "result_ok": True})
log.append({"tool": "payment", "amount": "49.00", "currency": "USD"})
log.verify() # VerifyResult(ok=True, rows=2, chained=2, ...)
Tampering is caught, not hoped against:
# someone edits row 1's amount in the file by hand...
log.verify() # VerifyResult(ok=False, first_break="line 1: chain mismatch")
CLI (wire it into CI or a pre-ship gate — a tampered log exits nonzero):
python -m ledger.cli append agent.log.jsonl '{"tool":"search","ok":true}'
python -m ledger.cli verify agent.log.jsonl # exit 0 = intact, 1 = broken
Prove who acted, not just the order
A hash chain proves sequence integrity — it can't prove who wrote each entry or
whether they were allowed to. Attach an authority block to bind the actor and
their permission surface into the chained (tamper-evident) row:
from ledger import Ledger, authority
log = Ledger("agent.log.jsonl")
log.append(
{"tool": "payment", "amount": "49.00"},
authority=authority(
"agent://billing-7",
capability_version="v3", # what they were allowed to do
tool_schema={"name": "payment", "args": ["amount"]}, # hashed, not just named
time_source="ntp", # trust surface of the clock
),
)
Now the audit question sharpens from "was this edited?" to "was this edited and was the writer authorized?" — editing the principal, capability, or schema hash breaks the chain like any other tamper. This composes tamper-evidence with permission-replay. (Shipped in response to community feedback on launch.)
Why this exists
The loudest unmet pain for agent builders in 2026 is the reliability/audit gap:
an agent "completes" a task and the result is quietly wrong, and you can't
reconstruct — or prove — what actually happened. Observability platforms trace
runs; none give you a tamper-evident, portable, ownable record. Regulations
(EU AI Act Art. 12, tamper-evident AI decision records) are starting to require
exactly this. ledger is the smallest honest version: a cryptographically
chained action log you drop in, own, and verify.
How the chain works
chain = sha256(prev_chain + canonical_json(row_without_chain))[:32]
Each row commits to the entire history before it. The first row chains from a
fixed "genesis" seed. Rows without a chain field are tolerated only before
the first chained row (so you can adopt it on an existing log); an unchained row
appearing after the chain begins is itself flagged. On a mismatch, verify
keeps going from the claimed value so it counts later damage honestly instead of
cascading one break into noise.
The honest limit: ledger proves a file wasn't altered after writing. It does
not prove the writer was honest at write time, and it does not by itself defend
against someone who rewrites the whole chain from a chosen point forward — for
that you periodically anchor the latest chain value somewhere you don't control
(a commit, a timestamp service, a witness). That anchoring is on the roadmap;
the core tamper-evidence is here and tested.
Drop it into any MCP agent
ledger ships a zero-dependency MCP server, so any MCP client (Claude Code,
etc.) can give its agent tamper-evident logging with no code. Wire it in:
{
"mcpServers": {
"ledger": {
"command": "python",
"args": ["-m", "ledger.mcp_server", "--log", "agent.log.jsonl"]
}
}
}
The agent then has two tools: ledger_append(record) to log an action
(returns its chain hash) and ledger_verify() to prove the whole log is
intact (or get the exact tampered line back). MCP is JSON-RPC over stdio and
this server speaks it directly — no SDK, no extra install.
Status
Core library, CLI, and a drop-in MCP server, all tested: the library
against edit / delete / reorder tampering (test_ledger.py), the MCP server
through a full initialize → tools/list → append → verify handshake including
tamper detection over the wire. Extracted from a hash-chained action ledger
running in production. A hosted collection tier (retention + compliance export)
and periodic external anchoring are the next layers.
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file arcaeon_ledger-0.2.0.tar.gz.
File metadata
- Download URL: arcaeon_ledger-0.2.0.tar.gz
- Upload date:
- Size: 9.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e4393d1e2c56960127c67edb857ebe67eee238e7975929a54a86c65db5fe54e
|
|
| MD5 |
2a4c55998fee1da698721952d7a88b11
|
|
| BLAKE2b-256 |
a2bad5ac3e649e845d62f5c8b19978daae73328af8723ed28c5db23bff603af0
|
File details
Details for the file arcaeon_ledger-0.2.0-py3-none-any.whl.
File metadata
- Download URL: arcaeon_ledger-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c7c8938fce282626192293cf4240768afe345ff3275adaf351e7ad134d406b3
|
|
| MD5 |
acbe9b2beecf2952f702108eebfe979d
|
|
| BLAKE2b-256 |
3f3c2ffec461dddff5c9406ad93047d6113210eb79ab94ee141bea50fcfe4915
|