Skip to content

docs(blog): Native Tool Calls in the Audit Trail#444

Draft
ojongerius wants to merge 9 commits into
mainfrom
worktree-blog+hooks-native-tool-audit
Draft

docs(blog): Native Tool Calls in the Audit Trail#444
ojongerius wants to merge 9 commits into
mainfrom
worktree-blog+hooks-native-tool-audit

Conversation

@ojongerius
Copy link
Copy Markdown
Contributor

Stub for the third post in the series. Outline is in the file as comments.

Publishing order:

  1. docs(blog): Why Your Agent Can't Audit Itself #443 — Daemon re-architecture ("Why Your Agent Can't Audit Itself")
  2. docs(blog): One Chain, Two Channels, Zero Secrets #442 — Disclosure + redaction ("One Chain, Two Channels, Zero Secrets")
  3. This — Hooks ("Native Tool Calls in the Audit Trail")

Content to write: the gap MCP proxy leaves (native tools invisible), how the hook fills it, installation (one settings.json change), real Bash receipt, PostToolUse-only today with PreToolUse on the roadmap.

@ojongerius ojongerius changed the title docs(blog): Native Tool Calls in the Audit Trail [stub] docs(blog): Native Tool Calls in the Audit Trail May 17, 2026
@ojongerius ojongerius requested a review from Copilot May 17, 2026 01:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new blog post draft explaining how the Claude Code PostToolUse hook (agent-receipts-hook) captures native tool calls (Bash/Read/Write/Edit/etc.) and forwards them to agent-receipts-daemon, complementing MCP proxy coverage.

Changes:

  • Add new blog post: “Native Tool Calls in the Audit Trail”.
  • Add the post to the site’s Blog sidebar navigation.
  • Add a 0.10.0 section to the daemon changelog.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
site/src/content/docs/blog/hooks-native-tool-audit.mdx New blog post describing the Claude Code hook approach and showing example receipts.
site/astro.config.mjs Adds the new blog post to the Blog sidebar items.
daemon/CHANGELOG.md Adds a 0.10.0 changelog entry describing recent daemon changes.
Comments suppressed due to low confidence (2)

site/src/content/docs/blog/hooks-native-tool-audit.mdx:126

  • The JSON example is presented as a “real Bash receipt”, but its shape doesn’t match the repository’s documented receipt schema (e.g., other docs/spec show issuer + credentialSubject.{action,outcome,chain} with chain.previous_receipt_hash). As written, this looks like a partial/extracted view but it isn’t labeled as such. Consider either showing a full receipt matching the schema, or explicitly labeling this as an excerpt and keeping field names/locations consistent with the spec to avoid confusing readers/copy-pasting.
---

## What a native tool receipt looks like

Here's a real `Bash` receipt from a Claude Code session, captured while running a shell command that included a fake API key:

