Skip to main content
Hooks let external programs observe and control Deep Agents Code lifecycle events. Configure command handlers in ~/.deepagents/hooks.json, and Deep Agents Code sends a JSON payload to each matching handler whenever an event fires. Some events also read the handler’s response to allow, deny, or continue an action. Hooks run with your user permissions and execute arbitrary code from your configuration. Treat hook configuration as executable code and only install hooks from sources you trust.

Setup

Create ~/.deepagents/hooks.json. Handlers nest in three levels: event name, matcher group, then the handlers that run for that group.
~/.deepagents/hooks.json
Run dcode config path to confirm the resolved location of hooks.json and whether it exists. Hook configuration is snapshotted when a session starts. Editing hooks.json mid-session does not add, remove, or weaken hooks until the next session, so an agent that edits settings during a turn cannot change the policy hooks that govern it.

Handler fields

Each entry in a matcher group’s hooks array is a command handler:
type
string
required
Handler type. Only command is supported. A command handler runs a subprocess that receives the event JSON on stdin.
command
string
required
Path to the executable or script to run. The event payload is written to stdin as JSON, never interpolated into arguments.
timeout
number
default:"600"
optional
Per-handler timeout in seconds. Handlers that exceed the timeout are cancelled and treated as a non-blocking failure.
statusMessage
string
optional
Message shown in the UI while the handler runs.
Configuring an unsupported handler type is a configuration error that fails validation visibly, rather than being skipped silently.

Matchers

A matcher filters whether a handler group runs for a given event. Each event matches against one field (see Events):
  • Omitted, empty, or * matches all values for that event.
  • A simple name matches exactly (Bash).
  • Alternation matches either side (Edit|Write).
  • Any other value is treated as a regular expression (mcp__.*).
Compile errors invalidate that group and produce a user-visible configuration diagnostic before the session runs. Tool-oriented events (PreToolUse, PostToolUse, PermissionRequest) also accept an optional if predicate using permission-rule syntax, such as Bash(git *), as a second-stage filter. On any other event, an if predicate fails closed and the handler does not run.

Events

Deep Agents Code emits the following events. Client-owned events run in the CLI process. Server-owned events originate in the agent execution path and round-trip to the client so command handlers run where your configuration lives. PreToolUse runs before the permission prompt and before tool execution, which makes it the primary enforcement seam. Stop runs before a terminal model response is committed.

Input payload

Every handler receives a JSON object on stdin. All events share a common envelope, plus event-specific fields.

Common fields

Event-specific fields

Example PreToolUse payload:

Tool names

Hook scripts see stable public tool names and argument shapes, not internal Deep Agents Code tool names. Match on and read these names in PreToolUse, PostToolUse, and PermissionRequest:

Handler output

Command handlers communicate results through their exit code, stdout, and stderr. JSON output is only processed on exit 0, and a JSON response must be the only content on stdout. User-facing and model-facing output is capped at 10,000 characters.

Universal output fields

Any handler may return these top-level fields:
Returning "continue": false stops all processing and takes precedence over event-specific decisions. When multiple hooks match, the first stopReason in configuration order is shown, and all systemMessage values are preserved in configuration order. Event-specific control lives in hookSpecificOutput (for tool and permission events) or in top-level decision and reason (for Stop).

Control tool execution with PreToolUse

Return a permission decision to allow, deny, or force a prompt before a tool runs:
When multiple hooks match, decisions combine with the precedence deny > ask > allow. A deny short-circuits execution before the permission prompt and feeds its reason to the model. An ask forces the permission prompt. An allow suppresses the ordinary prompt but does not override a separate deny or ask. Any additionalContext values are passed through in configuration order. You can also block with exit code 2 and write the reason to stderr.

Allow or deny with PermissionRequest

Return a decision to answer a permission prompt on the user’s behalf:
Any deny wins. If no hook denies and at least one allows, the action is allowed. If no hook decides, the normal permission prompt is shown.

Continue a turn with Stop

Return a block decision to keep the agent working instead of ending the turn:
A block continues the agent turn with your feedback. To avoid infinite loops, check stop_hook_active in the payload and stop blocking once your condition is met. Deep Agents Code also enforces a hard cap of eight consecutive continuations.

Inject context with start events

SessionStart and SubagentStart cannot block, but they can add context for the model:
PostToolUse and SubagentStop are also non-blocking: they can append additionalContext for the model but cannot undo an action that already ran.

Unsupported output fields

Some fields defined by the hook output contract are recognized and validated, but not applied. When a handler returns one of these, Deep Agents Code emits a diagnostic and falls back to normal behavior rather than failing silently:

Examples

~/.deepagents/hooks/block-rm.sh
~/.deepagents/hooks.json
~/.deepagents/hooks/load-context.sh
~/.deepagents/hooks.json
~/.deepagents/hooks.json
~/.deepagents/hooks/handler.py

Security

Hooks follow the same trust model as Git hooks or shell aliases: any process that can write to hooks.json can run arbitrary commands with your permissions.
  • Payload data flows to stdin as JSON, never interpolated into command arguments.
  • Hook configuration is snapshotted at session start, so a mid-session settings change cannot alter the active policy hooks.
  • Prefer explicit executables and argument arrays over shell wrappers.
  • Only install hooks from sources you trust.
A hook runs with your user permissions. Treat hook configuration as executable code.

See also