Connect Claude Code¶
Four Claude Code hooks send a record to Planisphere for each prompt you submit, each tool call Claude makes and each reply it finishes. Prompts, tool inputs and replies are hashed with SHA-256 on your machine; Planisphere receives the hashes, not the text. The hooks record activity. They don't gate it: every hook exits successfully, so a failed delivery never stops Claude Code.
The console writes the hooks for you. On the Connections page, under Connect a system, choose Claude Code, paste a key, and copy the block labelled Claude Code hooks (settings.json). Read the commands before you paste them anywhere.
What the hooks record¶
Every record uses the AI Provenance pack and the system name
claude-code-primary.
| Record (hook) | Hashed on your machine | Sent as plain metadata |
|---|---|---|
prompt_submitted (UserPromptSubmit) |
The prompt text | Model, session ID, working directory, agent type, a prompt counter |
tool_used (PreToolUse, every tool) |
The tool's input, as compact JSON | Tool name, tool class, session ID, agent type |
agent_response (Stop) |
Claude's latest reply text, and the whole transcript file | Model, session ID, stop reason, working directory, turn count, a reply counter |
The fourth hook, SessionStart, sends nothing. It saves the session's model
name in /tmp/planisphere/ so the prompt records can carry it.
The tool class groups tool names: fs_read (Read, Glob, Grep), fs_write
(Write, Edit, NotebookEdit), shell (Bash, BashOutput, KillShell), network
(WebFetch, WebSearch), agent_dispatch (Task, Agent), skill (Skill) and
other.
A few limits follow from where the hooks run:
- Tool calls are recorded before they run. PreToolUse fires as Claude
asks for the tool, so a
tool_usedrecord says the call was requested. Itssuccessispendingand itsduration_msis0: placeholders, not measurements. Tool output is not recorded. - The working directory is sent as written. Prompt and reply records carry the full path of the folder Claude Code runs in. If a path names a client or a project you keep private, use a neutral folder name.
- The Stop hook reads your transcript locally. It finds Claude's latest reply in the session transcript and hashes it, and it hashes the transcript file as a whole. Neither leaves your machine as text.
- The counters are per machine.
system_seqcomes from~/.claude/planisphere-seq-promptand~/.claude/planisphere-seq-response, which the hooks increment. Two machines keep separate counts.
Before you start¶
- jq. The hooks use it to read each event Claude Code passes them. Check
with
command -v jq; on a Mac,brew install jq; on Debian or Ubuntu,sudo apt-get install jq. - curl and a SHA-256 tool. macOS has
curlandshasum; most Linux systems havecurlandsha256sum. The hooks use whichever is present. - A key from your workspace. Create one on the console's Keys page.
Use a key just for this machine, for example
claude-code-laptop, so you can revoke it without touching anything else. - macOS or Linux. Claude Code runs each hook command with
sh -c: bash 3.2 in POSIX mode on macOS, dash on Debian and Ubuntu. The hooks are written for that plain POSIX shell, not for a newer bash.
The key ends up in your settings file as plain text, inside each hook command. Keep that file private, and never put these hooks in a settings file you commit to a repository.
Add the hooks¶
- In the console, open Connections and choose Claude Code under Connect a system.
- Paste your key into Key to fill in. It stays in that browser tab and fills into the hooks; nothing is sent.
- Copy the Claude Code hooks (settings.json) block.
- Open
~/.claude/settings.json, your user settings, which apply to every project on this machine. If the file doesn't exist, create it with the block as its whole content. - If the file already has a
"hooks"object, merge rather than replace: for each ofSessionStart,PreToolUse,UserPromptSubmitandStop, add the Planisphere entry to the event's list next to the entries you already have. Check the result is valid JSON withjq . ~/.claude/settings.json. - Start a new Claude Code session. Claude Code's
/hooksmenu lists the hooks it loaded.
To connect a single project instead, put the hooks in that project's
.claude/settings.local.json, your own settings for that project, which
are not meant to be committed. Avoid .claude/settings.json in a project:
it is shared through the repository, and the hooks contain your key.
Check that records arrive¶
Send a prompt in the new session, then open the console:
- Connections → Systems sending records lists
claude-code-primarywith its record count for the last 24 hours, when the last record arrived and its last event. The last event opens that record. - Activity lists the records your workspace sealed, newest first. Each opens with its receipt.
The hooks don't print action keys, so start from the Systems table rather than Check a received record. One received record shows that the hooks ran and reached your workspace once; it doesn't show that every prompt or tool call was captured.
Troubleshooting¶
Nothing arrives. The hooks send in the background and discard errors, so a failure is silent. Check, in order:
command -v jqprints a path.jq . ~/.claude/settings.jsonprints your settings, not an error.- You started a new session after adding the hooks, and
/hookslists them. -
The key is current. This prints
200for a working key and401for a revoked or mistyped one:curl -sS -o /dev/null -w '%{http_code}\n' https://api.planisphere.ooo/tenant/me \ -H "X-Planisphere-Key: YOUR_KEY"
Prompts and replies arrive, but no tool calls, or Claude Code reports a
hook error on every tool. Your hooks are an older copy. Claude Code runs
hook commands with sh -c, and on macOS that is bash 3.2 in POSIX mode,
which can't parse a case pattern's closing ) inside $(...). The old
PreToolUse command then stops with syntax error near unexpected token and
exit status 2, which Claude Code treats as a block on that tool call. Copy
the hooks again from Connections, or edit the PreToolUse command so each
pattern opens with ( as well:
CLASS=$(case "$TN" in (Read|Glob|Grep) echo fs_read;; (Write|Edit|NotebookEdit) echo fs_write;; (Bash|BashOutput|KillShell) echo shell;; (WebFetch|WebSearch) echo network;; (Task|Agent) echo agent_dispatch;; (Skill) echo skill;; (*) echo other;; esac);
Some prompts or tool calls never arrive, often the ones with line breaks
or backslashes. Your hooks are an older copy that passes each event to jq
with echo "$INPUT". In sh (bash 3.2 in POSIX mode on macOS, dash on
Debian and Ubuntu), echo turns the \n and other backslash escapes inside
the event's JSON into real characters, so jq can't read it and the record is
silently dropped. Copy the hooks again from Connections: the current
hooks pass each value with printf '%s\n', which prints it unchanged. To
fix a copy by hand, replace every echo "$INPUT" and echo "$LAST" with
the same printf form, for example:
SID=$(printf '%s\n' "$INPUT" | jq -r .session_id);
Older Stop hooks fail differently: instead of dropping the record, they send a
reply record whose response hash is the hash of empty text
(sha256:e3b0c442…) and whose model is blank. Records like that, sealed
before you updated the hooks, show an empty reply, not the real one.
Records stopped after a while. A sandbox workspace keeps up to 100
records, and the hooks send one for every prompt, tool call and reply, so a
working session reaches that quickly. After that the API answers 402 and
the hooks drop the record. Upgrade on the console's Billing page.
The model shows as unknown. The prompt record reads the model name that
SessionStart saved in /tmp/planisphere/. If that file is missing (the
session began before you added the hooks, or /tmp was cleared), the record
says unknown. A new session fixes it.
Remove the hooks¶
Delete the four Planisphere entries from ~/.claude/settings.json (or from the
project file you used), then start a new session. Remove
/tmp/planisphere/ and ~/.claude/planisphere-seq-* if you no longer want
them, and revoke the key on the console's Keys page.
Hook events and settings files follow the official Claude Code hooks documentation.