Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/docker/docker-agent/llms.txt

Use this file to discover all available pages before exploring further.

Hooks let you execute shell commands at key points in an agent’s lifecycle. They provide deterministic control that works alongside the LLM’s behavior — useful for validation, logging, environment setup, notifications, and blocking dangerous operations.
Common use cases:
  • Validate or transform tool inputs before execution
  • Block dangerous operations based on custom rules
  • Log all tool calls to an audit file
  • Set up the environment when a session starts
  • Send external notifications when errors occur
  • Log model responses for analytics or compliance

Hook events

There are seven hook events:
EventWhen it firesCan block?
pre_tool_useBefore a tool call executesYes
post_tool_useAfter a tool completes successfullyNo
session_startWhen a session begins or resumesNo
session_endWhen a session terminatesNo
on_user_inputWhen the agent is waiting for user inputNo
stopWhen the model finishes respondingNo
notificationWhen the agent emits a notification (error/warning)No

Configuration

Hooks are configured under agents.<name>.hooks:
agents:
  root:
    model: openai/gpt-4o
    description: Agent with hooks
    instruction: You are a helpful assistant.
    hooks:
      pre_tool_use:
        - matcher: "shell|edit_file"
          hooks:
            - type: command
              command: "./scripts/validate.sh"
              timeout: 30

      post_tool_use:
        - matcher: "*"
          hooks:
            - type: command
              command: "./scripts/log.sh"

      session_start:
        - type: command
          command: "./scripts/setup.sh"

      session_end:
        - type: command
          command: "./scripts/cleanup.sh"

      on_user_input:
        - type: command
          command: "./scripts/notify.sh"

      stop:
        - type: command
          command: "./scripts/log-response.sh"

      notification:
        - type: command
          command: "./scripts/alert.sh"

Hook definition fields

type
string
required
Hook type. Currently only command is supported.
command
string
required
Shell command or inline shell script to execute. Multi-line scripts are supported using YAML block scalars (|).
timeout
number
default:"60"
Execution timeout in seconds. The hook is killed if it exceeds this limit.

Matcher patterns

pre_tool_use and post_tool_use hooks use a matcher field with regex patterns to match tool names:
PatternMatches
*All tools
shellOnly the shell tool
shell|edit_fileEither shell or edit_file
mcp:.*All MCP tools

Hook input

Hooks receive JSON on stdin with context about the event:
{
  "session_id": "abc123",
  "cwd": "/path/to/project",
  "hook_event_name": "pre_tool_use",
  "tool_name": "shell",
  "tool_use_id": "call_xyz",
  "tool_input": {
    "cmd": "rm -rf /tmp/cache"
  }
}

Fields by event type

Fieldpre_tool_usepost_tool_usesession_startsession_endon_user_inputstopnotification
session_id
cwd
hook_event_name
tool_name
tool_use_id
tool_input
tool_response
source
reason
stop_response
notification_level
notification_message
Notes:
  • source for session_start: startup, resume, clear, or compact
  • reason for session_end: clear, logout, prompt_input_exit, or other
  • notification_level: error or warning

Hook output

Hooks communicate back by writing JSON to stdout:
{
  "continue": true,
  "stop_reason": "Optional message when continue=false",
  "suppress_output": false,
  "system_message": "Warning shown to user"
}
FieldTypeDescription
continuebooleanWhether to continue execution. Default: true.
stop_reasonstringMessage displayed to the user when continue is false.
suppress_outputbooleanWhen true, hides the hook’s stdout from the transcript.
system_messagestringWarning message displayed to the user.

Pre-tool-use output

pre_tool_use hooks support additional output via hook_specific_output:
{
  "hook_specific_output": {
    "hook_event_name": "pre_tool_use",
    "permission_decision": "deny",
    "permission_decision_reason": "Dangerous command blocked",
    "updated_input": { "cmd": "modified command" }
  }
}
FieldValuesDescription
permission_decisionallow, deny, askOverride the permission decision for this call
permission_decision_reasonstringExplanation shown to the user
updated_inputobjectReplacement tool input (replaces original)

