Signed Audit Trails Recipe
Seth HobsonCommunityCreated by Tom FarleyDistributed by Seth Hobson
- Skill
- Guidelines
- Security
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive guide to implementing cryptographically signed audit trails for Claude Code tool calls. By integrating Cedar policies for pre-execution evaluation and Ed25519 signatures for post-execution receipts, it enables offline, tamper-evident verification of agent behavior. This pattern is designed for regulated environments, CI/CD pipelines, and multi-party collaborations where verifiable evidence of agent actions is required without relying on vendor trust.
What it does
- Configures runtime hooks to intercept and evaluate tool calls against Cedar policies.
- Generates cryptographically signed Ed25519 receipts for every tool execution.
- Provides a mechanism for offline verification of receipt chains using public keys.
- Demonstrates tamper detection by validating signature integrity against receipt payloads.
- Integrates with CI/CD pipelines to enforce policy gates and verify agent behavior automatically.
- Supports composition with SLSA provenance for agent-built software.
When to use it
- In regulated industries like finance or healthcare requiring tamper-evident logs.
- When you need to prove that specific policy gates were applied during automated build steps.
- For multi-party scenarios where counterparties must verify agent actions independently.
- To meet compliance requirements such as the EU AI Act or SLSA provenance standards.
Advantages
- Enables offline verification without network calls or vendor lookups.
- Provides strong, tamper-evident proof of agent behavior.
- Uses standardized JCS canonicalization and Ed25519 signatures for interoperability.
- Supports granular policy enforcement via Cedar.
- Facilitates secure integration into automated CI/CD workflows.
Usage examples
- “How do I set up signed audit trails for my Claude Code agent?”
- The agent provides the step-by-step installation guide, including key generation, hook configuration, and policy creation.
- “How can I verify that my agent's tool call logs haven't been tampered with?”
- The agent explains how to use the verification tool with your public key to check the integrity of the receipts.jsonl file.
- “Can I integrate these audit trails into my GitHub Actions pipeline?”
- The agent provides a YAML configuration example for a CI/CD job that runs the agent, verifies the receipts, and uploads them as artifacts.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/wshobson/signed-audit-trails-recipe/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip signed-audit-trails-recipe.zip -d .agents/skills
Documentation by Tom Farley
Signed Audit Trails for Claude Code Tool Calls
Cookbook-style walkthrough for cryptographically signed receipts on every
Claude Code tool call. This is the teaching skill. For the runtime
implementation, install the protect-mcp plugin.
What this gives you
Every tool call (Bash, Edit, Write, WebFetch) is:
Evaluated against a Cedar policy before execution. If the policy denies the call, the tool does not run.
Signed as an Ed25519 receipt after execution. Receipts are JCS-canonical and verifiable offline by anyone with the public key.
An auditor, regulator, or counterparty can verify every receipt later (Step 5). No network call, no vendor lookup, no trust in the operator.
When to use the pattern
Regulated environments (finance, healthcare, critical infrastructure) where you need tamper-evident evidence of agent behavior
CI/CD pipelines where you want to prove that a policy gate held for every automated build step
Multi-party collaboration where a counterparty wants to verify your agent's behavior without trusting your operator
Compliance contexts (EU AI Act Article 12, SLSA provenance for agent-built software) where standard logging is not sufficient
Step 1: Install the hook configuration
Install the protect-mcp plugin with /plugin install protect-mcp. Its hooks
run evaluate.sh before each tool call and sign.sh after it. Both scripts
read the hook event from stdin, because Claude Code sets no TOOL_NAME or
TOOL_INPUT variables. See
references/hook-wiring.md for the hook
configuration and what each script passes to protect-mcp.
protect-mcp 0.7.4 does not create the signing key, and without a key the
receipts are unsigned. Create ./protect-mcp.key once. The command never
replaces an existing key:
if [ ! -e ./protect-mcp.key ]; then
d=$(mktemp -d) && npx [email protected] init --dir "$d" && mv "$d/keys/gateway.json" ./protect-mcp.key
fi
chmod 600 ./protect-mcp.keyGive auditors the publicKey value from that file. Do not commit the file,
because it also holds the private key.
Add the private key and receipt directory to .gitignore:
echo "/protect-mcp.key" >> .gitignore
echo "/receipts/" >> .gitignoreStep 2: Write a Cedar policy
Create ./protect.cedar from the example in
references/cedar-policy.md. It allows read-only
tools and a short list of Bash commands, denies shell chaining and destructive
commands, and limits writes to the project with .. segments denied.
Step 3: Use Claude Code normally
Start Claude Code. Every tool call goes through both hooks:
You: Please read the README and summarize it.
Claude: I will read README.md.
[PreToolUse: Read ./README.md -> allow]
[Tool: Read executes]
[PostToolUse: receipt rcpt-a8f3c9d2 signed to ./receipts/]
... summary of README ...A session of 20 tool calls appends 20 receipts to ./receipts/receipts.jsonl.
Step 4: Inspect a receipt
protect-mcp 0.7.4 appends each receipt as one line of
./receipts/receipts.jsonl. Print the newest one:
tail -n 1 ./receipts/receipts.jsonl | python3 -m json.toolThe receipt is a signed v2 envelope that names the tool, and it holds no
public key. See references/receipt-format.md
for a sample and the signed fields.
Step 5: Verify the receipts
Pass the publicKey value from ./protect-mcp.key to the verifier:
PUB=$(node -p 'JSON.parse(require("fs").readFileSync("./protect-mcp.key")).publicKey')
npx @veritasacta/[email protected] --replay-chain ./receipts/receipts.jsonl --key "$PUB"Exit codes:
| Code | Meaning |
|---|---|
0 | Every receipt verified |
1 | A receipt failed verification (tampered, wrong key, or malformed line) |
2 | The receipts file could not be read |
Step 6: Demonstrate tamper detection
Change the newest receipt's decision from allow to deny:
python3 -c "
import json
path = './receipts/receipts.jsonl'
lines = open(path).read().splitlines()
r = json.loads(lines[-1])
r['payload']['decision'] = 'deny'
lines[-1] = json.dumps(r)
open(path, 'w').write('\n'.join(lines) + '\n')
"
npx @veritasacta/[email protected] --replay-chain ./receipts/receipts.jsonl --key "$PUB"The verifier exits with code 1 and reports which line failed. The
Ed25519 signature no longer matches the JCS-canonical bytes of the
tampered payload.
Restore the field and verification passes again.
How the cryptography works
Two invariants make receipts verifiable offline across any conformant implementation:
JCS canonicalization (RFC 8785) before signing. Keys sorted by UTF-16 code units, whitespace minimized, strings not normalized. Two independent implementations produce byte-identical signing payloads for the same receipt content.
Ed25519 signatures (RFC 8032) over the canonical bytes. Deterministic, fixed-size, no nonce dependency.
protect-mcp 0.7.4 receipts carry no link to the previous receipt, so a deleted receipt goes undetected.
For the formal wire format see draft-farley-acta-signed-receipts.
Cross-implementation interop
The receipt format has four independent implementations today:
| Implementation | Language | Use case |
|---|---|---|
| protect-mcp | TypeScript | Claude Code, Cursor, MCP hosts |
| protect-mcp-adk | Python | Google Agent Development Kit |
| sb-runtime | Rust | OS-level sandbox (Landlock + seccomp) |
| APS governance hook | Python | CrewAI, LangChain |
A receipt produced by any of them verifies against
@veritasacta/verify.
The auditor does not need to trust the operator's tooling choice: the format
is the contract.
CI/CD integration
Verify receipts in CI so a tampered receipt fails the build.
references/ci-cd.md has a GitHub Actions workflow
that runs on pushes to the default branch. It installs the signing key from a
branch-limited environment, runs the agent, verifies the receipts, and uploads
them. It does not run on pull requests, because that would hand the key to
unreviewed code.
Composition with SLSA provenance for agent-built software
When Claude Code builds and releases software (running npm install,
npm build, npm publish as tool calls), the receipt chain is the
per-step build log. SLSA Provenance v1 has an extension point for this: the
byproducts field can reference the receipt chain alongside the build
attestation.
The agent-commit build type documents the pattern using the ResourceDescriptor shape:
{
"name": "decision-receipts",
"digest": { "sha256": "..." },
"uri": "oci://registry/org/build-xyz/receipts:sha256-...",
"annotations": {
"predicateType": "https://veritasacta.com/attestation/decision-receipt/v0.1",
"signerRole": "supervisor-hook"
}
}The SLSA provenance is signed by the builder identity; the receipt attestation is signed by the supervisor-hook identity. Two trust domains, cross-referenced at the byproduct layer. See slsa-framework/slsa#1594 for the composition discussion.
Common pitfalls
Private key in version control. The generated ./protect-mcp.key must
not be committed. The examples above add it to .gitignore. If a key is
accidentally committed, rotate it immediately. Move the key and
./receipts/receipts.jsonl to an archive, then run the Step 1 command again.
Verify the archived receipts with the old public key.
Hook payload on stdin. Claude Code sets no $TOOL_NAME or $TOOL_INPUT
variables. A hook command that passes --tool "$TOOL_NAME" sends an empty
tool name, so the policy denies every call. Read the payload from stdin as the
plugin scripts do.
Receipts directory in CI. If Claude Code runs in CI, upload receipts as an artifact at the end of the job or the receipts are lost at job end.
Policy is missing. When ./protect.cedar does not exist, evaluate.sh
prints a warning to stderr and allows the call. No call is gated until you
create the policy in Step 2.
Related in this marketplace
protect-mcp— the runtime hook implementation (use this plugin in production)review-agent-governance— require human approval before review-surface actions; composes with protect-mcp
References
draft-farley-acta-signed-receipts— IETF draft, receipt wire formatRFC 8032 — Ed25519
RFC 8785 — JCS
in-toto/attestation#549 — Decision Receipt predicate proposal
agent-commit build type — SLSA provenance for agent-produced commits
Microsoft Agent Governance Toolkit (
examples/protect-mcp-governed/)
Files
- ATTRIBUTION.mdAdded by AutoGineer1015 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md9.9 KiB
- references/cedar-policy.md3.9 KiB
- references/ci-cd.md2.1 KiB
- references/hook-wiring.md1.3 KiB
- references/receipt-format.md1.2 KiB
Requirements and compatibility
Written for: Claude Code
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Names Claude Code tools, Needs Python, Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Tom Farley
- Publisher
- Seth Hobson (Community)
- Distributed by
- Seth Hobson
- Source
- wshobson/agents · plugins/signed-audit-trails/skills/signed-audit-trails-recipe · commit 4bde316
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Tom Farley or Seth Hobson.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download signed-audit-trails-recipe.zip