Hooks
OpenWolf registers 6 hooks with Claude Code. They fire automatically on every action. No user interaction required.
All hooks are pure Node.js file I/O. No network calls, no AI, no external dependencies. They read JSON on stdin from Claude Code and communicate via exit codes and stderr.
Hook Lifecycle
┌──────────────┐
│ Claude Code │
│ session start │──→ session-start.js ──→ creates _session.json, logs to memory.md
└──────┬───────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ Claude wants │──→ │ pre-read.js │──→ warns on repeated reads, shows anatomy info
│ to READ │ └──────────────┘
└──────┬───────┘
│ (read happens)
▼
┌──────────────┐ ┌──────────────┐
│ Read complete │──→ │ post-read.js │──→ estimates tokens, records to _session.json
└──────────────┘ └──────────────┘
┌──────────────┐ ┌───────────────┐
│ Claude wants │──→ │ pre-write.js │──→ checks cerebrum Do-Not-Repeat patterns
│ to WRITE │ └───────────────┘
└──────┬───────┘
│ (write happens)
▼
┌──────────────┐ ┌────────────────┐
│ Write done │──→ │ post-write.js │──→ updates anatomy.md, appends to memory.md
└──────────────┘ └────────────────┘
┌──────────────┐ ┌──────────┐
│ Claude stops │──→ │ stop.js │──→ writes session summary to token-ledger.json
└──────────────┘ └──────────┘session-start.js
Fires: When a Claude Code session begins.
What it does:
- Creates a fresh
_session.jsonin.wolf/hooks/with a unique session ID - Appends a session header to
.wolf/memory.mdwith a table template - Increments the
total_sessionscounter intoken-ledger.json
Timeout: 5 seconds
pre-read.js
Fires: Before Claude reads any file (via the Read tool).
Stdin: { "tool_name": "Read", "tool_input": { "file_path": "src/index.ts" } }
What it does:
- Checks if this file was already read this session
- If repeated: writes a warning to stderr. "⚡ OpenWolf: file.ts was already read this session (~380 tokens)"
- Looks up the file in
anatomy.mdand prints the description. "📋 OpenWolf anatomy: file.ts, Main entry point (~380 tok)" - Records anatomy hit or miss in the session tracker
Behavior: Always exits 0 (allows the read). Warnings only, never blocks.
Timeout: 5 seconds
pre-write.js
Fires: Before Claude writes, edits, or multi-edits any file.
Stdin: { "tool_name": "Write", "tool_input": { "file_path": "...", "content": "..." } }
What it does:
- Reads
cerebrum.mdand extracts entries from the## Do-Not-Repeatsection - For each entry, checks if the content being written contains flagged patterns
- If matched: writes a warning to stderr. "⚠️ OpenWolf cerebrum warning: 'never use var', check your code"
Pattern matching: Simple regex on quoted strings and "never use X" / "avoid X" phrases. No LLM involved.
Behavior: Always exits 0 (allows the write). Warnings only, never blocks.
Timeout: 5 seconds
post-read.js
Fires: After Claude successfully reads a file.
Stdin: { "tool_input": { "file_path": "..." }, "tool_output": { "content": "..." } }
What it does:
- Estimates token count of the file content (character ratio based on file extension)
- Updates the file's entry in
_session.jsonwith the actual token count
Timeout: 5 seconds
post-write.js
Fires: After Claude writes, edits, or multi-edits a file. This is the most important hook.
Stdin: { "tool_name": "Write", "tool_input": { "file_path": "...", "content": "..." } }
What it does:
- Updates
anatomy.md: reads the written file, extracts a description, estimates tokens, upserts the entry in the correct directory section. Writes atomically (temp + rename). - Appends to
memory.md: logs the action with timestamp, file path, and token estimate. - Records in
_session.json: file, action type, tokens, timestamp.
Timeout: 10 seconds (longer because anatomy update involves file parsing)
stop.js
Fires: When Claude finishes a response.
What it does:
- Reads
_session.jsonfor accumulated session data - If there's been any activity (reads or writes):
- Builds a session entry with read/write totals
- Appends the session to
token-ledger.json - Updates lifetime counters
- Calculates estimated savings (anatomy hits + blocked repeated reads)
Note: The stop hook fires every time Claude finishes a response, not just at session end. It only writes to the ledger when there's significant data.
Timeout: 10 seconds
Session State (_session.json)
An ephemeral file in .wolf/hooks/ that tracks the current session:
{
"session_id": "session-2026-03-09-1430",
"started": "2026-03-09T14:30:00Z",
"files_read": {
"src/index.ts": { "count": 1, "tokens": 380, "first_read": "..." }
},
"files_written": [
{ "file": "src/api.ts", "action": "edit", "tokens": 620, "at": "..." }
],
"anatomy_hits": 4,
"anatomy_misses": 1,
"repeated_reads_warned": 1,
"cerebrum_warnings": 0,
"stop_count": 0
}This file is deleted and recreated on each SessionStart. It does not persist across sessions.