Howto: Learning Capture for Claude Code
What it does
Claude Code automatically captures failed bash commands and stores them as learnings. When you run the same failing command again, the pre-tool-use hook warns you. Both Claude Code and opencode share the same learning store.
Architecture
Claude Code hooks (~/.claude/hooks/)
|
|--- PreToolUse (pre_tool_use.sh)
| |---> terraphim-agent guard --json (safety)
| |---> terraphim-agent replace --role ... --json (knowledge graph rewrites)
| |---> terraphim-agent hook --hook-type pre-tool-use (generic pre handler)
|
|--- PostToolUse (post_tool_use.sh)
| |---> terraphim-agent learn hook --format claude (capture failed commands)
| |---> terraphim-agent hook --hook-type post-tool-use (generic post handler)
|
|
v
Shared learning store
(~/.config/terraphim/learnings/)Prerequisites
terraphim-agentinstalled at~/.cargo/bin/terraphim-agent- Claude Code v2.1+ installed (
npm install -g @anthropic-ai/claude-code)
Setup
1. Hook scripts (already installed)
The hook scripts live at:
~/.claude/hooks/pre_tool_use.sh— runs before every Bash tool call~/.claude/hooks/post_tool_use.sh— runs after every Bash tool call
2. Hook registration (already configured)
Hooks can be registered in either ~/.claude/settings.json (shared, version-controlled) or ~/.claude/settings.local.json (personal, git-ignored). This setup uses settings.local.json so per-developer paths do not leak into the repo. On teams that want everyone to share the same hooks, move the block into settings.json.
3. Verify it works
# Simulate what Claude Code sends when a command fails
|
# Check the learning was captured
Expected output:
Learnings matching 'nonexistent-test-cmd'.
[G] [cmd] nonexistent-test-cmd (exit: 127)How learning capture works
Capture (automatic)
When Claude Code runs a Bash command that fails, Claude Code sends JSON to the PostToolUse hook via stdin:
The post_tool_use.sh script:
- Locates
terraphim-agentbinary (4 fallback paths) - Reads JSON from stdin
- Pipes to
terraphim-agent learn hook --format claude - Also runs
terraphim-agent hook --hook-type post-tool-use --json - Always fails open (
|| true) — never blocks Claude Code
Pre-tool-use warnings (automatic)
Before each Bash command, pre_tool_use.sh runs terraphim-agent hook --hook-type pre-tool-use --json which checks the command against past learnings and the role-configured knowledge graph. If it matches a past failure or a recorded correction, the hint is surfaced to the LLM via the hook's structured JSON response — never directly to the user terminal.
Claude Code and opencode now align on the same UX principle: pre-tool-use hints are for LLM consumption only, keeping the user interface clean while still informing the model about past failures and corrections.
Safety guard (automatic)
pre_tool_use.sh also runs terraphim-agent guard which blocks destructive commands like git reset --hard, rm -rf, etc. If blocked, the hook returns:
Correction (manual)
Add corrections to teach the system what to do instead:
# Record that 'npm install' should be 'bun install'
# Record that a specific command has a known fix
# Capture a user correction inline (used in conversation)
Query (manual)
Search past learnings:
# Search by keyword
# Search exactly
# List recent learnings
# Query and see corrections
Hook script details
post_tool_use.sh
stdin -> JSON { tool_name, tool_input, tool_result }
|
v
Find terraphim-agent binary
(~/.cargo/bin/ -> target/release/ -> target/debug/ -> PATH)
|
v
cd ~/.config/terraphim (for KG access)
|
v
terraphim-agent learn hook --format claude (capture failed commands)
|
v
terraphim-agent hook --hook-type post-tool-use --json (generic handler)
|
v
stdout passthrough (always succeeds, || true)pre_tool_use.sh
stdin -> JSON { tool_name, tool_input }
|
v
Filter: only Bash commands
|
v
Step 1: terraphim-agent guard --json (block destructive commands)
| If blocked -> return deny JSON
v
Step 2: terraphim-agent replace --role "Terraphim Engineer" --json
| (knowledge graph text replacement for git commits, package managers)
v
Step 3: terraphim-agent hook --hook-type pre-tool-use --json
(generic pre-tool handler)Key differences from opencode hooks
| Aspect | Claude Code | opencode |
|--------|-------------|----------|
| Hook type | Shell scripts (bash) | JavaScript plugins (Bun) |
| Registration | settings.local.json | Auto-loaded from plugin/ dir |
| Input format | JSON on stdin | JS objects (input, output) |
| Tool name | "Bash" (capital B) | "bash" (lowercase) |
| Exit code | Structured { exit_code: N } | Raw string (parse from output) |
| Blocking | Return permissionDecision: "deny" | throw new Error() |
| Fail-open | \|\| true | catch {} |
Troubleshooting
Learnings not being captured
- Check terraphim-agent is installed:
- Test the hook directly:
|
- Check hook is registered:
| Hook script not executable
Safety guard blocking legitimate commands
The safety guard uses terraphim-agent guard which checks for destructive patterns. If a legitimate command is blocked, the guard can be bypassed by running the command outside Claude Code (directly in terminal).
See also
- Learning Capture for opencode — same learning store, Bun plugin instead of shell scripts
- Command Rewriting How-To — deeper walkthrough of the knowledge-graph-driven
replacepipeline