CLI Hooks Reference
Hook Endpoint
Section titled “Hook Endpoint”POST /api/runs/{id}/hookAll hook events are sent to this single endpoint. The hook event name is extracted from the payload:
{ "hook_event_name": "PreToolUse", ... }Abbado checks for the event name in these fields (in order): hook_event_name, event_name, hookEventName.
Hook Script
Section titled “Hook Script”Each run gets a hook script at $IA_IDE_DATA_DIR/runs/<run-id>/hook.sh:
#!/bin/bashRESPONSE=$(curl -s -X POST "http://127.0.0.1:3000/api/runs/<run-id>/hook" \ -H "Content-Type: application/json" -d @- 2>/dev/null)echo "$RESPONSE"The script:
- Reads the hook payload from stdin (JSON, provided by the CLI)
- POSTs it to the Abbado hook endpoint
- Echoes the response back to the CLI
Hook Configuration
Section titled “Hook Configuration”The hooks config file at $IA_IDE_DATA_DIR/runs/<run-id>/claude-hooks.json maps all events to the hook script. It is passed to Claude Code via --settings.
{ "hooks": { "UserPromptSubmit": [ { "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "Stop": [ { "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "StopFailure": [ { "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "SessionEnd": [ { "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "PreToolUse": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "PostToolUse": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "PostToolUseFailure": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "Notification": [ { "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "PermissionRequest": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "SubagentStart": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ], "SubagentStop": [ { "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }] } ] }}Tool-related events use "matcher": "*" to match all tool names. Non-tool events omit the matcher.
Event Reference
Section titled “Event Reference”UserPromptSubmit
Section titled “UserPromptSubmit”When: User sends a prompt to the agent (types a message and presses Enter).
Payload fields: Standard Claude Code hook payload.
Abbado behavior:
- If the run status is not already
running, marks it asrunning - This is how Abbado transitions from
queuedorpausedtorunning
Response: {}
When: Agent finishes responding to a prompt.
Payload fields:
last_assistant_message(string) — the agent’s last response text
Abbado behavior:
- Marks the run as
paused(idle but session still alive) - If the run has
notify: true, sends a Discord notification with the last message summary
Response: {}
StopFailure
Section titled “StopFailure”When: Agent encounters an error while processing.
Payload fields:
error(string) — error message
Abbado behavior:
- Marks the run as
failed - Sends a Discord notification with the error (uses
notify_on_run_failedsetting)
Response: {}
SessionEnd
Section titled “SessionEnd”When: User quits the CLI or the session terminates.
Abbado behavior:
- If the run is
runningorpaused, marks it ascompleted - If the run has
notify: true, sends a Discord notification
Response: {}
PreToolUse
Section titled “PreToolUse”When: Agent is about to invoke a tool.
Payload fields:
tool_name(string) — name of the tool (e.g., “Read”, “Edit”, “Bash”)tool_input(object) — tool input parameters
Abbado behavior:
- Persists an
agent.tool_callevent with{ "tool": "<name>", "input": <input> } - This powers the real-time activity feed in the dashboard
Response: {}
PostToolUse
Section titled “PostToolUse”When: A tool call completed successfully.
Payload fields:
tool_name(string) — name of the tooltool_response(object) — tool output
Abbado behavior:
- Persists an
agent.tool_resultevent with{ "tool": "<name>", "output": <response> }
Response: {}
PostToolUseFailure
Section titled “PostToolUseFailure”When: A tool call failed with an error.
Payload fields:
tool_name(string) — name of the toolerror(string) — error message
Abbado behavior:
- Persists an
agent.tool_resultevent with{ "tool": "<name>", "error": "<message>" }
Response: {}
Notification
Section titled “Notification”When: Claude Code emits a notification (permission prompt, idle prompt, etc.).
Payload fields:
notification_type(string) — type of notification (e.g.,"permission_prompt","idle_prompt")message(string) — notification message
Abbado behavior:
- For
permission_promptandidle_prompttypes:- Persists an
agent.needs_attentionevent - Sends a Discord notification
- Persists an
- Other notification types are acknowledged but not persisted
Response: {}
PermissionRequest
Section titled “PermissionRequest”When: Agent requests permission to perform an action.
Payload fields:
- Standard Claude Code permission request payload
Abbado behavior:
- Does nothing — returns an empty response
- The user handles permissions directly in the terminal
Response: {}
SubagentStart
Section titled “SubagentStart”When: Agent spawns a subagent.
Payload fields:
agent_type(string) — type of the subagent
Abbado behavior:
- Persists an
agent.subagent_startevent
Response: {}
SubagentStop
Section titled “SubagentStop”When: A subagent stops.
Payload fields:
agent_type(string) — type of the subagent
Abbado behavior:
- Persists an
agent.subagent_stopevent
Response: {}
Codex Hook Response Format
Section titled “Codex Hook Response Format”For Codex CLI hooks, the response format wraps the event name:
{ "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "" }}This format is only used for the SessionStart event. All other Codex events use the standard {} response.
Persisted Events
Section titled “Persisted Events”All hook-generated events follow this schema in the database:
{ "id": 42, "run_id": "uuid", "sequence": 5, "event_type": "agent.tool_call", "event_version": 1, "payload": { "tool": "Edit", "input": { "file": "main.rs" } }, "created_at": "2025-01-01T12:00:00Z"}Events are immutable once written. The sequence field is monotonically increasing per run.
Debugging Hooks
Section titled “Debugging Hooks”To verify hooks are working:
- Start a run and open the terminal
- Watch the backend logs for
hook receivedmessages:INFO Abbado_api::runs: hook received run_id=a1b2c3d4 event=UserPromptSubmitINFO Abbado_api::runs: hook received run_id=a1b2c3d4 event=PreToolUse - Check the events API:
GET /api/runs/{id}/events - Verify the hook script is executable:
ls -la $IA_IDE_DATA_DIR/runs/<run-id>/hook.sh
If hooks are not firing, check:
- The hook script has execute permissions (
chmod 755) - The server is running on the expected port
- The
--settingsflag is being passed to the CLI