src/hooks/ -- ~54 Lifecycle Hooks Across 62 Dirs

September 2, 2026 · View on GitHub

Generated: 2026-07-17

OVERVIEW

54 base registered hooks on default config (61 with team-mode; monitor-status-injector adds 1 more with monitor.enabled → 62 max), composed from 54 index.ts hook dirs (52 wired; task-reminder/ and ralph-loop/ unwired) plus 5 standalone hook .ts files at the src/hooks/ top level (bash-file-read-guard, empty-task-response-detector, preemptive-compaction, session-notification, tool-output-truncator). The 62 directories = 54 with index.ts + 8 without (shared/, team-session-events/, hashline-edit-diff-enhancer/ unwired, and 5 zauc-mocks-*/zauc-sync-mocks). 5-tier composition wired in src/plugin/hooks/. All hooks follow createXXXHook(deps) -> HookFunction factory pattern.

Unwired WIP (do not modify casually): task-reminder/ (has index.ts + createTaskReminderHook but NOT exported from barrel, NOT imported by any composer), ralph-loop/ (exported from barrel but NOT imported by any composer; retained for migration, superseded by goal/), and hashline-edit-diff-enhancer/ (has only hook.ts, NOT registered). Treat as orphaned until wired in.

TIER COMPOSITION

TierComposerBaseWith team-modeWhere
Sessioncreate-session-hooks.ts2424OpenCode session lifecycle + chat.params + chat.message
Tool Guardcreate-tool-guard-hooks.ts1718Pre/post tool execution (+1: team-tool-gating)
Transformcreate-transform-hooks.ts46experimental.chat.messages.transform (+2: team-mode-status-injector, team-mailbox-injector; monitor-status-injector is a further +1 gated on monitor.enabled, not team-mode)
Continuationcreate-continuation-hooks.ts77Boulder/atlas/compaction/notification
Skillcreate-skill-hooks.ts22Skill awareness (categorySkillReminder, autoSlashCommand)
Direct event handlerssrc/plugin/event.ts0+4team-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, 62 with team-mode + monitor (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)

HookEventPurpose
preemptiveCompactionsession.idleTrigger compaction before limit
sessionNotificationsession.idleOS notifications on completion
thinkModechat.paramsModel variant switching for extended thinking
anthropicContextWindowLimitRecoverysession.errorMulti-strategy context recovery (truncation, compaction, dedup)
autoUpdateCheckersession.createdCheck npm for plugin updates
astGrepSgProvisionsession.createdProvision the ast-grep sg binary for the bundled skill
agentUsageReminderchat.messageRemind about available agents
nonInteractiveEnvchat.messageAdjust behavior for run command
interactiveBashSessiontool.executeTmux session lifecycle for interactive_bash tool
goaleventPersistent per-session objective; idle continuation + usage accounting. Replaces ralphLoop (see goal/AGENTS.md)
editErrorRecoverytool.execute.afterRetry failed file edits
delegateTaskRetrytool.execute.afterRetry failed task delegations
ulwExecutechat.message/ulw-execute command handler
prometheusMdOnlytool.execute.beforeEnforce .md-only writes for Prometheus
sisyphusJuniorNotepadchat.messageNotepad injection for subagents
questionLabelTruncatortool.execute.beforeTruncate long Question tool labels
taskResumeInfochat.messageInject task context on resume
modelFallbackchat.paramsProvider-level proactive model fallback
noSisyphusGptchat.messageBlock Sisyphus from non-GPT providers (with warning toast)
noHephaestusNonGptchat.messageBlock Hephaestus from non-GPT models
hephaestusAgentsMdInjectorchat.messageInject walk-up AGENTS.md context for Hephaestus deep-work sessions
runtimeFallbackeventReactive auto-switch on API provider errors
legacyPluginToastchat.messageShow toast when legacy plugin name detected

Tier 2: Tool Guard Hooks (17)

