Caelan's Domain

Hooks - The Event System

Created: March 29, 2026 | Modified: March 29, 2026

This is Part 10 of a 10-part series on cAgents. Previous: Sessions - Under the Hood | First: Getting Started with cAgents


The previous article covered sessions - the static record of what happened. This article covers hooks - the live machinery that runs while a pipeline is executing.

Hooks are how cAgents reacts to events in real time: tracking which agents are running, catching dangerous commands before they execute, saving state before context gets compacted, and coordinating teams of parallel agents. Sessions record what happened. Hooks make it happen.

Claude Code fires events at specific moments - when a session starts, when a tool is about to be used, when a subagent spawns, when context gets compacted. cAgents registers hook scripts that run in response to these events. It's an event-driven architecture that keeps the orchestration layer informed without requiring the agents themselves to report back.


How Hooks Work

Hooks are configured in settings.json. Each hook maps an event type to a script. When Claude Code fires the event, it runs the script and passes context via stdin as JSON. The script can return instructions that modify Claude Code's behavior - blocking a tool call, injecting context, or logging state.

Here's what a hook registration looks like:

"PreToolUse": [
  {
    "matcher": "Bash",
    "hooks": [
      {
        "type": "command",
        "command": "bash -c '... node \"$R/.claude/hooks/run-hook.cjs\" bash-validator'",
        "timeout": 5
      }
    ]
  }
]

Three things to notice:

  1. matcher filters which tool triggers the hook. This one only fires when a Bash command is about to run. Other matchers target Write, Edit, Task, or any tool name.
  2. timeout prevents hung hooks from blocking the pipeline. Five seconds is typical - hooks should be fast.
  3. run-hook.cjs is a launcher that dispatches to the right hook script. The argument (bash-validator) tells it which hook to run.
Hooks run as Node.js scripts (.cjs files) via the run-hook.cjs launcher. This is a cAgents convention, not a Claude Code requirement - Claude Code hooks can be any executable command. cAgents uses the launcher pattern to keep registration clean.

Event Types

cAgents hooks into every major event type Claude Code exposes. Here's the full map, grouped by when they fire.

Session Lifecycle

Event When It Fires cAgents Hook
SessionStart Session begins session-catchup.cjs - restores state from incomplete sessions
SessionEnd Session ends team-stop.cjs - cleans up team processes
Stop Agent stops verify-completion.cjs - checks execution_summary.yaml exists
StopFailure Agent fails to stop stop-failure-handler.cjs - saves recovery state

Agent Lifecycle

Event When It Fires cAgents Hook
SubagentStart Subagent spawns subagent-tracker.cjs - registers in agent_tree.yaml
SubagentStop Subagent finishes subagent-stop-tracker.cjs - records completion summary
TeammateIdle Team member idle teammate-idle-handler.cjs - reassigns or stops idle teammates
TaskCompleted Task finishes team-task-complete.cjs - triggers next wave

Tool Guards

Event When It Fires cAgents Hook
PreToolUse (Bash) Before shell command bash-validator.cjs - blocks dangerous commands
PreToolUse (Write/Edit) Before file write secret-detection.cjs - prevents committing secrets
PreToolUse (Write/Edit/Bash) Before mutation attention-injection.cjs - injects context reminders
PreToolUse (Write/Edit/Bash) Before mutation approval-gate.cjs - enforces approval for sensitive ops
PreToolUse (Task) Before agent spawn session-init-gate.cjs - ensures session exists first
PreToolUse (Task) Before agent spawn model-routing-advisor.cjs - recommends optimal model
PostToolUse (Write/Edit) After file write post-write-validator.cjs - validates written content
PostToolUseFailure After tool fails tool-failure-tracker.cjs - logs failures for self-correction

Context Management

Event When It Fires cAgents Hook
PreCompact Before context compression pre-compact-save.cjs - saves workflow state to disk
PostCompact After context compression post-compact-restore.cjs - restores critical context
InstructionsLoaded Instructions loaded instructions-loaded.cjs - validates instruction integrity

User Interaction

Event When It Fires cAgents Hook
UserPromptSubmit User sends message delegation-enforcer.cjs - prevents /run from self-handling
UserPromptSubmit User sends message magic-keywords.cjs - detects special command patterns
PermissionRequest Permission needed permission-handler.cjs - auto-grants safe permissions
Notification Notification fired notification.cjs - routes notifications to correct session