```json
{
  "action": {
    "type": "claude-code.Bash",
    "tool_name": "Bash",
    "risk_level": "medium",
    "parameters_hash": "sha256:dc143db4ad2fd5df10685749c688e018610dfb254bd75bbf753ed3ddd84d97a2",
    "parameters_disclosure": {
      "input": "{\"command\":\"echo \\\"Connecting with api_key=[REDACTED] to service\\\"\"}",
      "output": "{\"stdout\":\"Connecting with api_key=[REDACTED] to service\",\"stderr\":\"\"}",
      "peer.platform": "darwin",
      "peer.uid": "501",
      "peer.pid": "74389"
    }
  },
  "outcome": { "status": "success" },
  "chain": {

site/src/content/docs/blog/hooks-native-tool-audit.mdx:160

  • This section states the hook “exits non-zero” when the daemon is unreachable. Elsewhere in the docs the hook is described as “always exits 0” (e.g., site/src/content/docs/reference/cli-commands.mdx under agent-receipts-hook). Please align the documentation (either update the other page(s) or add a version/behavior note here) so readers don’t get conflicting guidance about failure behavior.
</Aside>

---

## Fail-hard, not silent

Comment on lines +1 to +12
---
title: "Native Tool Calls in the Audit Trail"
description: "How the Claude Code hook captures Bash, Read, Write, Edit and other native tools — closing the gap the MCP proxy leaves open."
---

import { Aside } from '@astrojs/starlight/components';

**Series: Auditing AI Agents** · Part 3 of 3 · [← One Chain, Two Channels, Zero Secrets](/blog/unified-chain-redaction-demo/)

---

The MCP proxy covers MCP tool calls. Everything that flows through an MCP server — GitHub API calls, database queries, Atlassian writes — is intercepted, receipted, and hash-chained. But Claude Code has another class of tools that never touch an MCP server at all.
Comment thread daemon/CHANGELOG.md
Comment on lines +46 to +47
- Bump `github.com/agent-receipts/ar/sdk/go` to `v0.9.1`
(DESC ordering and no silent 10k row cap in `QueryReceipts`).
Comment on lines +102 to +103
That's it. No MCP server to wrap, no proxy config to write. The next tool call you make will land a receipt.

@ojongerius ojongerius force-pushed the worktree-blog+hooks-native-tool-audit branch from 45691a1 to 9d78b89 Compare May 17, 2026 08:15
Two edits to align with the series register:

- Add publish date (2026-05-28, one week after post 2 per the weekly
  cadence).
- Soften the closing — "an agent that could previously obscure its
  activity" framed the agent as adversarial in the same shape as the
  "compromised or misbehaving agent" line we flattened in post 1.
  Replace with a structural-completeness framing: what's missing
  without the hook (file writes, shell commands, web fetches) and what
  is present with both.

Things I considered but think work as-is:
- The `Bash`. `Read`. `Write`. ... staccato is name-the-things
  presentation, not abstract negation.
- The "That's it. No MCP server to wrap, no proxy config to write." in
  the install section caps a contrast against real prior setup pain.
- The triple "If it..." in the PreToolUse rationale enumerates real
  failure modes rather than rhetorical buildup.
Two related fixes that came out of the same review:

- **Receipt JSON example** (`hooks-native-tool-audit.mdx`): the example
  was missing the `credentialSubject` envelope and the `proof` block,
  flattening fields that the schema nests. Match post 1's level of
  detail by wrapping `outcome` and `chain` in `credentialSubject` and
  adding an abbreviated `proof` block. Also abbreviate the
  `parameters_hash` value to match post 1's convention. Reader no
  longer sees a partial-shape receipt presented as the canonical
  example.

- **Hook exit-behaviour docs** (`reference/cli-commands.mdx`): the page
  claimed the hook "Always exits 0" and that emit failures "are dropped
  silently." That's not what the code does — `agent-receipts-hook`
  runs with `emitter.WithStrictErrors()` and exits 1 with a stderr
  message on emit failure. ADR-0010's "events truly drop silently" is
  about the in-chain ledger (no daemon to record the gap), not about
  the hook process itself. Reword to describe both: stdin/format
  issues exit 0 silently, emit failures exit 1 with stderr; the
  in-chain gap is still silent by design.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment on lines 246 to 252
| Flag | Description |
|---|---|
| `--format` | Force a specific input format (default: auto-detected from environment variables). Currently supported: `claude-code`. |

**Exit behaviour:** Always exits 0. Emit failures (daemon not running, socket missing, malformed frame) are dropped silently — the hook never blocks the agent.
**Exit behaviour:** The hook never blocks the agent — the tool call has already completed by the time `PostToolUse` fires. Stdin/format issues exit 0 silently (unreadable stdin, unrecognised runtime). Emit failures (daemon unreachable, parse error, socket write timeout) exit 1 with a message on stderr so the operator can surface a missing-receipt event out-of-band. The in-chain audit gap from a daemon-down event is still silent by design — see [ADR-0010](https://github.com/agent-receipts/ar/blob/main/docs/adr/0010-daemon-process-separation.md) — but the hook itself is loud about its own failures.

**Auto-detection:** When `--format` is omitted, the binary inspects environment variables to identify the calling runtime. `CLAUDE_SESSION_ID` set → `claude-code` format.
Comment on lines +176 to +184
The recommended Agent Receipts configuration wires up `PostToolUse` only. That's deliberate.

**Audit first, policy second.** `PreToolUse` can block a tool call by exiting non-zero — which puts the hook in the critical path. If it's slow, the agent is slow. If it crashes, the tool call fails. If it incorrectly blocks something, the agent breaks in ways that are hard to debug. `PostToolUse` has none of these failure modes: the tool has already run, the hook fires after the fact, and a failure to record surfaces as a non-blocking error rather than a broken tool call. The audit trail has a gap, not a breakage.

**The output is more interesting than the intent.** A `PostToolUse` hook sees what the tool *returned*. A `PreToolUse` hook only sees what the agent *asked for*. For forensics and breach investigation, the output — what actually came back — is often the more useful half of the record.

**Expanding deliberately.** `SessionStart`, `UserPromptSubmit`, and `Stop` are natural next candidates: they would let the chain record session boundaries and the prompts that triggered tool use, not just the tool calls themselves. Each new event type adds surface area, and there's a wire-format question to resolve first — see the note below.

The MCP proxy already does `PreToolUse`-equivalent blocking for MCP calls. The hook will follow the same path — audit baseline first, then policy enforcement once it's proven in production.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants