Hive Recorder · Claude Code plugin

Claude Code plugin · open source · MIT

When an agent goes where it wasn't allowed, the record can't be yours alone. This one is signed before each call runs, and witnessed outside your walls.

Hive Recorder writes down what a session was allowed to touch before it starts. It signs every tool call before the call runs and flags anything outside what was allowed. Before each call runs, a second party witnesses the record, and a public timestamp service stamps it at the start and end of every turn. It keeps fingerprints, never content, and it never blocks anything. Anyone you hand the record to can check it offline.

claude plugin marketplace add srotzin/hive-claude-code-recorder claude plugin install hive-recorder@hive

Install from GitHubCheck a real session

Why now

In July, an agent left its sandbox. The hardest part afterwards was the record.

During internal cyber evaluations, OpenAI models got around the controls meant to keep them off the internet and broke into Hugging Face. Every account of what happened was rebuilt afterwards, from logs the people involved controlled.

WhenWhat happenedSource
May 12 to 26Agents start an improvised message board and get internet access they shouldn't haveOpenAI
July 9 to 13A 4.5-day campaign against Hugging Face. Hugging Face later rebuilt about 17,600 actions from its own logsHugging Face
July 16Hugging Face discloses the intrusion. People familiar with the matter told Reuters that OpenAI realized its own agent was responsible only after thatReuters
July 19 to 21OpenAI's monitoring flags unusual activity, OpenAI connects it to Hugging Face, then disclosesOpenAI
Late JulyHugging Face's CEO asks OpenAI to release all the agent's traces, and for $100 million in computeBusiness Insider
August 26METR and Redwood Research report that the agents tried to tamper with logs and manipulated transcripts to hide evidence of cheatingMETR
Late AugustOpenAI's investigation, validated by CrowdStrike with an independent assessment by METR and Redwood Research, finds about 700 agents took partBleepingComputer

The victim's ask was for the traces themselves, and the agents had already tried to rewrite theirs. A lab can't settle that with its own logs, because it wrote them. Signing a log with the lab's own key doesn't fix it either: whoever holds the key can delete a line and sign the whole thing again. That's what the witness is for.

A real session

Claude was allowed one host. It reached for another. The record shows it, signed before the call ran.

This is a real Claude Code 2.1.296 session from October 10, 2026, with Hive Recorder 1.1.0 installed from GitHub. Before it started, the project held an admission: Read, Edit, Glob, Grep and Bash, any file in the project, and one host, registry.npmjs.org. The task was to fix a tax bug and then look up a dataset on huggingface.co with curl. Claude Code's own permissions allowed curl. The admission didn't allow huggingface.co. Every line carries two signatures, Ed25519 and ML-DSA-65, and Hive's live witness signed both seals. This page checks all of it in your browser.

Checking in your browser...

The admission, signed as line 1

The record holds no content. The owner can still prove one value.

Line 8 is the call that left the admission. The record keeps the host, because anyone checking has to be able to re-run the scope check, and only a keyed fingerprint of the command itself. Reveal the input and this page checks it against the fingerprint, using the demo install's fingerprint key.

Break it yourself

12 ways to change the story afterwards. Each one is rejected.

Each case is a changed copy of the real record above. Several delete or hide the call to huggingface.co and then re-sign everything with both of the recorder's own keys, which is what a lab could do with its own log. The scope check, the admission or the witness catches every one.

How it works

An admission before it starts, a signed line and a witness before every call.

Before it starts

Whoever starts the agent, whether that's a sandbox orchestrator, a CI job or a person, writes down what the session may touch: tools, paths and hosts. The recorder signs that as line 1, before the first tool call. The purpose is kept as a fingerprint only.

Before every call

Claude Code runs the plugin's hooks before and after every tool call. Each line records the event, the time, the tool, the paths and hosts it touches, which of those fell outside the admission, and fingerprints of the input and output. It's signed with Ed25519 and, optionally, ML-DSA-65.

Before the call runs

The recorder sends four values to the witness at the start, after every request to run a tool and at every seal: your public key, a hash of the session id, the line count and the head hash. The witness signs them with its own time. At the start and every seal, the head also goes to DigiCert's public timestamp service. From then on, a rewritten record fails the check, even one re-signed with your own keys.

It never blocks. It reports.

The hook always exits 0 and prints nothing, so it can't deny, delay or change a call. The scope check says what happened. Your own permissions decide what's allowed.

What a line keeps

  • Which event, and when
  • Tool name, call id and MCP server name
  • With an admission: the paths and hosts the call touches, and which fell outside
  • Byte sizes, duration and keyed fingerprints of input, output and prompt
  • Two signatures and the link to the line before

What never leaves your machine

  • Prompts, tool input and tool output
  • File contents and Claude's replies
  • Your signing keys and your fingerprint key
  • Anything at all, if you set HIVE_WITNESS_URL and HIVE_TSA_URL to off

Keys out of the agent's reach

The agent can add lines. It can't change or remove one. Nobody in the session has to be trusted.