That's over 20 hooks across 15+ event types. Each one is a small, focused script that does one thing - but together they form the coordination layer that makes multi-agent pipelines work reliably.


Key Hooks in Detail

Five hooks that do the most important work:

subagent-tracker.cjs

Every time a subagent spawns, this hook writes an entry to agent_tree.yaml in the session directory. It captures the agent's ID, type, parent relationship, role, and spawn timestamp. When the agent finishes, the companion hook subagent-stop-tracker.cjs appends its completion summary.

This is the hook that builds the audit trail from Part 9. Without it, the session would know what was requested and what state the pipeline reached, but not which agents did the work or when they ran. Every entry in agent_tree.yaml exists because this hook wrote it.

pre-compact-save.cjs and post-compact-restore.cjs

Long pipelines can exceed Claude Code's context window. When that happens, Claude Code compresses the context - summarizing earlier conversation to make room for new work. That compression is useful, but it can lose critical state: which task is in progress, what's been completed, what files were changed, what the plan says to do next.

pre-compact-save.cjs fires before compression and writes the current workflow state to the session directory - plan progress, active tasks, file change list, and any in-flight coordination data. After compression, post-compact-restore.cjs reads that state back and injects the critical bits into the fresh context.

This pair is why pipelines can survive context compression without losing their place. The agent might not remember the full conversation history, but it knows exactly where it is in the plan and what to do next.

bash-validator.cjs

This hook intercepts every Bash command before execution. It checks the command against a set of safety rules - blocking destructive operations like rm -rf /, sudo commands that could modify system state, and other patterns that could damage the host system or the project.

The safety net matters because agents run shell commands frequently - installing dependencies, running builds, checking file state, executing tests. Most of those commands are fine. The validator's job is to catch the rare ones that aren't, before they execute. It's a PreToolUse hook, so it can block the command entirely and return an error message to the agent explaining why.

delegation-enforcer.cjs

This one enforces the architectural pattern that makes cAgents work. The /run pipeline is supposed to delegate work to specialist agents - planners plan, executors execute, validators validate. But the pipeline agent itself is a capable Claude instance. Without guardrails, it might decide to skip delegation and just write the code directly.

delegation-enforcer.cjs catches this. It monitors UserPromptSubmit events and checks whether /run is attempting to do work itself instead of spawning agents. If it detects self-handling, it intervenes with a reminder to delegate. It's the architectural enforcement that keeps the multi-agent pattern honest.

verify-completion.cjs

This hook fires when an agent stops and checks whether execution_summary.yaml was written to the session directory. A properly completed pipeline always writes a summary - it's the last step before VALIDATED. If the summary is missing, the pipeline ended abnormally: it was interrupted, errored out, or the agent stopped without finishing.

The hook flags incomplete sessions so you know to investigate or resume them. If it fires, just ask Claude "what happened with that last run?" - it can read the session files, diagnose what went wrong, and resume from where things stopped. Without this hook, a silently failed pipeline could look like it simply finished.


The Launcher Pattern

You might have noticed that the hook registration points to run-hook.cjs with the actual hook name as an argument, rather than pointing directly to each hook script. This is deliberate.

Instead of registering 20+ separate commands in settings.json - each with its own path, timeout, and configuration - cAgents uses a single launcher script that takes the hook name as an argument and dispatches to the right .cjs file. The launcher handles common setup (reading stdin JSON, loading the session context, error handling) so individual hooks can focus on their specific logic.

This keeps settings.json clean and makes it easy to add new hooks. Write a new .cjs file, add one line to the launcher's dispatch table, and register one entry in settings.json. The alternative - 20+ separate command entries with duplicated paths and timeouts - would be a maintenance headache.

You can see all registered hooks by checking your project's settings.json. In Claude Code, hooks from plugins appear alongside your own custom hooks, and you can add your own using the same event types.

Wrapping Up the Series

The hook system is what turns cAgents from a collection of agents into an actual orchestration framework. Sessions record what happened. Hooks make it happen in real time - tracking, guarding, saving, restoring, and coordinating across every event in the pipeline.

This is the final article in the series. You've gone from installation through every command and now understand the infrastructure underneath. If you want to dig deeper, the cAgents source is open. The full series:

Part 1: Getting Started | Part 2: /designer | Part 3: /run | Part 4: /team | Part 5: /org | Part 6: /optimize | Part 7: /debug | Part 8: /review | Part 9: Sessions | Part 10: Hooks


Series navigation: Previous: Sessions - Under the Hood | First: Getting Started with cAgents