HookEventPurpose
commentCheckertool.execute.afterBlock AI-slop comment patterns (binary: @code-yeongyu/comment-checker)
toolOutputTruncatortool.execute.afterTruncate oversized tool output
directoryAgentsInjectortool.execute.beforeInject dir-local AGENTS.md into context
directoryReadmeInjectortool.execute.beforeInject dir-local README.md into context
emptyTaskResponseDetectortool.execute.afterDetect empty task results
rulesInjectortool.execute.beforeConditional rules injection (AGENTS.md, .rules)
tasksTodowriteDisablertool.execute.beforeDisable TodoWrite when Sisyphus task system active
writeExistingFileGuardtool.execute.beforeRequire Read before Write/Edit on existing files
bashFileReadGuardtool.execute.beforeGuard bash commands that read files (cat/head/tail)
readImageResizertool.execute.afterResize large images for context efficiency
todoDescriptionOverridetool.execute.beforeOverride todo item descriptions
webfetchRedirectGuardtool.execute.beforeGuard webfetch redirect behavior
hashlineReadEnhancertool.execute.afterTag every Read output with LINE#ID content hashes
jsonErrorRecoverytool.execute.afterDetect JSON parse errors, inject correction reminder
fsyncSkipWarningtool.execute.afterWarn when fsync is skipped for atomic writes
notepadWriteGuardtool.execute.beforeBlock Write to append-only notepad paths (.omo/notepads, .sisyphus/notepads)
planFormatValidatortool.execute.beforeValidate plan/todo checkbox format on Write/Edit of boulder plans

Tier 3: Transform Hooks (4 base + 1 monitor-gated)

HookEventPurpose
claudeCodeHooksmessages.transformClaude Code settings.json compatibility
keywordDetectormessages.transformDetect ultrawork/search/analyze/team modes; inject mode-specific prompt
contextInjectorMessagesTransformmessages.transformInject AGENTS.md/README.md into context
toolPairValidatormessages.transformValidate tool call/result pairing
monitorStatusInjectormessages.transformInject running Monitor watch status into context (monitor.enabled)

Tier 4: Continuation Hooks (7)

HookEventPurpose
stopContinuationGuardchat.message/stop-continuation command handler
compactionContextInjectorsession.compactedRe-inject context after compaction
compactionTodoPreserversession.compactedPreserve todos through compaction
todoContinuationEnforcersession.idleBoulder -- force continuation on incomplete todos
unstableAgentBabysittersession.idleMonitor unstable agent behavior
backgroundNotificationHookeventBackground task completion notifications
atlasHookeventMaster orchestrator for boulder/background sessions

Tier 5: Skill Hooks (2)

HookEventPurpose
categorySkillReminderchat.messageHint to load skills before invoking categories
autoSlashCommandchat.messageAuto-execute matching /command from user message

Team-mode Hooks (conditional, only when team_mode.enabled: true)

HookTierRegistered InPurpose
team-mode-status-injectorTransformcreate-transform-hooks.tsInject <team_mode_status> block into messages
team-mailbox-injectorTransformcreate-transform-hooks.tsPull pending team mailbox messages into agent context
team-tool-gatingTool Guardcreate-tool-guard-hooks.tsRestrict team_* tools based on member role + permissions
team-idle-wake-hintevent handlersrc/plugin/event.tsNudge idle team members back to work
team-lead-orphan-handlerevent handlersrc/plugin/event.tsDetect lead departure → orphan members
team-member-error-handlerevent handlersrc/plugin/event.tsReact to member session errors
team-member-status-handlerevent handlersrc/plugin/event.tsTrack member status transitions

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

hooks/
├── shared/                                  # Cross-hook helpers (timing, prompt builders, etc.)
├── team-session-events/                     # 4 team event handlers (wired via src/plugin/event.ts)
├── (54 index.ts hook directories incl. `task-reminder/` and `ralph-loop/` unwired -- see tier tables above)
├── zauc-mocks-{bg,cache,hook,ws}, zauc-sync-mocks  # 5 test mocks (NOT hooks; named for sort-order isolation)
└── (each hook dir)/
    ├── index.ts        # createXXXHook factory + barrel
    ├── *.ts            # implementation
    └── *.test.ts       # bun:test

ADDING A NEW HOOK

  1. mkdir src/hooks/{name} + index.ts exporting createXXXHook(deps)
  2. 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
  3. Add hook name to config/schema/hooks.ts HookNameSchema
  4. 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.
  • goal replaces ralphLoop (PR #6184): ralphLoop was removed from HookNameSchema and create-session-hooks.ts; the /ralph-loop, /ulw-loop, /cancel-ralph builtin commands were removed. The ralph-loop/ dir + createRalphLoopHook factory remain for migration (barrel export kept); ralph_loop config is a deprecated passthrough. See goal/AGENTS.md.