Hooks
Hooks (processes) are Node.js scripts attached to Claude Code lifecycle events.
They manage context, inject knowledge into agents, block exit when a task is still active,
and ensure progress transfer between sessions. Brewcode registers 8 hooks in hooks.json.
Summary table
| # | Hook | Event | Matcher | Channel | Timeout | Purpose |
|---|---|---|---|---|---|---|
| 1 | forced-eval | UserPromptSubmit | — | updatedInput | 1s | Skill activation (84%) |
| 2 | session-start | SessionStart | — | additionalContext | 3s | Session initialization, LATEST.md |
| 3 | grepai-session | SessionStart | — | systemMessage | 5s | Auto-start grepai watch |
| 4 | pre-task | PreToolUse | Task | additionalContext, updatedInput | 5s | Knowledge injection into agents |
| 5 | grepai-reminder | PreToolUse | Glob|Grep | additionalContext | 1s | grepai_search reminder |
| 6 | post-task | PostToolUse | Task | additionalContext | 5s | Session binding, 2-step protocol |
| 7 | pre-compact | PreCompact | — | — | 60s | Compaction, handoff |
| 8 | stop | Stop | — | decision | 5s | Exit blocking, lock cleanup |
Execution flow
UserPromptSubmit
└── forced-eval.mjs [SKILL?] Check available skills
SessionStart
├── session-start.mjs Session ID, LATEST.md symlink, handoff
└── grepai-session.mjs Auto-start grepai watch
PreToolUse:Task
└── pre-task.mjs grepai + KNOWLEDGE + phase context -> agent prompt
PreToolUse:Glob|Grep
└── grepai-reminder.mjs "USE grepai_search FIRST"
PostToolUse:Task
└── post-task.mjs Session bind, coordinator reminder
PreCompact
└── pre-compact.mjs Compact KNOWLEDGE, write handoff, status update
Stop
└── stop.mjs Block if active task, cleanup lock
I/O protocol
All hooks follow a unified protocol:
- Read JSON from stdin (via
readStdin()) - Receive fields:
session_id,cwd,source(SessionStart),tool_input(PreToolUse/PostToolUse) - Output JSON to stdout (via
output()) - Write logs to stderr and to the file
.claude/tasks/logs/brewcode.log
Shared utilities:
hooks/lib/utils.mjs— I/O, lock files, configuration, logging, task parsinghooks/lib/knowledge.mjs— KNOWLEDGE.jsonl read/write, compaction, handoff
Detailed description
1. forced-eval.mjs
UserPromptSubmit updatedInputBoosts skill activation from ~20-50% to ~84%. Intercepts every user prompt and adds a reminder to check available skills.
| Parameter | Value |
|---|---|
| Event | UserPromptSubmit |
| Channel | updatedInput (prompt) |
| Timeout | 1000 ms |
What it does:
- Receives the user prompt
- Adds a prefix:
[SKILL?] Check available skills. If one matches this request, use Skill tool before responding. - Returns the modified prompt via
updatedInput
When it fires: On every user input, except events with an incorrect hook_event_name.
2. session-start.mjs
SessionStart additionalContextInitializes the session, logs the session ID, and manages Plan Mode symlinks.
| Parameter | Value |
|---|---|
| Event | SessionStart |
| Channel | additionalContext |
| Timeout | 3000 ms |
Logic by session source:
| Source | Behavior |
|---|---|
init | Log session_id |
resume | Log session_id |
clear | Create symlink LATEST.md -> newest plan |
compact + active task | Handoff instructions in additionalContext |
LATEST.md symlink:
- Checks
~/.claude/plans/for.mdfiles - Picks the newest one (by mtime)
- If the file is less than 60 seconds old — creates
.claude/plans/LATEST.md->~/.claude/plans/<newest>.md - Used by the
/brewcode:planskill for Plan Mode
3. grepai-session.mjs
SessionStart systemMessageAutomatically starts grepai watch when entering a project with a configured .grepai/.
| Parameter | Value |
|---|---|
| Event | SessionStart |
| Channel | systemMessage |
| Timeout | 5000 ms |
Logic:
- If
.grepai/does not exist — skips silently - If
.grepai/exists — checks ollama, index, watch process, MCP - If watch is not running — starts it automatically
- Reports status via
systemMessage
Safety
This hook never blocks session start. All errors are handled as informational. Platform: macOS/Linux only (Windows not supported due to missing pgrep).
4. pre-task.mjs
PreToolUse:Task additionalContext + updatedInputInjects context into the subagent prompt before every Task tool call.
| Parameter | Value |
|---|---|
| Event | PreToolUse |
| Matcher | Task |
| Channel | additionalContext, updatedInput |
| Timeout | 5000 ms |
What it injects:
| Component | Condition | Channel |
|---|---|---|
| grepai reminder | .grepai/ exists | additionalContext |
| ## K (knowledge) | brewcode lock active, not a system agent | updatedInput.prompt |
| v3 phase context | phases/ exists | updatedInput.prompt |
| BC_PLUGIN_ROOT | Always | updatedInput.prompt |
Knowledge compression: KNOWLEDGE.jsonl is compressed to maxTokens (default 500 tokens)
via compressKnowledge() — priority ❌ > ✅ > ℹ️.
System agents (Explore, Plan, general-purpose) do not receive the ## K injection.
5. grepai-reminder.mjs
PreToolUse:Glob|Grep additionalContextReminds to use grepai_search instead of direct Glob/Grep.
| Parameter | Value |
|---|---|
| Event | PreToolUse |
| Matcher | Glob|Grep |
| Channel | additionalContext |
| Timeout | 1000 ms |
Throttling: The reminder is shown at most once per 60 seconds (via timestamp file .grepai/.reminder-ts).
Condition: Only fires if .grepai/ and .grepai/index.gob exist.
6. post-task.mjs
PostToolUse:Task additionalContextHandles the Task tool result: binds the session and reminds about the 2-step protocol.
| Parameter | Value |
|---|---|
| Event | PostToolUse |
| Matcher | Task |
| Channel | additionalContext |
| Timeout | 5000 ms |
Logic:
- If bc-coordinator finished — binds session_id to the lock file
- If a worker agent finished (developer, tester, etc.) — reminds: “WRITE report -> CALL bc-coordinator”
- System agents — skipped
7. pre-compact.mjs
PreCompact knowledge managementFires before Claude Code’s automatic context compaction. Saves progress and prepares data for continuation after compact.
| Parameter | Value |
|---|---|
| Event | PreCompact |
| Channel | — |
| Timeout | 60000 ms (1 minute) |
Actions:
- Lock file check (brewcode active + belongs to this session)
- KNOWLEDGE.jsonl compaction (deduplication, trimming)
- Handoff entry written to KNOWLEDGE.jsonl
- Task status updated ->
handoff
Session ID does not change
Claude Code auto-compact compresses context within the same session.
The session_id stays identical before and after compact. The lock file is not released.
Status handoff means “re-read TASK.md”, not “new session”.
8. stop.mjs
Stop decisionControls session exit: blocks when a task is active, cleans up the lock when finished.
| Parameter | Value |
|---|---|
| Event | Stop |
| Channel | decision |
| Timeout | 5000 ms |
Terminal statuses: finished, cancelled, failed, error.
Logic:
| State | Action |
|---|---|
| No lock file | Allow exit |
| Lock older than 24 hours | Delete lock, allow exit |
| Task in terminal status | Delete lock, allow exit |
| Task is active | Block exit |
Exit blocking
If a task is active (status not in the terminal set), the hook blocks exit
from Claude Code. To finish a task, use /brewcode:start for finalization
or set the task status to finished/failed/cancelled.
Recursion protection: If input.stop_hook_active === true, the hook is skipped
to prevent an infinite loop.
Configuration
Hooks read settings from .claude/tasks/cfg/brewcode.config.json:
| Parameter | Default value | Description |
|---|---|---|
knowledge.maxEntries | 100 | Maximum entries in KNOWLEDGE.jsonl |
knowledge.maxTokens | 500 | Maximum tokens in the ## K block for agents |
logging.level | info | Logging level (error/warn/info/debug/trace) |
agents.system | (list) | System agents excluded from knowledge injection |
autoSync.intervalDays | 7 | Auto-sync interval |