Mercury CLI
Documentation

Extend

Hooks

A hook runs at a named moment in a Mercury session. It can run a shell command, have a model answer a prompt, have an agent check something, or post the moment's facts to an HTTP endpoint.

Hooks are declared under the hooks key in user, project, local or managed policy settings. A skill or an extension can declare its own hooks in its frontmatter or manifest, and /hooks lists every hook the session carries.

Hook kinds

Every hook has a type.

  • command: Runs command in a shell. shell selects bash, the default, or powershell. async: true runs the hook in the background, and asyncRewake: true also wakes the model when the hook exits with the blocking status.
  • prompt: Has a model answer prompt. $ARGUMENTS receives the hook input JSON, and model selects the model.
  • agent: Has an agent verify prompt. $ARGUMENTS receives the hook input JSON, and the timeout defaults to 60 seconds.
  • http: Posts the hook input JSON to url. headers may reference environment variables as $VAR or ${VAR}; only the names listed in allowedEnvVars are interpolated, and every other reference resolves to an empty string.

Entry fields

Each event names a list of entries.

  • matcher: Matches the event's tool name on the tool events. An absent or empty matcher, or *, matches everything; a plain name matches that tool; Read|Edit matches either; anything else is a regular expression. An entry whose matcher is not a valid regular expression is refused whole.
  • hooks: Lists the hooks to run when the matcher matches.

Fields every hook kind accepts

  • if: A condition in permission-rule syntax, such as Bash(git *), evaluated against the tool events' input. A hook whose condition does not match is skipped.
  • timeout: The timeout in seconds.
  • statusMessage: The text shown in the spinner while the hook runs.
  • once: Runs the hook once, then removes it.

Declare a command hook

To declare a command hook, follow these steps:

  1. Add an entry under the event name in the settings file's hooks object:

    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [{ "type": "command", "command": "./scripts/check-command.sh" }]
          }
        ]
      }
    }
    

The command runs before each Bash tool call, subject to workspace trust and managed policy.

Event inputs

Every hook input carries hook_event_name, session_id, transcript_path, cwd and permission_mode. Each event adds its own fields.

  • Tool events: PreToolUse, PostToolUse, PostToolUseFailure and PermissionDenied carry tool_name, tool_input and tool_use_id; PostToolUse adds tool_response, PostToolUseFailure adds error and is_interrupt, and PermissionDenied adds reason. PermissionRequest carries tool_name, tool_input and permission_suggestions.
  • Prompt events: UserPromptSubmit carries prompt; UserPromptExpansion adds expansion_type, command_name, command_args and command_source.
  • Session events: SessionStart carries source, agent_type and model; SessionEnd carries reason; Setup, fired by --init, --init-only or --maintenance, carries trigger.
  • Turn events: Stop carries stop_hook_active and last_assistant_message; SubagentStop adds agent_id, agent_transcript_path and agent_type; StopFailure carries error, error_details and last_assistant_message.
  • Agent and task events: SubagentStart carries agent_id and agent_type; TeammateIdle carries teammate_name and team_name; TaskCreated and TaskCompleted add task_id, task_subject and task_description.
  • Compaction events: PreCompact carries trigger and custom_instructions; PostCompact carries trigger and compact_summary.
  • MCP events: Elicitation carries mcp_server_name, message, mode, url and elicitation_id; ElicitationResult carries mcp_server_name, elicitation_id, mode, action and content.
  • Configuration and file events: ConfigChange carries source and file_path; InstructionsLoaded carries file_path, memory_type, load_reason, globs and trigger_file_path; CwdChanged carries old_cwd and new_cwd; FileChanged carries file_path and event.
  • Worktree events: WorktreeCreate carries name; WorktreeRemove carries worktree_path.
  • Notification: Carries message, title and notification_type.

Hook responses

A command hook answers with its exit code and its stdout. Prompt, agent and HTTP hooks answer with the same JSON object.

  • Exit code 0: Success. Stdout is plain text shown as the hook's output, or one JSON object.
  • Exit code 2: The event is blocked, and stderr is the reason the model sees.
  • Any other exit code: A nonblocking error, reported to the user.

The JSON object may carry continue, where false stops the whole turn with stopReason shown to the user; suppressOutput; systemMessage; decision: "block" with reason; and hookSpecificOutput with hookEventName set to the event that ran. On PreToolUse the permission answer is permissionDecision with allow, deny or ask inside hookSpecificOutput, never the decision field; permissionDecisionReason, updatedInput and additionalContext ride beside it. PermissionRequest answers decision with behavior: "allow" or "deny", Elicitation and ElicitationResult answer action and content, SessionStart may add additionalContext, initialUserMessage and watchPaths, and WorktreeCreate answers worktreePath. A hookEventName that is not the event that ran is an error.

Policy controls

  • disableAllHooks: Disables every hook, managed hooks included.
  • allowManagedHooksOnly: Restricts execution to the hooks the policy settings define.

Workspace trust keeps a project's hooks from running before the workspace is trusted.

Workspace trust and permissions, Extensions, MCPs and skills, Permission modes