Plain text output

For session_start, post_tool_use, and stop hooks, plain text written to stdout (non-JSON) is captured and injected as additional context for the agent.

Exit codes

Exit codeMeaning
0Success — continue normally
2Blocking error — stop the operation
OtherError — logged, execution continues
Hooks run synchronously and add latency to every matched operation. Keep hook scripts fast. Use suppress_output: true for logging-only hooks.
session_end hooks run even when the session is interrupted (e.g., Ctrl+C), subject to their configured timeout.

Examples

Block dangerous commands

hooks:
  pre_tool_use:
    - matcher: "shell"
      hooks:
        - type: command
          timeout: 10
          command: |
            INPUT=$(cat)
            CMD=$(echo "$INPUT" | jq -r '.tool_input.cmd // ""')

            if echo "$CMD" | grep -qiE 'rm\s+.*-rf|sudo|mkfs'; then
              cat <<'EOF'
            {"hook_specific_output":{"permission_decision":"deny","permission_decision_reason":"Dangerous command blocked by policy"}}
            EOF
              exit 2
            fi

            echo '{"continue": true}'

Audit logging

hooks:
  post_tool_use:
    - matcher: "*"
      hooks:
        - type: command
          command: |
            INPUT=$(cat)
            TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
            TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
            SESSION_ID=$(echo "$INPUT" | jq -r '.session_id')
            echo "$TIMESTAMP | $SESSION_ID | $TOOL_NAME" >> ./audit.log
            echo '{"continue": true}'

Session lifecycle

hooks:
  session_start:
    - type: command
      timeout: 10
      command: |
        INPUT=$(cat)
        SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
        echo "Session $SESSION_ID started at $(date)" >> /tmp/agent-session.log

  session_end:
    - type: command
      timeout: 10
      command: |
        INPUT=$(cat)
        SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
        REASON=$(echo "$INPUT" | jq -r '.reason // "unknown"')
        echo "Session $SESSION_ID ended ($REASON) at $(date)" >> /tmp/agent-session.log

Response logging (stop hook)

hooks:
  stop:
    - type: command
      timeout: 10
      command: |
        INPUT=$(cat)
        SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
        RESPONSE_LENGTH=$(echo "$INPUT" | jq -r '.stop_response // ""' | wc -c | tr -d ' ')
        echo "[$(date)] Session $SESSION_ID - Response: $RESPONSE_LENGTH chars" >> /tmp/responses.log

Error notifications

hooks:
  notification:
    - type: command
      timeout: 10
      command: |
        INPUT=$(cat)
        LEVEL=$(echo "$INPUT" | jq -r '.notification_level // "unknown"')
        MESSAGE=$(echo "$INPUT" | jq -r '.notification_message // "no message"')
        echo "[$(date)] [$LEVEL] $MESSAGE" >> /tmp/agent-notifications.log
The notification hook fires when:
  • All models fail to respond
  • A degenerate tool call loop is detected
  • The max_iterations limit is reached

CLI flags

Add hooks from the command line without modifying the YAML file:
FlagDescription
--hook-pre-tool-useRun a command before every tool call
--hook-post-tool-useRun a command after every tool call
--hook-session-startRun a command when a session starts
--hook-session-endRun a command when a session ends
--hook-on-user-inputRun a command when waiting for input
All flags are repeatable.
# Add an audit hook without touching the YAML
docker agent run agent.yaml --hook-post-tool-use "./audit.sh"

# Combine multiple hooks
docker agent run agent.yaml \
  --hook-pre-tool-use "./validate.sh" \
  --hook-post-tool-use "./log.sh"

# Layer hooks onto a registry agent
docker agent run agentcatalog/coder \
  --hook-pre-tool-use "./audit.sh"
CLI hooks are appended to hooks defined in the YAML config — they don’t replace existing hooks. CLI pre/post-tool-use hooks match all tools (equivalent to matcher: "*").

Build docs developers (and LLMs) love