Hooks specification
The schema Observal uses for hook definitions -- both the registry hook type (observal registry hook) and hooks wired into harness configs by observal agent pull / observal doctor patch.
Current version: HOOKS_SPEC_VERSION = "5" (see observal_cli/hooks_spec.py).
Where hooks live
Two distinct things share the name "hook":
Registry hooks: packaged, versioned hook definitions in the Observal registry. Install them via
observal registry hook install.harness hooks: entries in
~/.claude/settings.json,.kiro/agents/<name>.json, etc. These are written byobserval agent pullandobserval doctor patch.
Both use the same event vocabulary.
Events
SessionStart
New harness session begins
Stop
Session ends
SubagentStop
Sub-agent session ends (Claude Code only)
UserPromptSubmit
User submits a prompt
PreToolUse
Before a tool call
PostToolUse
After a tool call (with result)
Notification
harness surfaces a notification
Source: observal_cli/constants.py:VALID_HOOK_EVENTS.
Handler types
command
Shell command with templated args
Kiro (shell hooks only), Claude Code (local scripts)
http
URL + method + headers + body
Claude Code (native HTTP hooks)
Execution modes
async
Fire and forget - harness doesn't wait
sync
harness waits for handler to return before continuing
blocking
Handler can veto the event (e.g. block a tool call)
Source: observal_cli/constants.py:VALID_HOOK_EXECUTION_MODES.
Scopes
agent
Applies only to one agent
session
Applies for the duration of a session
global
Applies across everything
Metadata marker
Observal writes a _observal key into hook matcher groups so subsequent runs of doctor patch / pull can find and update only Observal-managed hooks without stomping on user-authored ones.
Older installs (pre-metadata) are detected with a fallback heuristic.
Claude Code: native HTTP hook example
Kiro: shell-command hook example
Kiro doesn't support native HTTP hooks, so Observal uses curl:
Event name mapping (Claude Code ↔ Kiro)
Kiro uses camelCase / lowercase event names; Claude Code uses PascalCase. Observal maps between them.
SessionStart
agentSpawn
Stop
stop
SubagentStop
(no equivalent)
UserPromptSubmit
userPromptSubmit
PreToolUse
preToolUse
PostToolUse
postToolUse
Notification
(no equivalent)
Registry hook payload shape
When submitting a hook to the registry (observal registry hook submit):
Each field is validated server-side against the lists in observal_cli/constants.py (mirrored from observal-server/schemas/constants.py).
Source of truth
observal_cli/hooks_spec.py: version, metadata marker, spec shapeobserval_cli/constants.py: valid events, handler types, execution modes, scopesobserval-server/schemas/constants.py: server-side mirror
A sync test (tests/test_constants_sync.py) ensures CLI and server stay in lockstep.
Related
Last updated
Was this helpful?