Claude Code hooks record prompts and tool intent and enforce the deterministic
safety policy. Hooks are separate from
gensee watch: watch observes filesystem effects and macOS system
events, while Claude Code must be configured to call gensee hook claude-code
for user prompts and tool intent. Use the same GENSEE_HOME for watch, hooks,
and timeline when you want the signals to appear together.
The examples below use
/path/to/gensee-crate/target/debug/gensee— replace it with the absolute path to your built binary, and pick aGENSEE_HOME.
cargo build -p gensee-crate-cliInstall or update the Claude Code hook config:
gensee setup claude-code --gensee-home "$GENSEE_HOME"When running from a source checkout, invoke the binary you built:
./target/debug/gensee setup claude-code --gensee-home "$GENSEE_HOME"The setup command preserves unrelated settings and non-Gensee commands in the
same events, replaces stale or duplicate Gensee commands, and installs hooks
for UserPromptSubmit, PreToolUse, PostToolUse, and Stop. Changed files
are backed up and written atomically; unchanged setup runs do not rewrite them.
To route Claude Code traffic through an inspecting company gateway at the same time, pass the gateway URL and one credential source:
gensee setup claude-code \
--gensee-home "$GENSEE_HOME" \
--anthropic-base-url https://llm-gateway.example.com \
--anthropic-auth-token "$GATEWAY_TOKEN"Use --anthropic-api-key instead when the gateway expects x-api-key, or
--api-key-helper ~/bin/get-gateway-key when credentials come from SSO or a
vault. The setup command writes these values into the env block of
~/.claude/settings.json and removes stale static Claude credentials that would
conflict with the selected gateway credential.
This makes requests observable by the gateway; the gateway must still log, reject, or canonicalize suspicious request bodies itself. For strict enforcement, pair this with network policy that blocks direct Claude provider egress from developer machines.
For local testing or a small team rollout, Gensee ships a minimal Anthropic-compatible gateway:
cargo build -p gensee-crate-cli
GENSEE_HOME="$GENSEE_HOME" \
GENSEE_BIN="$PWD/target/debug/gensee" \
GENSEE_GATEWAY_TOKEN="local-gateway-token" \
ANTHROPIC_UPSTREAM_API_KEY="$ANTHROPIC_API_KEY" \
node scripts/anthropic_gateway.mjsThen configure Claude Code to use the local gateway:
./target/debug/gensee setup claude-code \
--gensee-home "$GENSEE_HOME" \
--anthropic-base-url http://127.0.0.1:8787 \
--anthropic-auth-token local-gateway-tokenThe gateway screens JSON request bodies before forwarding to Anthropic. By
default it blocks invisible/bidirectional/variation/tag Unicode markers anywhere
in the request, and blocks variant punctuation in trusted prompt scaffolding such
as system and tool descriptions. Blocks are recorded with
policy_prompt_steganography_detected through gensee gateway-alert, so they
appear in timeline and the dashboard. Set GENSEE_GATEWAY_STEGO_ACTION=warn
to record but forward suspicious requests.
The relevant settings shape is:
{
"env": {
"ANTHROPIC_BASE_URL": "https://llm-gateway.example.com",
"ANTHROPIC_AUTH_TOKEN": "sk-gateway-token"
},
"hooks": {
"UserPromptSubmit": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "GENSEE_HOME=/tmp/gensee-watch-store /path/to/gensee-crate/target/debug/gensee hook claude-code" } ] }
],
"PreToolUse": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "GENSEE_HOME=/tmp/gensee-watch-store /path/to/gensee-crate/target/debug/gensee hook claude-code" } ] }
],
"PostToolUse": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "GENSEE_HOME=/tmp/gensee-watch-store /path/to/gensee-crate/target/debug/gensee hook claude-code" } ] }
],
"Stop": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "GENSEE_HOME=/tmp/gensee-watch-store /path/to/gensee-crate/target/debug/gensee hook claude-code" } ] }
]
}
}Fully restart Claude Code, then run the sidecar plus Claude normally:
GENSEE_HOME=/tmp/gensee-watch-store ./target/debug/gensee watch \
--workspace /path/to/project --watch-root ~/.aws --watch-root ~/.sshcd /path/to/project && claudeAfter Claude runs tools, inspect the combined timeline:
GENSEE_HOME=/tmp/gensee-watch-store ./target/debug/gensee timelineHook events are stored in $GENSEE_HOME/hooks.jsonl (or ~/.gensee/hooks.jsonl
when GENSEE_HOME is not set). UserPromptSubmit prompts and Stop assistant
responses are stored from the redacted Claude hook payload and shown in
timeline as per-turn conversation events.
Redaction is pattern-based: known secret assignments, secret-looking JSON fields, private keys, and common token prefixes are redacted, but ordinary prompt and response text is otherwise persisted.
For PreToolUse, the bridge makes a deterministic policy decision and returns
allow, ask, or deny to Claude Code — see policy.md.
Bash file intents are parsed from Claude tool commands; copy commands are
represented as copy_source and copy_dest so later graph logic can trace
lineage from the input path to the output path. File effects whose timestamps
fall inside a Claude PreToolUse/PostToolUse window are shown under that tool
call as time-window correlated evidence. This correlation is not PID proof;
FSEvents does not expose the actor process.