Signed evidence packs: proving how AI-written code shipped
Matt · · Last updated · 5 min read · Product
What goes into an AI CodeOps evidence pack, why we sign it with Ed25519 over canonical JSON, and how an auditor can verify one offline without trusting us.
Sooner or later someone asks a team that uses AI to write code a fair question: how did this change get to production? Who asked for it, which model wrote it, who looked at it, what was tested, and what was approved?
The answers already live in AI CodeOps. The session, the review findings, the test runs, the approvals and the audit log are all there. But "log in to our tool and click around" is not an answer an auditor can keep, and a screenshot proves nothing. So today we are shipping evidence packs: one signed file per change that holds the answers and can be checked by anyone, without an account and without trusting us.
What a pack contains
Open Changes, pick a change, and select Download evidence pack. You get a JSON file with:
- The task. The prompt given to the AI, the model, provider and tier, and the context files.
- The runs. The session and every follow-up run, with status, timings, tokens and cost, plus the provider and model of each agent step.
- The result. The summary, the list of changed files, and a SHA-256 hash of the diff.
- Approvals. Each approval request, who could approve it, and every vote with its time and note.
- Policy decisions. Each allow, deny or ask that the workspace's policies made during the change.
- Findings and tests. Review findings with how they were triaged, and test results: passed, failed, skipped and coverage.
- Delivery. The pull request, the deployment, and any incident linked to the change.
- The audit trail. The audit log entries about any of the above.
- People. The email address behind every account ID in the pack, so the file reads on its own.
The code itself is not in the pack. That was a deliberate choice. Source code is often the most sensitive thing a company owns, and an evidence file tends to get emailed around. The diff hash gives you the link instead: hash the diff of the pull request, and if it matches, the pack describes exactly that code.
Downloading a pack needs audit access in the workspace. Owners, admins and security admins have it. Every download is itself recorded in the audit log, so you can see who exported what. The evidence packs guide covers the details.
Why sign it
A JSON file is easy to edit. If a pack could be changed after download, it would be worth no more than a spreadsheet someone typed up. The signature is what turns it into evidence.
Each pack has three parts: a format string, the payload with everything above, and a signature. The signature is Ed25519 (RFC 8032) over the payload. We picked Ed25519 because it is small, fast, has no parameters to get wrong, and is built into the standard libraries most people already have, including Node.js's module, Go, Python's cryptography package and OpenSSL. You should not need our code to check our claims.
Canonical JSON
There is one trap with signing JSON. The same data can be written many ways: keys in a different order, extra spaces, a line break. If you sign the exact bytes we sent, a harmless re-save by a text editor or a JSON tool breaks the signature, and you can't tell a re-format from a forgery.
So we sign the canonical form of the payload instead: object keys sorted at every level, and no whitespace. Whoever re-serializes the pack, the canonical bytes are the same, and the signature still checks. The canonical function is about ten lines:
const canonical = (v) =>
v === null || typeof v !== "object"
? JSON.stringify(v)
: Array.isArray(v)
? `[${v.map(canonical).join(",")}]`
: `{${Object.keys(v)
.sort()
.map((k) => `${JSON.stringify(k)}:${canonical(v[k])}`)
.join(",")}}`
Verifying a pack
There are two ways.
In the browser. Open /evidence/verify and choose the file. No account is needed. It tells you whether the signature is valid, which key signed it, which change it is about and when it was made.
Offline. This is the one that matters for an audit, because it doesn't ask you to trust our verifier. Our public keys are published at /api/evidence?action=keys. Save them once, then run a short Node.js script, which is in the guide, against the pack. It canonicalizes the payload, finds the key the pack names, and checks the signature with node:crypto. If anyone changed a single character in the payload, it prints "NOT VERIFIED".
We also run that exact script from the guide in our own tests, against a real signed pack. If the code and the documentation ever disagree, our tests fail, not your audit.
Keys and how long packs stay valid
Each pack names the key that signed it with a key ID: the first 16 hex characters of the SHA-256 of the public key. The private key is generated on first use and stored encrypted.
Keys are never deleted. When a key is retired, it stops signing new packs, but its public half stays published, so every pack it signed still verifies. A pack you download today should still check out years from now.
What a pack does not prove
It is worth being precise. A pack proves that AI CodeOps recorded these facts about this change, and that nobody has altered them since. It does not prove the code is correct, and it does not prove anything about steps that happened outside the platform, such as a commit someone pushed directly to the branch. The diff hash is how you check that the code in the pull request is the code the pack describes.
Within those limits, it gives an auditor something they rarely get with AI-written code: one file, per change, that shows the whole path from prompt to production and can be checked independently. If you work in a regulated industry, the regulated teams page shows how packs fit with the rest of the controls, the audit and RBAC page covers the audit log they draw from, and human approvals for AI changes explains the approvals a pack records.
Key takeaways
- An evidence pack is one JSON file per change: the task, runs, approvals, policy decisions, findings, tests, delivery and audit trail.
- The code isn't in the pack; a SHA-256 hash of the diff ties the pack to the exact pull request.
- It is signed with Ed25519 over canonical JSON, so a re-format doesn't break it and any edit does.
- Anyone can verify it in the browser at /evidence/verify or offline with a short Node.js script and our published keys.
- It proves what AI CodeOps recorded and that nobody changed it since, not that the code is correct.