Wires Claude Code to a didbot personal data server: hooks, a plugin, and the harness contract they rest on.

Files
README.md

didbot-claude #

Wires Claude Code to a didbot personal data server: the hook the harness runs, the plugin that installs it, and the measured contract they rest on.

Nothing here signs, holds a credential, or knows a product's record types. Everything reaches a personal data server through the local daemon's socket. AGENTS.md says why each of those is a rule.

Watching what your agents are doing #

Install the plugin, start the receiver, and every session on the machine narrates itself:

claude plugin marketplace add https://tangled.org/permadeath.com/didbot-claude
claude plugin install didbot@didbot
./tools/echo-receiver.py

If didbot's daemon is already running, see With didbot's daemon instead.

10:16:43  2ef76bde  session started  ~/work/thing
10:16:49  2ef76bde    main                         Agent
10:16:49  2ef76bde  spawned          adb7fdf6 general-purpose
10:16:51  2ef76bde    adb7fdf6 general-purpose     Bash
10:16:54  2ef76bde    adb7fdf6 general-purpose     Bash
10:16:57  2ef76bde  finished a turn  adb7fdf6 general-purpose
10:17:01  2ef76bde  session ended    ~/work/thing

A running count sits pinned below the feed:

────────────────────────────────────────────────────────────────
 sessions 3 (1 open)   agents 9: 2 working, 7 resting   resumed 1
 calls 247   main 180   sub 67   failed 2
 anomalies: forks 12   unspawned 1

A stop ends a turn, not an agent, so what is working is a refcount rather than a flag. forks counts stops carrying no start and no type — the harness's own internal forks, which are never allowed to become agents — and unspawned counts calls from an agent nothing was seen to spawn.

--json prints records instead of the feed, --quiet keeps only the count, and --log <path> keeps everything either way. kill -USR1 prints a fuller summary without stopping it, and so does exiting.

The receiver authenticates nothing and sends nothing off the machine. didbot's daemon, listening on the same socket instead, gives every session and every subagent an account on its server. Removing the plugin is claude plugin uninstall didbot@didbot.

Field names and identifiers are recorded. Values are not — a payload carries prompts, tool arguments and file paths, and none of that answers a question plan/collection.md asks. The exceptions are the session's working directory, which the feed shows, the request_uri of each sign-in URL a tool call saw, and the sign-in page a browser tool is about to open or failed to open.

Signing the agent's browser in #

A web app's sign-in code goes only to a browser signed in as the agent. When chrome-devtools-mcp's new_page or navigate_page is about to open the sign-in page the daemon named, the hook writes the daemon's one-time link into the tool's input, and removes the link's ticket and the browser's session cookie from every chrome-devtools tool's output before the model reads it. Claude Code's session transcript on disk keeps the rewritten URL, whose ticket the browser spends as it opens it.

With didbot's daemon #

didbot's didbot-agentd listens on the same socket as the echo receiver, and only one of them can hold it. Run the daemon there alone and the plugin talks to it directly: each context is told its identity, and nothing narrates.

To watch the feed as well, start the daemon on daemon.sock first. Then scripts/dev-feed.sh takes the plugin's socket, narrates each record, and forwards it to the daemon, whose answer goes back to the hook unchanged:

# in the didbot checkout
DIDBOT_SOCK="${XDG_RUNTIME_DIR:-/tmp}/didbot-agent/daemon.sock" \
    ./scripts/dev-agentd.sh
# here
./scripts/dev-feed.sh

What it will cost, before you install it #

tools/estimate.py counts what the harness has already written on this machine — one transcript per session, one sidecar per subagent — and says how many agent contexts that implies per month. File names and timestamps only; no transcript is opened.

It reports a range rather than a number on purpose: on the machine this was built for, thirty days averaged 1,500 contexts a month while the last two days ran at 5,300. Either figure alone would be wrong within a week, and the spread is the finding.

What is measured, and what is assumed #

plan/harnesses.md is the register. An entry says how it was observed: which version, which surface, what the run was. Rates over long interactive sessions are what plan/collection.md measures.