src/hooks/ — ~52 Lifecycle Hooks Across 58 Dirs
Generated: 2026-05-15
OVERVIEW
52 hooks (5 of the 58 dirs are zauc-mocks-* test scaffolds + 1 shared/). 5-tier composition wired in src/plugin/hooks/. All hooks follow createXXXHook(deps) → HookFunction factory pattern.
TIER COMPOSITION
| Tier |
Composer |
Base |
With team-mode |
Where |
| Session |
create-session-hooks.ts |
24 |
24 |
OpenCode session lifecycle + chat.params + chat.message |
| Tool Guard |
create-tool-guard-hooks.ts |
16 |
17 |
Pre/post tool execution (+1: team-tool-gating) |
| Transform |
create-transform-hooks.ts |
5 |
7 |
experimental.chat.messages.transform (+2: team-mode-status-injector, team-mailbox-injector) |
| Continuation |
create-continuation-hooks.ts |
7 |
7 |
Boulder/atlas/compaction/notification |
| Skill |
create-skill-hooks.ts |
2 |
2 |
Skill awareness (categorySkillReminder, autoSlashCommand) |
| Direct event handlers |
src/plugin/event.ts |
0 |
+4 |
team-session-events/ sub-files: team-idle-wake-hint, team-lead-orphan-handler, team-member-error-handler, team-member-status-handler |
Total exposed hooks: 54 base, 61 with team-mode (counts the 4 team-session-events handlers individually).
Hook name allowlist for disabled_hooks: all configurable hook names enumerated in src/config/schema/hooks.ts HookNameSchema. Team-session-event sub-hooks are not individually listed in the schema — they activate together with team_mode.enabled.
Tier 1: Session Hooks (24)
| Hook |
Event |
Purpose |
contextWindowMonitor |
session.idle |
Track context usage |
preemptiveCompaction |
session.idle |
Trigger compaction before limit |
sessionRecovery |
session.error |
Recover from structural errors (tool_result_missing, thinking_block_order) |
sessionNotification |
session.idle |
OS notifications on completion |
thinkMode |
chat.params |
Model variant switching for extended thinking |
anthropicContextWindowLimitRecovery |
session.error |
Multi-strategy context recovery (truncation, compaction, dedup) |
autoUpdateChecker |
session.created |
Check npm for plugin updates |
agentUsageReminder |
chat.message |
Remind about available agents |
nonInteractiveEnv |
chat.message |
Adjust behavior for run command |
interactiveBashSession |
tool.execute |
Tmux session lifecycle for interactive_bash tool |
ralphLoop |
event |
Self-referential dev loop (boulder continuation) |
editErrorRecovery |
tool.execute.after |
Retry failed file edits |
delegateTaskRetry |
tool.execute.after |
Retry failed task delegations |
startWork |
chat.message |
/start-work command handler |
prometheusMdOnly |
tool.execute.before |
Enforce .md-only writes for Prometheus |
sisyphusJuniorNotepad |
chat.message |
Notepad injection for subagents |
questionLabelTruncator |
tool.execute.before |
Truncate long Question tool labels |
taskResumeInfo |
chat.message |
Inject task context on resume |
anthropicEffort |
chat.params |
Adjust reasoning effort level |
modelFallback |
chat.params |
Provider-level proactive model fallback |
noSisyphusGpt |
chat.message |
Block Sisyphus from non-GPT providers (with warning toast) |
noHephaestusNonGpt |
chat.message |
Block Hephaestus from non-GPT models |
runtimeFallback |
event |
Reactive auto-switch on API provider errors |
legacyPluginToast |
chat.message |
Show toast when legacy plugin name detected |
Tier 2: Tool Guard Hooks (16)
| Hook |
Event |
Purpose |
commentChecker |
tool.execute.after |
Block AI-slop comment patterns (binary: @code-yeongyu/comment-checker) |
toolOutputTruncator |
tool.execute.after |
Truncate oversized tool output |
directoryAgentsInjector |
tool.execute.before |
Inject dir-local AGENTS.md into context |
directoryReadmeInjector |
tool.execute.before |
Inject dir-local README.md into context |
emptyTaskResponseDetector |
tool.execute.after |
Detect empty task results |
rulesInjector |
tool.execute.before |
Conditional rules injection (AGENTS.md, .rules) |
tasksTodowriteDisabler |
tool.execute.before |
Disable TodoWrite when Sisyphus task system active |
writeExistingFileGuard |
tool.execute.before |
Require Read before Write/Edit on existing files |
bashFileReadGuard |
tool.execute.before |
Guard bash commands that read files (cat/head/tail) |
readImageResizer |
tool.execute.after |
Resize large images for context efficiency |
todoDescriptionOverride |
tool.execute.before |
Override todo item descriptions |
webfetchRedirectGuard |
tool.execute.before |
Guard webfetch redirect behavior |
hashlineReadEnhancer |
tool.execute.after |
Tag every Read output with LINE#ID content hashes |
jsonErrorRecovery |
tool.execute.after |
Detect JSON parse errors, inject correction reminder |
fsyncSkipWarning |
tool.execute.after |
Warn when fsync is skipped for atomic writes |
Tier 3: Transform Hooks (5)
| Hook |
Event |
Purpose |
claudeCodeHooks |
messages.transform |
Claude Code settings.json compatibility |
keywordDetector |
messages.transform |
Detect ultrawork/search/analyze/team modes; inject mode-specific prompt |
contextInjectorMessagesTransform |
messages.transform |
Inject AGENTS.md/README.md into context |
thinkingBlockValidator |
messages.transform |
Validate thinking block structure |
toolPairValidator |
messages.transform |
Validate tool call/result pairing |
Tier 4: Continuation Hooks (7)
| Hook |
Event |
Purpose |
stopContinuationGuard |
chat.message |
/stop-continuation command handler |
compactionContextInjector |
session.compacted |
Re-inject context after compaction |
compactionTodoPreserver |
session.compacted |
Preserve todos through compaction |
todoContinuationEnforcer |
session.idle |
Boulder — force continuation on incomplete todos |
unstableAgentBabysitter |
session.idle |
Monitor unstable agent behavior |
backgroundNotificationHook |
event |
Background task completion notifications |
atlasHook |
event |
Master orchestrator for boulder/background sessions |
Tier 5: Skill Hooks (2)
| Hook |
Event |
Purpose |
categorySkillReminder |
chat.message |
Hint to load skills before invoking categories |
autoSlashCommand |
chat.message |
Auto-execute matching /command from user message |
Team-mode Hooks (conditional, only when team_mode.enabled: true)
The 4 team-session-events/ handlers live in src/hooks/team-session-events/ (separate files: team-idle-wake-hint.ts, team-lead-orphan-handler.ts, team-member-error-handler.ts, team-member-status-handler.ts) and are wired into src/plugin/event.ts directly, not through a tier composer.
STRUCTURE
ADDING A NEW HOOK
mkdir src/hooks/{name} + index.ts exporting createXXXHook(deps)
- Pick the right tier:
- Session lifecycle? →
create-session-hooks.ts
- Pre/post tool? →
create-tool-guard-hooks.ts
- Message transform? →
create-transform-hooks.ts
- Continuation/idle? →
create-continuation-hooks.ts
- Skill awareness? →
create-skill-hooks.ts
- Team-mode-only? → register inside the team-mode conditional block
- Add hook name to
config/schema/hooks.ts HookNameSchema
- Cover with co-located
*.test.ts (given/when/then style)
NOTES
- Tier order matters within a phase: within Session tier the registration order in
create-session-hooks.ts determines invocation order — earlier hooks see un-mutated input, later hooks see accumulated output.
- Mock files (
zauc-mocks-*, zauc-sync-mocks) are NOT hooks. They are placed inside src/hooks/ purely so bun:test discovers them with the hook test fixtures.
atlasHook vs todoContinuationEnforcer: atlas handles boulder/ralph/subagent sessions, todoContinuationEnforcer handles the main Sisyphus session. Both fire on session.idle but check session type first.
runtime-fallback vs model-fallback: runtime-fallback is reactive (after error); model-fallback is proactive (chat.params). They operate independently.