Hooks
Genie’s hook system intercepts Claude Code events to add orchestration capabilities. Hooks run as a chain-of-responsibility — each handler can allow, deny, or modify the tool use before it executes.
How Hooks Work
Claude Code fires events at specific lifecycle points. Genie registers a hook command (genie hook dispatch) that receives JSON on stdin, routes to matching handlers, and returns a JSON decision on stdout.
Event Types
Handler Chain
For blocking events, handlers run in priority order (lower = first):
- If any handler returns
deny → short-circuit, return immediately
- If a handler returns
updatedInput → merge into payload for next handler
- If a handler returns
allow or void → continue to next handler
Built-in Handlers
identity-inject (Priority: 10)
Event: PreToolUse:SendMessage
Injects [from:<agent-name>] into SendMessage content so recipients always know who sent the message, even across teams.
The agent name comes from GENIE_AGENT_NAME environment variable, set automatically by genie spawn.
auto-spawn (Priority: 20)
Event: PreToolUse:SendMessage
When an agent sends a message to a recipient that doesn’t have a live tmux pane, this handler respawns them from their saved template.
Resolution order:
- Check agent registry for live pane → skip if alive
- Check agent directory for recipient identity
- Check saved spawn templates → spawn from template
This enables “self-healing” teams — if an agent crashes, sending it a message automatically restarts it.
Event: PreToolUse (all tools)
Publishes tool call events to genie.tool.{agent}.call on NATS. Fire-and-forget.
nats-emit-msg (Priority: 30)
Event: PostToolUse:SendMessage
Publishes message delivery events to genie.msg.{recipient} on NATS.
nats-emit-user-prompt (Priority: 30)
Event: UserPromptSubmit
Publishes user prompt events to genie.user.{agent}.prompt on NATS.
nats-emit-assistant-response (Priority: 30)
Event: Stop
Publishes assistant response events to genie.agent.{agent}.response on NATS.
branch-guard
Event: PreToolUse
Prevents agents from committing or pushing to protected branches (main, master). Returns deny if the current branch is protected and the tool is a git write operation.
Hook Payload
The JSON payload sent to hook handlers:
Hook Response
Handlers return a decision object:
Registration
Hooks are registered in Claude Code’s settings:
Gotchas
15-second hard timeout — Hook dispatch has a 15-second timeout. Handlers that take longer silently timeout, blocking the tool use. No retry is attempted.
- GENIE_AGENT_NAME must be set for identity injection and auto-spawn to work. This is set automatically by
genie spawn but must be manually set if running agents outside Genie.
- NATS handlers degrade silently — if NATS is unavailable, events are simply dropped. No error is raised.
- Auto-spawn has a 15-second ready timeout — if the spawned agent doesn’t reach idle within 15 seconds, the message is queued for later delivery.