Troubleshooting¶
Common errors and how to diagnose them.
"My hook didn't fire"¶
Four things to check, in order:
- Run
capt-hook --hooks <dir> testwith the inline tests in place. If the test fails, the hook's conditions aren't matching the input you expect — fix the condition before debugging dispatch. - Confirm the
--hooksargument points at the directory that actually contains your hook file. Captain-hook loads.pyfiles under that root and nothing else. - Inspect the
events=argument. A primitive defaults to one event (block_command→PreToolUse,nudge→PostToolUse); if you want a different event, pass it explicitly. - View the recent dispatch logs with
capt-hook logs. By default it prints the most recent session's per-event log file, written under the cache log dir (default~/.cache/captain-hook/logs, see Configuration). Pass--tail Nto limit lines, or--session <id-or-transcript-path>to target a specific session. If your hook never appears in the log, dispatch never reached it — recheck steps 1–3.
Settings not picked up¶
Captain-hook reads settings from environment variables with the HOOKS_ prefix. A HooksSettings subclass only auto-loads if you build it through build_settings(YourSettings) or expose it from your conf.py so the dispatch CLI can discover it.
- Run
printenv | rg HOOKS_to confirm the variable is set. - If you changed the prefix via
model_config = SettingsConfigDict(env_prefix="MYAPP_"), double-check that nothing else still expectsHOOKS_. - See Configuration for the full settings surface.
RuntimeError: spaCy model is not installed¶
NLP signals refuse to auto-download the spaCy model at hook execution time (it's a ~100MB silent fetch). Install it once, explicitly:
Or, if you want the model cached at the location captain-hook expects:
Hook fired twice¶
If a primitive emits the same nudge / block twice for one event:
- Inspect
events=on every registration. A hook registered withEvent.Stop | Event.SubagentStopfires on both — confirm that's what you want. - For
nudge, addmax_fires=Nto cap how many times it can emit in a session. - For signal-driven nudges, the same trigger phrase may live in multiple
Signalpatterns. Runcapt-hook --hooks <dir> test— each test prints theInputit built and a PASS/FAIL, so you can confirm whether the phrase matched.
"Inline test failed but I can't tell why"¶
The default output prints the Input it built and a PASS/FAIL for each test. Add --json to emit one record per test (id, status, expected, reason) for structured inspection. If the test still looks correct, dump the Input you're constructing — the most common mistake is leaving a field off (e.g. file= for an Edit test) so the hook's condition can't match.
"How do I see what events look like?"¶
Drop an audit() into your hooks directory for one session:
It writes one JSONL line per event under the log directory (see Configuration). Tail the file while the agent runs to see the exact tool_input, tool_name, and metadata your hooks will receive.