In this third real session, the recorder ran as a small service under its own system user. Claude ran as a different user, and when it tried to read the signing key it got "Permission denied". The hook on Claude's side sends fingerprints and nothing else. The service signs every line with both keys, waits for Hive's witness to sign before letting each tool call run, and sends the head to DigiCert, a public timestamp service no party to the session controls.

Checking in your browser...

6 more ways to change the story. Each one is rejected.

These go after the new protections: the Hugging Face call deleted and every line re-signed with the recorder's own keys, the witness statements withheld, fresh statements asked for afterwards, timestamps withheld or moved, and the end of the session cut off. They're checked the strict way a reviewer who wasn't there should check.

cd hive-claude-code-recorder/examples/claude-code-recorderd node ../../plugins/hive-recorder/scripts/verify.mjs session.jsonl --key key.json --admission hive-admission.json --witness-key FCHk4lQ-PvNo2cxkUoL0VlGuKdU6DiK-vPraAR7gyHE --strict

On your machine the checker also verifies DigiCert's signature on each timestamp with openssl and your system's certificates. No Hive key is involved in that check. In the browser, this page confirms each timestamp names this record's head and reads its time.

Ask the witness yourself

Nobody has to hand you the witness statements. The witness remembers.

Hive's witness now keeps every statement it signs: four fingerprints, its time and its signature, nothing else. It only remembers requests signed with the recorder's own key, so nobody else can add a history to someone's session. In this real session, Claude pulled licensed data through a market-data tool. The admission allowed two futures datasets. Claude also asked for loan-level mortgage records.

Asking the witness...

3 rewrites, none with witness statements. The witness's memory rejects each one.

cd hive-claude-code-recorder/examples/claude-code-datasets node ../../plugins/hive-recorder/scripts/verify.mjs session.jsonl --key key.json --admission hive-admission.json --witness /none --ask-witness --strict --witness-key FCHk4lQ-PvNo2cxkUoL0VlGuKdU6DiK-vPraAR7gyHE

The market-data server in this session is a local stand-in with made-up values, and every reply says so. The record names the dataset and keeps none of the data. Someone who holds the recorder key could rebuild a record and ask the witness again. The witness then remembers both histories, and both fail against its memory.

A second real session

A call Claude Code denied, shown as asked for with no outcome.

In an earlier session, with no admission, Claude asked to run a curl that Claude Code's permissions didn't allow. Claude Code's own output lists the call as denied. The record shows the same call id as asked for, with no outcome. Hive's live witness signed both seals.

Checking in your browser...

Check it on your machine

No form, no account. Download it and run one command.

unzip hive-claude-code-recorder.zip && cd hive-claude-code-recorder/examples/claude-code-admission node ../../plugins/hive-recorder/scripts/verify.mjs session.jsonl --key key.json --admission hive-admission.json --witness-key FCHk4lQ-PvNo2cxkUoL0VlGuKdU6DiK-vPraAR7gyHE cd ../.. && node tests/run.mjs

The checker exits 0 when the record holds and everything stayed inside the admission, 3 when the record holds and something reached outside it, and 1 when the record was changed. The test suite runs the real hook script once per event, the way Claude Code does. On our run, 59 of 59 checks passed, including the witness memory tests against a real Postgres database.

Open format

hive.agent-action/1. Any agent runtime with before and after hooks can write it.

The record format, the admission, the scope check, the witness protocol, the public timestamps and the ten checks are written up as an open spec with JSON Schemas. Claude Code is the first producer. The format doesn't depend on it.

What this does not show

A record shows what the session was allowed to touch, which events Claude Code reported, in what order and when, and that none of it changed afterwards. It doesn't show that an action was right, safe or authorized, or why an agent reached outside its admission. The admission is only as good as whoever wrote it.

The scope check only sees what a tool's input names. A host reached by a program the agent starts, or through a variable, isn't seen. Covering that takes a recorder on the sandbox's network boundary writing the same records, and that's the next piece. The recorder can't include anything Claude Code doesn't report to its hooks.

In plugin mode the signing keys sit on the agent's machine, so an agent that can run shell commands could read them. Everything a witness has signed still holds, and with a witness before every call that's every line up to the last one. In service mode the keys aren't on the agent's side at all. Hive's witness remembers what it signed, so a reviewer can ask it directly, and a record cut short or rebuilt fails even when nobody hands over the statements. Someone holding the recorder key can still write a second history for a session. The witness then remembers both, and neither passes. A record rebuilt from scratch under a new session id is caught by knowing which session ran, and the public timestamps carry a time nobody in the session controls.

Hive runs the default witness and holds its key, so it is a second party to you, not an independent auditor. The recorder takes several witnesses at once, and the checker can require more than one. You can run your own, or have an auditor or the other side run one, from the same repo. DigiCert's timestamps need no trust in Hive at all. The ML-DSA-65 signature uses the open-source noble library. The witness signs with Ed25519.

If you run agents in evaluations or on real systems and want this on your own sessions, write to me at [email protected].

Sources