From 7cfb626dde1e33834e767145df442e9c15f93de3 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 09:27:29 +1200 Subject: [PATCH 1/7] docs(daemon): add v0.10.0 CHANGELOG entry --- daemon/CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/daemon/CHANGELOG.md b/daemon/CHANGELOG.md index c90184cc..b09fbca3 100644 --- a/daemon/CHANGELOG.md +++ b/daemon/CHANGELOG.md @@ -5,6 +5,47 @@ All notable changes to `agent-receipts-daemon` are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.10.0] - 2026-05-17 + +### Added + +- **Receipt pipeline redaction** ([#426](https://github.com/agent-receipts/ar/pull/426), + closes [#423](https://github.com/agent-receipts/ar/issues/423)): + The daemon now redacts secrets from receipt body fields before persistence. + Built-in patterns cover GitHub PATs, OpenAI/Anthropic keys, AWS access key IDs, + bearer tokens, Slack tokens, PEM private keys, and URL query-string tokens. + JSON-aware key redaction additionally covers `password`, `token`, `api_key`, + `secret`, `authorization`, `private_key`, `jwt`, and 20+ other sensitive key names. + Redaction runs after hashing — `parameters_hash` and `response_hash` commit to + the raw canonical bytes; only the stored text fields (`outcome.error`, + `parameters_disclosure` when enabled) are sanitised. + Custom patterns can be added via `--redact-patterns ` + (env: `AGENTRECEIPTS_REDACT_PATTERNS`). + +- **`agent-receipts list` companion CLI command** ([#420](https://github.com/agent-receipts/ar/pull/420), + closes [#410](https://github.com/agent-receipts/ar/issues/410)): + `agent-receipts list` prints recent receipts from the daemon store in tabular + or JSON form. Flags: `--limit N` (default 50), `--json`, `--db`/`AGENTRECEIPTS_DB`. + Newest-first by default. + +### Changed + +- **mcp-proxy is now a thin emitter** ([#421](https://github.com/agent-receipts/ar/pull/421), + closes [#416](https://github.com/agent-receipts/ar/issues/416)): + The mcp-proxy no longer maintains its own `receipts.db` or signs receipts. + It forwards raw tool-call events to the daemon over the Unix socket + (the same pattern as `agent-receipts-hook`). The daemon is the sole receipt + writer. **Breaking change for mcp-proxy:** the `-receipt-db`, `-key`, `-chain`, + `-issuer*`, `-operator*`, `-principal`, `-taxonomy`, and `-bundled-taxonomies` + flags have been removed. The `mcp-proxy list`, `inspect`, `verify`, `export`, + and `stats` subcommands now print a deprecation notice pointing to + `agent-receipts list` / `agent-receipts verify`. + +### Dependencies + +- Bump `github.com/agent-receipts/ar/sdk/go` to `v0.9.1` + (DESC ordering and no silent 10k row cap in `QueryReceipts`). + ## [0.9.1] - 2026-05-16 ### Dependencies From 79172364b52454538dacd8272855ed8722c92a23 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 09:53:35 +1200 Subject: [PATCH 2/7] =?UTF-8?q?docs(blog):=20Why=20Your=20Agent=20Can't=20?= =?UTF-8?q?Audit=20Itself=20=E2=80=94=20daemon=20process=20separation=20po?= =?UTF-8?q?st?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- site/astro.config.mjs | 4 + .../docs/blog/daemon-process-separation.mdx | 115 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 site/src/content/docs/blog/daemon-process-separation.mdx diff --git a/site/astro.config.mjs b/site/astro.config.mjs index 6a644b0f..e1809a9d 100644 --- a/site/astro.config.mjs +++ b/site/astro.config.mjs @@ -156,6 +156,10 @@ export default defineConfig({ label: "Blog", items: [ { label: "All Posts", slug: "blog" }, + { + label: "Why Your Agent Can't Audit Itself", + slug: "blog/daemon-process-separation", + }, { label: "OpenClaw Plugin: How It Works", slug: "blog/openclaw-plugin-deep-dive", diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx new file mode 100644 index 00000000..a999b811 --- /dev/null +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -0,0 +1,115 @@ +--- +title: "Why Your Agent Can't Audit Itself" +description: "The architectural problem with in-process receipt signing, and how daemon process separation restores the audit property." +--- + +An agent that signs its own audit trail isn't being audited. It's writing its own report card. + +This sounds obvious when you say it out loud. It took building the first version of Agent Receipts to see it clearly. + +--- + +## The original design + +The first version of Agent Receipts worked like this: each MCP proxy instance loaded an Ed25519 signing key, maintained its own SQLite database, and signed and stored a receipt for every tool call it intercepted — all in the same process as the agent. + +It produced real cryptographic signatures. The hash chain was valid. Receipts could be verified. But the security property was hollow: the process doing the auditing was the same process being audited. A compromised or misbehaving agent could suppress receipts, forge them, or simply not write them. The signing key was right there in memory. + +There was a second problem. Running multiple MCP proxy instances — which is the normal case when an agent uses several MCP servers — meant multiple independent chains with no shared sequence space. Correlating a GitHub tool call with a filesystem tool call meant writing application-level join logic, not querying one table. + +--- + +## The decision + +ADR-0010 split every integration into two roles. + +**Thin emitter** — the plugin, proxy, or SDK fires an event describing the tool call. No signing. No storage. No crypto. Fire-and-forget over a local Unix socket. The agent is never blocked waiting for the audit layer. If the daemon is down, the event drops silently and the gap is visible in the chain on restart. + +**agent-receipts-daemon** — a separate process running as its own OS user, sole owner of the signing keys and the SQLite database. Receives events, captures peer credentials at the kernel level, canonicalises inputs (RFC 8785), hash-chains, signs (Ed25519), and persists. + +```mermaid +graph LR + subgraph agent["Agent process"] + MP[mcp-proxy] + Hook[agent-receipts-hook] + end + subgraph daemon["agent-receipts-daemon"] + PC[peer credential capture] + CH[hash chain] + KS[signing key] + DB[(receipts.db)] + end + + MP-. fire-and-forget .->PC + Hook-. fire-and-forget .->PC + PC --> CH --> KS --> DB +``` + +The agent process no longer has access to the signing keys. It cannot read the database. It cannot forge, suppress, or tamper with its own receipts — not because we trust it, but because it structurally cannot. + +--- + +## Peer credential capture + +The daemon doesn't trust the emitter's identity claims. At connection accept time it captures OS-level peer credentials from the socket itself: + +- **macOS**: `LOCAL_PEERCRED` for uid/gid, `LOCAL_PEEREPID` for pid, then `proc_pidpath` for the executable path +- **Linux**: `SO_PEERCRED` for uid, gid, pid, then `/proc//exe` for the executable path + +These are kernel-attested. The connecting process cannot forge them. The daemon records them on every receipt, so an auditor can verify not just *what* was called but *which process* called it — by uid, pid, and executable path. + +--- + +## One chain, all channels + +Because all emitters connect to the same daemon socket, all receipts go into one chain with a global monotonic sequence. An agent session that uses three MCP servers and fires native tool calls via the Claude Code hook produces one chain — not four. + +Cross-channel correlation falls out naturally: find all receipts with the same `session_id` and you have the complete tool call history for that session, regardless of which emitter captured each call. + +--- + +## The tradeoff + +The daemon is a system service. That's friction the old `npm install` story didn't have. It requires installation, a signing key, and a service manager entry (launchd on macOS, systemd on Linux). + +That's the price of the security property. An in-process solution that's easy to install doesn't audit anything meaningful. A separate trusted process that requires setup does. + +Homebrew handles most of it: + +```sh +brew install agent-receipts/tap/agent-receipts-daemon +brew services start agent-receipts-daemon +``` + +--- + +## What it looks like in practice + +The receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. A real one from this session: + +```json +{ + "action": { + "type": "mcp.github.pull_request_read", + "parameters_hash": "sha256:2f9911eb..." + }, + "credentialSubject": { + "chain": { "sequence": 2046, "chain_id": "default" } + }, + "proof": { + "type": "Ed25519Signature2020", + "verificationMethod": "did:agent-receipts-daemon:local#k1", + "proofValue": "uZ7aqJ4Zfq..." + } +} +``` + +The signing key (`did:agent-receipts-daemon:local#k1`) lives only in the daemon. The agent process that triggered this call has never seen it. + +--- + +## What comes next + +The daemon is the trust anchor for everything that follows: secret redaction before storage, asymmetric payload encryption so only a forensic key holder can read stored inputs, centralised storage for cross-machine audit trails. All of it depends on having one trusted process that owns the keys and the chain. + +The next post covers two of those in action — a live demo of the unified chain and secret redaction working together. From 91a3019c1d9adba43592abe89d775e0eb9965427 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 13:18:00 +1200 Subject: [PATCH 3/7] docs(blog): clarify drop semantics and refine forward-looking section --- site/src/content/docs/blog/daemon-process-separation.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx index a999b811..61c15a16 100644 --- a/site/src/content/docs/blog/daemon-process-separation.mdx +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -23,7 +23,7 @@ There was a second problem. Running multiple MCP proxy instances — which is th ADR-0010 split every integration into two roles. -**Thin emitter** — the plugin, proxy, or SDK fires an event describing the tool call. No signing. No storage. No crypto. Fire-and-forget over a local Unix socket. The agent is never blocked waiting for the audit layer. If the daemon is down, the event drops silently and the gap is visible in the chain on restart. +**Thin emitter** — the plugin, proxy, or SDK fires an event describing the tool call. No signing. No storage. No crypto. Fire-and-forget over a local Unix socket. The agent is never blocked waiting for the audit layer. If the daemon is running but backpressured, the emitter increments a local drop counter and flushes it on the next successful send, so the daemon can record the gap as an `events_dropped` receipt in the chain. If the daemon isn't running at all, events drop without trace — that case is detectable from outside the chain, via service-manager status and the absence of fresh receipts. **agent-receipts-daemon** — a separate process running as its own OS user, sole owner of the signing keys and the SQLite database. Receives events, captures peer credentials at the kernel level, canonicalises inputs (RFC 8785), hash-chains, signs (Ed25519), and persists. @@ -85,7 +85,7 @@ brew services start agent-receipts-daemon ## What it looks like in practice -The receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. A real one from this session: +The receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. A real one from this session (hashes and signature abbreviated): ```json { @@ -110,6 +110,6 @@ The signing key (`did:agent-receipts-daemon:local#k1`) lives only in the daemon. ## What comes next -The daemon is the trust anchor for everything that follows: secret redaction before storage, asymmetric payload encryption so only a forensic key holder can read stored inputs, centralised storage for cross-machine audit trails. All of it depends on having one trusted process that owns the keys and the chain. +The daemon is the trust anchor for everything that follows: secret redaction before storage (already shipped), asymmetric payload encryption so only a forensic key holder can read stored inputs, centralised storage for cross-machine audit trails. All of it depends on having one trusted process that owns the keys and the chain. -The next post covers two of those in action — a live demo of the unified chain and secret redaction working together. +The next post puts the first two together — a live demo of the unified chain and secret redaction working end to end. From f62a3d97324c63fcd374d6057c5bc615d965e6ac Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 13:24:06 +1200 Subject: [PATCH 4/7] docs(blog): add series framing to daemon post --- site/src/content/docs/blog/daemon-process-separation.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx index 61c15a16..ec442941 100644 --- a/site/src/content/docs/blog/daemon-process-separation.mdx +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -3,6 +3,10 @@ title: "Why Your Agent Can't Audit Itself" description: "The architectural problem with in-process receipt signing, and how daemon process separation restores the audit property." --- +**Series: Auditing AI Agents** · Part 1 of 3 · Next: [One Chain, Two Channels, Zero Secrets →](/blog/unified-chain-redaction-demo/) + +--- + An agent that signs its own audit trail isn't being audited. It's writing its own report card. This sounds obvious when you say it out loud. It took building the first version of Agent Receipts to see it clearly. From 0ee22f63fb96c62b8795d431a154ee1e8a6057c4 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 19:10:40 +1200 Subject: [PATCH 5/7] docs(blog): tighten tone of daemon-process-separation post Retitle to declarative form, drop the apologetic intro paragraph, fold "deliberately small" into the original-design framing, and flatten a handful of writing tropes (rule-of-three buildup, "no X / no Y / no Z", "falls out naturally", "what actually provides the property"). --- .../docs/blog/daemon-process-separation.mdx | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx index ec442941..d7b226eb 100644 --- a/site/src/content/docs/blog/daemon-process-separation.mdx +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -1,5 +1,5 @@ --- -title: "Why Your Agent Can't Audit Itself" +title: "The audit boundary belongs outside the agent" description: "The architectural problem with in-process receipt signing, and how daemon process separation restores the audit property." --- @@ -7,19 +7,17 @@ description: "The architectural problem with in-process receipt signing, and how --- -An agent that signs its own audit trail isn't being audited. It's writing its own report card. - -This sounds obvious when you say it out loud. It took building the first version of Agent Receipts to see it clearly. +An agent that signs its own audit trail isn't being audited. --- ## The original design -The first version of Agent Receipts worked like this: each MCP proxy instance loaded an Ed25519 signing key, maintained its own SQLite database, and signed and stored a receipt for every tool call it intercepted — all in the same process as the agent. +The first version of Agent Receipts was deliberately small: each MCP proxy instance loaded an Ed25519 signing key, maintained its own SQLite database, and signed and stored a receipt for every tool call it intercepted — all in the same process as the agent. -It produced real cryptographic signatures. The hash chain was valid. Receipts could be verified. But the security property was hollow: the process doing the auditing was the same process being audited. A compromised or misbehaving agent could suppress receipts, forge them, or simply not write them. The signing key was right there in memory. +The cryptography worked. The audit property didn't. When the signing process and the audited process are the same, a process with access to its own signing key and receipt store can alter the record. -There was a second problem. Running multiple MCP proxy instances — which is the normal case when an agent uses several MCP servers — meant multiple independent chains with no shared sequence space. Correlating a GitHub tool call with a filesystem tool call meant writing application-level join logic, not querying one table. +The second limitation was fragmentation. Running multiple MCP proxy instances — the normal case when an agent uses several MCP servers — meant multiple independent chains with no shared sequence space. Correlating a GitHub tool call with a filesystem tool call meant writing application-level join logic, not querying one table. --- @@ -27,7 +25,7 @@ There was a second problem. Running multiple MCP proxy instances — which is th ADR-0010 split every integration into two roles. -**Thin emitter** — the plugin, proxy, or SDK fires an event describing the tool call. No signing. No storage. No crypto. Fire-and-forget over a local Unix socket. The agent is never blocked waiting for the audit layer. If the daemon is running but backpressured, the emitter increments a local drop counter and flushes it on the next successful send, so the daemon can record the gap as an `events_dropped` receipt in the chain. If the daemon isn't running at all, events drop without trace — that case is detectable from outside the chain, via service-manager status and the absence of fresh receipts. +**Thin emitter** — the plugin, proxy, or SDK serialises the tool call, writes it to a local Unix socket, and moves on. Signing, storage, and chaining are the daemon's concern; the agent is never blocked waiting for the audit layer. If the daemon is running but backpressured, the emitter increments a local drop counter and flushes it on the next successful send, so the daemon can record the gap as an `events_dropped` receipt in the chain. If the daemon isn't running at all, events drop without trace — that case is detectable from outside the chain, via service-manager status and the absence of fresh receipts. **agent-receipts-daemon** — a separate process running as its own OS user, sole owner of the signing keys and the SQLite database. Receives events, captures peer credentials at the kernel level, canonicalises inputs (RFC 8785), hash-chains, signs (Ed25519), and persists. @@ -49,13 +47,13 @@ graph LR PC --> CH --> KS --> DB ``` -The agent process no longer has access to the signing keys. It cannot read the database. It cannot forge, suppress, or tamper with its own receipts — not because we trust it, but because it structurally cannot. +The agent process has no access to the signing keys or the database. The separation is structural. --- ## Peer credential capture -The daemon doesn't trust the emitter's identity claims. At connection accept time it captures OS-level peer credentials from the socket itself: +The daemon does not rely on the emitter's identity claims. At connection accept time it captures OS-level peer credentials from the socket itself: - **macOS**: `LOCAL_PEERCRED` for uid/gid, `LOCAL_PEEREPID` for pid, then `proc_pidpath` for the executable path - **Linux**: `SO_PEERCRED` for uid, gid, pid, then `/proc//exe` for the executable path @@ -68,15 +66,15 @@ These are kernel-attested. The connecting process cannot forge them. The daemon Because all emitters connect to the same daemon socket, all receipts go into one chain with a global monotonic sequence. An agent session that uses three MCP servers and fires native tool calls via the Claude Code hook produces one chain — not four. -Cross-channel correlation falls out naturally: find all receipts with the same `session_id` and you have the complete tool call history for that session, regardless of which emitter captured each call. +Cross-channel correlation is one query: find all receipts with the same `session_id` and you have the complete tool call history for that session, regardless of which emitter captured each call. --- ## The tradeoff -The daemon is a system service. That's friction the old `npm install` story didn't have. It requires installation, a signing key, and a service manager entry (launchd on macOS, systemd on Linux). +The daemon is a system service. That's friction the old `npm install` flow didn't have. It requires installation, a signing key, and a service manager entry (launchd on macOS, systemd on Linux). -That's the price of the security property. An in-process solution that's easy to install doesn't audit anything meaningful. A separate trusted process that requires setup does. +That's the cost of a meaningful audit boundary. In-process signing is simpler to install; it isn't the audit boundary. Homebrew handles most of it: From 15227fb58a07418c3ff915c3b2114dd1429541d8 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 19:17:51 +1200 Subject: [PATCH 6/7] docs(blog): warm cadence and concrete detail in daemon post MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace clinical phrasings with warmer word choices throughout, and lean into the elegance of the underlying mechanics — particularly in the peer credential section, where the kernel-attested identity is now framed as the daemon asking the kernel directly. Adds the image of an auditor "holding its own signing key" to make the v1 limitation concrete, and notes that the separation is "structural, not policy". --- .../docs/blog/daemon-process-separation.mdx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx index d7b226eb..32a7d080 100644 --- a/site/src/content/docs/blog/daemon-process-separation.mdx +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -15,9 +15,9 @@ An agent that signs its own audit trail isn't being audited. The first version of Agent Receipts was deliberately small: each MCP proxy instance loaded an Ed25519 signing key, maintained its own SQLite database, and signed and stored a receipt for every tool call it intercepted — all in the same process as the agent. -The cryptography worked. The audit property didn't. When the signing process and the audited process are the same, a process with access to its own signing key and receipt store can alter the record. +The cryptography worked. The audit property didn't. When the signing process and the audited process are the same, the auditor is holding its own signing key. It can sign what it likes, drop what it doesn't, and nothing outside the process can disagree. -The second limitation was fragmentation. Running multiple MCP proxy instances — the normal case when an agent uses several MCP servers — meant multiple independent chains with no shared sequence space. Correlating a GitHub tool call with a filesystem tool call meant writing application-level join logic, not querying one table. +A second limitation came from running more than one MCP proxy at once — the usual case when an agent talks to several MCP servers. Each proxy kept its own chain, with no shared sequence between them. Correlating a GitHub tool call with a filesystem tool call meant application-level join logic instead of one query. --- @@ -47,26 +47,26 @@ graph LR PC --> CH --> KS --> DB ``` -The agent process has no access to the signing keys or the database. The separation is structural. +The agent process can't reach the signing keys or the database. The separation is structural, not policy. --- ## Peer credential capture -The daemon does not rely on the emitter's identity claims. At connection accept time it captures OS-level peer credentials from the socket itself: +The daemon doesn't take the emitter's word for who it is. The moment a connection lands on the socket, it asks the kernel directly: - **macOS**: `LOCAL_PEERCRED` for uid/gid, `LOCAL_PEEREPID` for pid, then `proc_pidpath` for the executable path - **Linux**: `SO_PEERCRED` for uid, gid, pid, then `/proc//exe` for the executable path -These are kernel-attested. The connecting process cannot forge them. The daemon records them on every receipt, so an auditor can verify not just *what* was called but *which process* called it — by uid, pid, and executable path. +These come straight from the kernel. The connecting process can lie about anything in its payload, but not about who it is. The daemon stamps every receipt with that identity, so an auditor can answer not just *what* was called but *which process* called it — by uid, pid, and executable path. --- ## One chain, all channels -Because all emitters connect to the same daemon socket, all receipts go into one chain with a global monotonic sequence. An agent session that uses three MCP servers and fires native tool calls via the Claude Code hook produces one chain — not four. +Because every emitter connects to the same daemon socket, all receipts land in one chain with a single monotonic sequence. An agent session that talks to three MCP servers and fires native tool calls through the Claude Code hook produces one chain — not four. -Cross-channel correlation is one query: find all receipts with the same `session_id` and you have the complete tool call history for that session, regardless of which emitter captured each call. +Cross-channel correlation collapses to one query: every receipt for a session carries the same `session_id`, regardless of which emitter captured the call. --- @@ -74,7 +74,7 @@ Cross-channel correlation is one query: find all receipts with the same `session The daemon is a system service. That's friction the old `npm install` flow didn't have. It requires installation, a signing key, and a service manager entry (launchd on macOS, systemd on Linux). -That's the cost of a meaningful audit boundary. In-process signing is simpler to install; it isn't the audit boundary. +That's the cost of an audit boundary that means something. In-process signing is simpler to install; it just isn't the audit boundary. Homebrew handles most of it: @@ -87,7 +87,7 @@ brew services start agent-receipts-daemon ## What it looks like in practice -The receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. A real one from this session (hashes and signature abbreviated): +Receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. Here's a real one from this session, signature and hashes abbreviated: ```json { @@ -106,7 +106,7 @@ The receipts are W3C Verifiable Credentials, Ed25519-signed, hash-chained. A rea } ``` -The signing key (`did:agent-receipts-daemon:local#k1`) lives only in the daemon. The agent process that triggered this call has never seen it. +That signing key — `did:agent-receipts-daemon:local#k1` — lives only in the daemon. The agent process that triggered this call has never seen it. --- @@ -114,4 +114,4 @@ The signing key (`did:agent-receipts-daemon:local#k1`) lives only in the daemon. The daemon is the trust anchor for everything that follows: secret redaction before storage (already shipped), asymmetric payload encryption so only a forensic key holder can read stored inputs, centralised storage for cross-machine audit trails. All of it depends on having one trusted process that owns the keys and the chain. -The next post puts the first two together — a live demo of the unified chain and secret redaction working end to end. +The next post is the demo — the unified chain and secret redaction working end to end, on real receipts. From 6685e6a9839714e22600be71d57bfa08e28aab41 Mon Sep 17 00:00:00 2001 From: Otto Jongerius Date: Sun, 17 May 2026 19:20:42 +1200 Subject: [PATCH 7/7] docs(blog): link ADR-0010 reference in daemon post --- site/src/content/docs/blog/daemon-process-separation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/content/docs/blog/daemon-process-separation.mdx b/site/src/content/docs/blog/daemon-process-separation.mdx index 32a7d080..9e4a72b8 100644 --- a/site/src/content/docs/blog/daemon-process-separation.mdx +++ b/site/src/content/docs/blog/daemon-process-separation.mdx @@ -23,7 +23,7 @@ A second limitation came from running more than one MCP proxy at once — the us ## The decision -ADR-0010 split every integration into two roles. +[ADR-0010](https://github.com/agent-receipts/ar/blob/main/docs/adr/0010-daemon-process-separation.md) split every integration into two roles. **Thin emitter** — the plugin, proxy, or SDK serialises the tool call, writes it to a local Unix socket, and moves on. Signing, storage, and chaining are the daemon's concern; the agent is never blocked waiting for the audit layer. If the daemon is running but backpressured, the emitter increments a local drop counter and flushes it on the next successful send, so the daemon can record the gap as an `events_dropped` receipt in the chain. If the daemon isn't running at all, events drop without trace — that case is detectable from outside the chain, via service-manager status and the absence of fresh receipts.