
Signed Audit Trails Recipe
Learn how to gate Claude Code tool calls with Cedar policies and Ed25519 signed receipts before adopting the protect-mcp runtime.
Install
npx skills add https://github.com/wshobson/agents --skill signed-audit-trails-recipeWhat is this skill?
- Pre-execution Cedar policy evaluation; denied tool calls never run
- Post-execution Ed25519 receipts: JCS-canonical, hash-chained, offline verifiable
- Offline verification via `npx @veritasacta/verify receipts/*.json` without vendor trust
- CI/CD and SLSA-style composition guidance for automated build steps
- Teaching cookbook that precedes the protect-mcp plugin runtime implementation
Adoption & trust: 2.1k installs on skills.sh; 36.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Azure Compliancemicrosoft/azure-skills
Openclaw Secure Linux Cloudxixu-me/skills
Entra Agent Idmicrosoft/azure-skills
Firebase Security Rules Auditorfirebase/agent-skills
Firestore Security Rules Auditorfirebase/agent-skills
Skill Vetteruseai-pro/openclaw-skills-security
Journey fit
Common Questions / FAQ
Is Signed Audit Trails Recipe safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Signed Audit Trails Recipe
# 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`](../../protect-mcp/) plugin. ## What this gives you Every tool call (`Bash`, `Edit`, `Write`, `WebFetch`) is: 1. **Evaluated against a Cedar policy** before execution. If the policy denies the call, the tool does not run. 2. **Signed as an Ed25519 receipt** after execution. Receipts are JCS-canonical, hash-chained, and verifiable offline by anyone with the public key. An auditor, regulator, or counterparty can verify the full chain later with a single CLI command (`npx @veritasacta/verify receipts/*.json`). 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 Create `.claude/settings.json` in your project root: ```json { "hooks": { "PreToolUse": [ { "matcher": ".*", "hook": { "type": "command", "command": "npx protect-mcp@latest evaluate --policy ./protect.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" } } ], "PostToolUse": [ { "matcher": ".*", "hook": { "type": "command", "command": "npx protect-mcp@latest sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts ./receipts/ --key ./protect-mcp.key" } } ] } } ``` The first run of `protect-mcp sign` generates `./protect-mcp.key` (Ed25519 private key) if one does not exist. Commit the **public** key fingerprint (visible in any receipt's `public_key` field); do not commit the private key. Add the private key and receipt directory to `.gitignore`: ```bash echo "./protect-mcp.key" >> .gitignore echo "./receipts/" >> .gitignore ``` ## Step 2: Write a Cedar policy Create `./protect.cedar`: ```cedar // Allow all read-oriented tools by default. permit ( principal, action in [Action::"Read", Action::"Glob", Action::"Grep", Action::"WebSearch"], resource ); // Allow Bash commands from a safe list only. permit ( principal, action == Action::"Bash", resource ) when { context.command_pattern in [ "git", "npm", "pnpm", "yarn", "ls", "cat", "pwd", "echo", "test", "node", "python", "make" ] }; // Explicit deny on destructive commands. Cedar deny is authoritative. forbid ( principal, action == Action::"Bash", resource ) when { context.command_pattern in ["rm -rf", "dd", "mkfs", "shred"] }; // Restrict writes to the project directory. permit ( principal, action in [Action::"Write", Action::"Edit"], resource ) when { context.path_starts_with == "./" }; ``` Four rules: - Read-oriented tools always allowed - `Bash` allowed for safe command patterns (`git`, `npm`, etc.) - `Bash rm -rf` and similar destructive commands explicitly denied - Writes allowed only within the project (`./` prefix) Cedar `forbid` rules take prece