Browse documentation

Hooks

Automate repetitive tasks and enforce best practices with event-driven agent hooks

Hooks run shell commands automatically when specific events happen in your session — the agent modifies a file, invokes a tool, or completes a task. You list the events and the commands; Mind handles the execution.

CapabilityIDECLIWeb
Event-driven hooks✓✓✓
Shell commands✓✓✓
Create Hooks by asking the agent in chat✓✓✓

What you can do with hooks

  • Enforce standards — run linters, formatters, or type checks automatically after agent file changes
  • Gate dangerous operations — block tool execution unless preconditions are met (PreToolUse)
  • Generate companion files — auto-create tests, docs, or translations when new source files appear
  • Validate before commit — check code quality before the agent finalises changes
  • Report back to the agent — a hook's message is appended to the tool result the agent reads, so a failing check explains itself

Quick example

A PostFileSave hook that runs ESLint whenever the agent saves or edits a file:

{
  "PostFileSave": [
    {
      "hooks": [{ "command": "npx eslint --fix" }]
    }
  ]
}

This lives at .mind/hooks.json and activates automatically — no manual prompting needed. The hook receives the saved file path and session context as JSON on STDIN.

How hooks work

Hooks are configured in one JSON file, .mind/hooks.json, in your project root. Its top-level keys are event names, each holding a list of groups, and each group holds the commands to run.

When the event fires, Mind checks each group's matcher. If it matches — or the group has no matcher — every command in that group runs, in order:

  • The command runs in your project root, with the event payload as JSON on STDIN.
  • Its exit code decides what happens next — 0 allows the action, 2 blocks it with the reason taken from STDERR, and any other code is a non-blocking warning. A command that exits 0 can still block by printing {"decision":"block","reason":"…"} on STDOUT.
  • The first run asks for your approval — Mind prompts before running a project's hooks, and the approval covers that exact file content, so editing it asks again.

Available events

EventWhen it firesCan block?
PostFileSaveAfter the agent overwrites or edits an existing fileNo
PostFileCreateAfter the agent writes a file that did not existNo
PreToolUseBefore a tool is about to executeYes
PostToolUseAfter a tool has executedNo
UserPromptSubmitWhen a message is sent to the agentYes
SessionStartWhen a new session beginsNo
SessionEndWhen the session is closingNo
SubagentStartWhen a delegated sub-agent, background agent or workflow startsNo
SubagentStopWhen one of those finishes, with its statusNo
NotificationWhen Mind raises a notification for youNo
StopWhen the agent finishes respondingNo
File events respond only to changes made by the agent: saving or creating a file manually in the editor does not fire PostFileSave or PostFileCreate. They are observational — a block decision is ignored, since a hook cannot un-write a file that is already on disk. To stop a write, match PreToolUse.

Hook file schema

The whole configuration is one JSON object in .mind/hooks.json. Each top-level key is an event name; its value is a list of groups, and a group pairs an optional matcher with the commands to run when it matches:

{
  "PreToolUse": [
    {
      "matcher": "shell",
      "hooks": [{ "command": "sh tools/guard-shell.sh", "timeout": 10 }]
    }
  ],
  "PostFileSave": [
    {
      "matcher": "file_write|file_edit",
      "hooks": [{ "command": "sh tools/format-saved-file.sh" }]
    }
  ],
  "Stop": [
    {
      "hooks": [{ "command": "sh tools/check-unlanded-work.sh" }]
    }
  ]
}

Field reference

FieldRequiredDescription
<EventName>YesA top-level key: one of the event names above, spelled exactly. Its value is the list of groups for that event, and keys Mind does not recognise are ignored.
[].matcherNoWhich tools the group applies to: an exact tool name, a pipe- or comma-separated list such as file_write|file_edit, * or omitted for every tool, or any other string, which is read as a regular expression. It is ignored on the events that are not about a tool (SessionStart, SessionEnd, UserPromptSubmit, Stop, Notification), and on SubagentStart and SubagentStop it is matched against the sub-agent type — task, agent or workflow — instead of a tool name.
[].hooksYesThe commands to run when the group matches, in order. The first one that blocks stops the rest.
[].hooks[].commandYesThe shell command, run from your project root, so repository-relative paths work.
[].hooks[].timeoutNoSeconds before the command is terminated and reported as a warning (default: 30).
[].hooks[].sourceNoAttribution an installed plugin sets on its own hooks, so a failure names the plugin that caused it. Leave it out of your project file.

What the command receives

The event is piped to the command as a JSON object on STDIN. Every payload carries hook_event_name, and alongside it:

  • cwd on every event except the sub-agent ones, and session_id on SessionStart, SessionEnd, UserPromptSubmit and Stop
  • prompt on UserPromptSubmit
  • tool_name and tool_input on PreToolUse, plus tool_response on PostToolUse
  • file_path on PostFileSave and PostFileCreate
  • subagent_type and a description on SubagentStart and SubagentStop, with a status on the stop
  • message and kind on Notification

File location

  • Location: .mind/hooks.json in your project root
  • One file per project: every hook the project defines lives in it, grouped under the event that fires it
  • Read fresh every time: Mind re-reads the file on each event, so an edit takes effect on the next one — there is nothing to restart or reload
  • Approved once, by content: the first time the file would run a command, Mind asks you to approve it; the approval covers that exact content, so a later edit asks again
  • Plugins add their own: hooks that come with an installed plugin run alongside the project's, and are approved when the plugin is installed
  • Activation: Hooks activate automatically when a session starts — no manual registration needed

Setting up hooks

Click the + button in the Agent Hooks section of the Mind panel and select Ask Mind to create a hook. Describe what you want in natural language — for example, "run tests after every file save" — and Mind generates the hook configuration through conversation.

The result is written to .mind/hooks.json.