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 9 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 |
| 9 | permission-guard | PermissionRequest | Edit|Write|MultiEdit|Bash | hookSpecificOutput | 1s | Auto-allow safe .claude/ writes |
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"
PermissionRequest:Edit|Write|MultiEdit|Bash
└── permission-guard.sh Auto-allow safe .claude/ and /tmp paths
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.
9. permission-guard.sh
PermissionRequest hookSpecificOutputAuto-allows write operations to safe .claude/ subdirectories and temp paths,
eliminating manual permission prompts during task execution. Written in bash for minimal overhead.
| Parameter | Value |
|---|---|
| Event | PermissionRequest |
| Matcher | Edit|Write|MultiEdit|Bash |
| Channel | hookSpecificOutput (decision: allow) |
| Timeout | 1000 ms |
Allowed paths for Edit/Write/MultiEdit:
| Path pattern | Example |
|---|---|
.claude/tasks/* | .claude/tasks/20260301_auth_task/PLAN.md |
.claude/tmp/* | .claude/tmp/scratch.md |
.claude/reports/* | .claude/reports/review.md |
.claude/rules/* | .claude/rules/best-practice.md |
.claude/skills/* | .claude/skills/custom/SKILL.md |
.claude/scripts/* | .claude/scripts/build.sh |
.claude/agents/* | .claude/agents/reviewer.md |
.claude/hooks/* | .claude/hooks/hooks.json |
.claude/private/* | .claude/private/notes.md |
.claude/convention/* | .claude/convention/patterns.md |
.claude/plans/* | .claude/plans/LATEST.md |
.claude/settings.json | Project settings |
.claude/TASK.md, .claude/CLAUDE.md | Quick-ref files |
/tmp/*, /private/tmp/* | System temp directories |
Bash tool handling:
The hook applies additional safety checks for Bash commands:
- Network commands blocked:
curl,wget,ssh,scp,rsync,nc,ftp,sftp - Dangerous redirections blocked: writes to
/dev/,/etc/,eval,exec,source rmrestricted: only allowed within.claude/tasks/,.claude/tmp/, and/tmp/- Path extraction: all
.claude/and temp path tokens are verified against the allow-list
Global config excluded
The hook explicitly skips the global ~/.claude/ directory.
Only project-level .claude/ paths receive auto-allow.
Writes to ~/.claude/CLAUDE.md or ~/.claude/rules/ still require manual permission.
Decision logic:
| State | Action |
|---|---|
| Path in allowed list | allow — bypass permission prompt |
| Path outside allowed list | {} — fall through to default prompt |
| No file_path (non-matching tool) | {} — fall through |
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 |
Latest Release
Download, changelog, and installation instructions.
View on GitHub
Source code, README, and configuration files.