Skip to main content
Hooks let external programs react to Deep Agents Code lifecycle events. Configure commands in ~/.deepagents/hooks.json and it pipes a JSON payload to each matching command’s stdin whenever an event fires. Hooks run fire-and-forget in a background thread. They never block Deep Agents Code and failures are logged without interrupting your session.

Setup

Create ~/.deepagents/hooks.json:
Now every time a session starts or ends, Deep Agents Code appends the event payload to ~/deepagents-events.log.

Hook configuration

The config file contains a single hooks array. Each entry has:
command
list[str]
required
Command and arguments to run. No shell expansion: use ["bash", "-c", "..."] if needed.
events
list[str]
optional
Event names to subscribe to. Omit or leave empty to receive all events.
The second hook above has no events filter, so it receives every event Deep Agents Code emits.

Payload format

Each hook command receives a JSON object on stdin with an "event" key plus event-specific fields:

Events reference

session.start

Fired when an agent session begins (both interactive and non-interactive modes).
thread_id
string
required
The session thread identifier.

session.end

Fired when a session exits.
thread_id
string
required
The session thread identifier.

user.prompt

Fired in interactive mode when the user submits a chat message. No additional fields.

input.required

Fired when the agent requires human input (human-in-the-loop interrupt). No additional fields.

permission.request

Fired before the approval dialog when one or more tool calls need user permission.
tool_names
list[str]
required
Names of the tools requesting approval.

tool.error

Fired when a tool call returns an error.
tool_names
list[str]
required
Names of the tool(s) that errored.

task.complete

Fired when the agent finishes its current task (the streaming loop ends without further interrupts).
thread_id
string
required
The session thread identifier.

context.compact

Fired before Deep Agents Code compacts (summarizes) the conversation context. No additional fields.

Execution model

  • Background thread: Hook subprocesses run in a thread via asyncio.to_thread so the main event loop is never blocked.
  • Concurrent dispatch: When multiple hooks match an event, they run concurrently in a thread pool.
  • 5-second timeout: Each command has a 5-second timeout. Commands that exceed this are killed.
  • Fire-and-forget: Errors are caught per-hook and logged at debug/warning level. A failing hook never crashes or stalls Deep Agents Code.
  • Lazy loading: The config file is read once on the first event dispatch and cached for the rest of the session.
  • No shell expansion: Commands are executed directly (not through a shell). Wrap in ["bash", "-c", "..."] if you need shell features like pipes or variable expansion.

Hook examples

Write a handler script that reads the JSON payload from stdin:
my_handler.py
~/.deepagents/hooks.json

Security considerations

Hooks follow the same trust model as Git hooks or shell aliases — any user who can write to ~/.deepagents/hooks.json can execute arbitrary commands. This is by design:
  • No command injection: Payload data flows only to stdin as JSON, never to command-line arguments. json.dumps handles escaping.
  • No shell by default: Commands run with shell=False, preventing shell injection.
  • Malformed config: Invalid JSON or unexpected types produce logged warnings, not security issues.
Only add hooks from sources you trust. A hook has the same permissions as your user account.

See also