Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
wshobson avatar

Signed Audit Trails Recipe

  • 3.4k installs
  • 38.3k repo stars
  • Updated July 22, 2026
  • wshobson/agents

signed-audit-trails-recipe is a teaching cookbook for Cedar-gated, Ed25519-signed audit receipts on Claude Code tool calls with offline verification.

About

Signed Audit Trails is a cookbook skill for cryptographically signed receipts on every Claude Code tool call before adopting the protect-mcp runtime hooks. Each Bash, Edit, Write, or WebFetch invocation is evaluated against a Cedar policy in PreToolUse and signed as a JCS-canonical Ed25519 receipt in PostToolUse, hash-chained for tamper detection. Auditors verify offline with npx @veritasacta/verify receipts/*.json without network trust. The walkthrough covers .claude/settings.json hook wiring, sample protect.cedar rules that forbid destructive Bash while permitting safe git and npm patterns, receipt field anatomy, tamper demos, and GitHub Actions jobs that gate merges on intact chains. Cryptography invariants follow RFC 8785 JCS canonicalization and RFC 8032 Ed25519 with parent_receipt_hash linkage. The skill documents SLSA provenance composition via agent-commit byproducts, cross-implementation interop with protect-mcp, protect-mcp-adk, and sb-runtime, and pitfalls around private key commits, hook quoting, and missing policy flags in production.

  • PreToolUse Cedar evaluation and PostToolUse Ed25519 receipt signing on every Claude Code tool call.
  • JCS-canonical hash-chained receipts verifiable offline via npx @veritasacta/verify without vendor trust.
  • Sample protect.cedar permits safe Bash patterns while forbid rules block rm -rf and similar destructive commands.
  • GitHub Actions workflow gates merges on receipt chain verification and uploads artifacts for audit retention.
  • Documents SLSA agent-commit byproduct composition and cross-implementation interop across four runtimes.

Signed Audit Trails Recipe by the numbers

  • 3,432 all-time installs (skills.sh)
  • +151 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #177 of 2,209 Security skills by installs in the Skillselion catalog
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

signed-audit-trails-recipe capabilities & compatibility

Capabilities
pretooluse cedar policy evaluation before tool e · posttooluse ed25519 jcs canonical receipt signin · offline receipt chain verification via @veritasa · github actions ci gating and artifact archival f · slsa provenance byproduct composition guidance f
Works with
github · jenkins
Use cases
security audit · ci cd
From the docs

What signed-audit-trails-recipe says it does

Receipts are JCS-canonical, hash-chained, and verifiable offline by anyone with the public key
SKILL.md
npx skills add https://github.com/wshobson/agents --skill signed-audit-trails-recipe

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs3.4k
repo stars38.3k
Security audit2 / 3 scanners passed
Last updatedJuly 22, 2026
Repositorywshobson/agents

How do I prove every agent tool call was policy-checked and tamper-evidently logged for regulators, CI pipelines, or untrusted counterparties?

Set up Cedar-gated, Ed25519-signed audit receipts for Claude Code tool calls with offline chain verification and CI/CD gates.

Who is it for?

Teams in regulated or multi-party environments who need cryptographically verifiable agent behavior evidence before installing protect-mcp in production.

Skip if: Skip when you only need runtime hook installation without the teaching walkthrough, or when standard unstructured logs suffice.

When should I use this skill?

User asks about signed audit trails, Cedar policy hooks, Ed25519 receipts, protect-mcp evaluation, or SLSA agent provenance composition.

What you get

Working PreToolUse and PostToolUse hooks, protect.cedar policy, hash-chained receipts, and passing @veritasacta/verify chain checks in local or CI runs.

  • protect.cedar policy file
  • signed receipt JSON chain
  • CI verification workflow YAML

By the numbers

  • Covers six implementation areas: Cedar policy, Ed25519 receipts, offline verification, tamper detection, CI/CD, and SLSA

Files

SKILL.mdMarkdownGitHub ↗

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:

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:

{
  "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:

echo "./protect-mcp.key" >> .gitignore
echo "./receipts/" >> .gitignore

Step 2: Write a Cedar policy

Create ./protect.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 precedence over permit rules, so destructive commands cannot be bypassed by a later permissive rule.

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 produces 20 receipts, each hash-chained to its predecessor.

Step 4: Inspect a receipt

cat ./receipts/$(ls -t ./receipts/ | head -1)
{
  "receipt_id": "rcpt-a8f3c9d2",
  "receipt_version": "1.0",
  "issuer_id": "claude-code-protect-mcp",
  "event_time": "2026-04-17T12:34:56.123Z",
  "tool_name": "Read",
  "input_hash": "sha256:a3f8c9d2e1b7465f...",
  "decision": "allow",
  "policy_id": "protect.cedar",
  "policy_digest": "sha256:b7e2f4a6c8d0e1f3...",
  "parent_receipt_id": "rcpt-3d1ab7c2",
  "public_key": "4437ca56815c0516...",
  "signature": "4cde814b7889e987..."
}

Every field except signature and public_key is covered by the Ed25519 signature. Modifying any field after signing invalidates the signature.

Step 5: Verify the receipt chain

npx @veritasacta/verify ./receipts/*.json

Exit codes:

CodeMeaning
0All receipts verified; chain intact
1A receipt failed signature verification (tampered, or wrong key)
2A receipt was malformed

Step 6: Demonstrate tamper detection

Modify any receipt's decision field from allow to deny:

python3 -c "
import json, os
path = './receipts/' + sorted(os.listdir('./receipts'))[-1]
r = json.loads(open(path).read())
r['decision'] = 'deny'
open(path, 'w').write(json.dumps(r))
"

npx @veritasacta/verify ./receipts/*.json

The verifier exits with code 1 and reports which receipt 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

Three invariants make receipts verifiable offline across any conformant implementation:

1. JCS canonicalization (RFC 8785) before signing. Keys sorted, whitespace minimized, strings NFC-normalized. Two independent implementations produce byte-identical signing payloads for the same receipt content. 2. Ed25519 signatures (RFC 8032) over the canonical bytes. Deterministic, fixed-size, no nonce dependency. 3. Hash chain linkage. Each receipt's parent_receipt_hash is the SHA-256 of the predecessor's canonical form. Insertions, deletions, and reorderings break later receipts.

For the formal wire format see draft-farley-acta-signed-receipts.

Cross-implementation interop

The receipt format has four independent implementations today:

ImplementationLanguageUse case
protect-mcpTypeScriptClaude Code, Cursor, MCP hosts
protect-mcp-adkPythonGoogle Agent Development Kit
sb-runtimeRustOS-level sandbox (Landlock + seccomp)
APS governance hookPythonCrewAI, 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

Gate merges on receipt chain verification so no build lands with a broken evidence chain:

# .github/workflows/verify-receipts.yml
name: Verify Decision Receipts
on: [push, pull_request]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - name: Run governed agent
        run: python scripts/run_agent.py > receipts.jsonl
      - name: Verify receipt chain
        run: npx @veritasacta/verify receipts.jsonl

Archive the receipts as an artifact so the chain survives beyond the job run:

      - name: Upload receipts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: decision-receipts
          path: receipts/

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 immediately (delete the key file and let the hook regenerate on next run).

Hook command quoting. The hooks receive $TOOL_NAME and $TOOL_INPUT as environment variables. Keep the quoting "$TOOL_INPUT" so inputs with spaces or special characters pass through intact.

Receipts directory in CI. If Claude Code runs in CI, upload receipts as an artifact at the end of the job or the chain is lost at job end.

Policy is missing. The example PreToolUse hook uses --fail-on-missing-policy false so an absent ./protect.cedar does not break Claude Code out of the box. Remove this flag in production so a missing policy is treated as a hard failure.

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

Related skills

How it compares

Teaching cookbook before production protect-mcp plugin; pairs with review-agent-governance for human approval gates.

FAQ

How are receipts verified offline?

Run npx @veritasacta/verify on receipt JSON files; exit code 0 means all signatures and hash chain links are intact.

What happens if a receipt is tampered after signing?

Modifying any signed field invalidates the Ed25519 signature and the verifier exits with code 1 reporting the failed receipt.

Should the private key be committed?

No. protect-mcp.key must stay out of version control; only the public key fingerprint from receipts should be shared.

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.

Securityauditcomplianceappsec

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.