Audit chain
A tamper-evident log of every decision, verifiable in the inbox and offline.
Every decision, approval, policy change and team change is appended to one hash chain in Postgres. Each entry’s hash covers every column of the entry plus the previous entry’s hash:
hash(n) = base64url(sha256(hash(n-1) + "|" + canonicalJson(entry n)))
hash(0) = "GENESIS"Editing, deleting or reordering an entry in the middle breaks every hash after it.
Browsing
Section titled “Browsing”- Activity lists every decision. Filter by agent, person, tool, verdict or rule, and open a run to see its plan, policy version and each call’s outcome.
- Audit verifies the chain on the server and lists flagged entries.
Members see only their own runs.
Verifying offline
Section titled “Verifying offline”An admin can export the whole chain and verify it with the CLI, using the same hashing code as the server:
curl -b cookies.txt -o audit.jsonl \
"https://intentlock.acme.dev/api/v1/audit?format=jsonl"
intentlock audit verify --file audit.jsonlThe result is either ok with a count, or the first broken sequence number and why. A member’s export holds only their own entries, which is not a complete chain.
The chain detects edits, deletions in the middle and reordering. Deleting the newest entries is not detectable from the chain alone; keep regular exports if that matters to you.
Decisions made in your app
Section titled “Decisions made in your app”In hybrid mode the client decides locally and writes every decision to an outbox file, chained with its own hashes, before the tool runs. A background worker uploads batches to the server, which appends them to the same chain. On upload the server:
- checks the client chain, and flags edited entries (
chain_break) and missing ones (gap); - re-runs
check()for each decision with its own signed token, and flags any decision looser than the policy (decision_mismatch); - compares the decision count in each report with what it received, and flags a truncated tail (
truncated).
Flagged entries are stored, never dropped, and shown in the inbox.