Chimera’s hook system lets external code react to lifecycle events that fire during an agent run. Events are dispatched by HookEmitter, executed by HookExecutor, and matched against HookMatcher records loaded from .claude/settings.json (or ~/.claude/settings.json).
This page is the full event reference for every wired event. The 27 events are organised below by phase: tool, session, sub-agent, compaction, permission, task, CLI, and filesystem.
Event Trigger Wired in Payload PreToolUseBefore each tool dispatch. May mutate input or deny. chimera/core/tool_executor.py (3 executors)tool_name, tool_inputPostToolUseAfter a tool returns successfully. chimera/core/tool_executor.py (3 executors)tool_name, tool_input, tool_outputPostToolUseFailureAfter a tool raises or returns success=False. chimera/core/tool_executor.py (3 executors)tool_name, tool_input, tool_error
Event Trigger Wired in Payload UserPromptSubmitFirst loop step when context carries a user message. chimera/core/loop.py (sync + async); chimera/commands/processor.py for /-commandsuser_promptSessionStartFirst instruction of iter_steps / async_iter_steps. chimera/core/loop.py; chimera/core/agent_loop.py— SessionEndLast instruction on every termination path of the loop. chimera/core/loop.py; chimera/core/agent_loop.py— StopLoop exited cleanly (no further tool calls). chimera/core/loop.py; chimera/core/agent_loop.py— StopFailureLoop terminated abnormally (cost limit, max steps, loop break, cancellation). chimera/core/loop.py; chimera/core/agent_loop.pytool_errorNotificationFires alongside Stop carrying the agent’s final text. chimera/core/loop.py; chimera/core/agent_loop.pytool_output
Event Trigger Wired in Payload SubagentStartJust before a sub-agent’s first turn. chimera/core/agent_spawner.pytool_name (subagent name)SubagentStopAfter a sub-agent finishes. chimera/core/agent_spawner.pytool_name, tool_outputTeammateIdleWhen a sub-agent goes idle awaiting input. chimera/core/agent_spawner.pytool_name
Event Trigger Wired in Payload PreCompactBefore context compaction runs. chimera/core/compaction_integration.py— PostCompactAfter context compaction completes. chimera/core/compaction_integration.py—
Event Trigger Wired in Payload PermissionRequestWhen the permission checker asks for a decision. chimera/permissions/checker.pytool_name, tool_inputPermissionDeniedWhen the permission checker denies a tool. chimera/permissions/checker.pytool_name, tool_inputElicitationBefore an interactive permission prompt. chimera/permissions/prompt_handler.py— ElicitationResultAfter an interactive permission prompt resolves. chimera/permissions/prompt_handler.py—
Event Trigger Wired in Payload TaskCreatedWhen the task manager creates a new task. chimera/core/task_manager.pytool_name (task subject)TaskCompletedWhen the task manager marks a task done. chimera/core/task_manager.pytool_name (task subject)
Event Trigger Wired in Payload SetupOnce at CLI startup, after settings are loaded. chimera/cli/main.pytool_name (subcommand)ConfigChangeWhen ~/.claude/settings.json is written through the mink CLI. chimera/mink/settings.py—
Event Trigger Wired in Payload WorktreeCreateAfter EnterWorktree succeeds. chimera/tools/worktree_tool.pytool_input (path, branch)WorktreeRemoveAfter ExitWorktree succeeds (or fails). chimera/tools/worktree_tool.pytool_input
Event Trigger Wired in Payload InstructionsLoadedWhen CLAUDE.md / AGENTS.md files are picked up. chimera/context/agent_memory.py; chimera/otter/rules.pymessages (loaded files)CwdChangedWhen the file watcher detects a working-directory change. chimera/hooks/file_watcher.py— FileChangedWhen the file watcher detects a tracked-file edit. chimera/hooks/file_watcher.pytool_input (path)
Hooks are declared per-project in .claude/settings.json under the hooks key. Each event maps to a list of matchers; each matcher carries a list of command, prompt, or function hooks.
"matcher" : " tool_name == 'bash' " ,
{ "type" : " command " , "command" : " scripts/audit-bash.sh " }
{ "hooks" : [{ "type" : " command " , "command" : " scripts/notify-done.sh " }]}
"matcher" : " tool_name == 'write_file' and 'production' in tool_input.get('path', '') " ,
"hooks" : [{ "type" : " command " , "command" : " scripts/audit-prod-write.sh " }]
The matcher string is evaluated against a small Python expression context with tool_name, tool_input, tool_output, tool_error, user_prompt, and messages bound from the HookInput.
The mink CLI parses these files in order and merges them into the HookEmitter carried on LoopConfig.hook_emitter:
~/.claude/settings.json
<cwd>/.claude/settings.json
<cwd>/.claude/settings.local.json
<cwd>/.chimera/settings.json
Later sources override earlier ones key-by-key.
Add the value to HookEvent in chimera/hooks/events.py .
Wire an emitter.emit(...) call (or emit_sync(...) for sync code paths) at the canonical trigger point. For loop-lifecycle events, call _fire_loop_hook / _fire_loop_hook_async from chimera/core/loop.py so failures never break the loop.
Add a row to one of the tables above documenting the trigger and payload.
Add a recording-emitter test under tests/events/test_hook_events.py that fires a minimal agent flow and asserts the new event appears.
Chimera installed: pip install chimera-run
A .claude/settings.json (or one of the other discovery paths) containing your hooks map
For command-type hooks: an executable on the path or a script with the right shebang
Permission modes — the events that fire on every approval decision.
File undo — FileChanged is what feeds the otter /undo snapshot store.