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.
| Capability | IDE | CLI | Web |
|---|---|---|---|
| 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
| Event | When it fires | Can block? |
|---|---|---|
| PostFileSave | After the agent overwrites or edits an existing file | No |
| PostFileCreate | After the agent writes a file that did not exist | No |
| PreToolUse | Before a tool is about to execute | Yes |
| PostToolUse | After a tool has executed | No |
| UserPromptSubmit | When a message is sent to the agent | Yes |
| SessionStart | When a new session begins | No |
| SessionEnd | When the session is closing | No |
| SubagentStart | When a delegated sub-agent, background agent or workflow starts | No |
| SubagentStop | When one of those finishes, with its status | No |
| Notification | When Mind raises a notification for you | No |
| Stop | When the agent finishes responding | No |
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
| Field | Required | Description |
|---|---|---|
| <EventName> | Yes | A 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. |
| [].matcher | No | Which 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. |
| [].hooks | Yes | The commands to run when the group matches, in order. The first one that blocks stops the rest. |
| [].hooks[].command | Yes | The shell command, run from your project root, so repository-relative paths work. |
| [].hooks[].timeout | No | Seconds before the command is terminated and reported as a warning (default: 30). |
| [].hooks[].source | No | Attribution 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:
cwdon every event except the sub-agent ones, andsession_idon SessionStart, SessionEnd, UserPromptSubmit and Stopprompton UserPromptSubmittool_nameandtool_inputon PreToolUse, plustool_responseon PostToolUsefile_pathon PostFileSave and PostFileCreatesubagent_typeand a description on SubagentStart and SubagentStop, with a status on the stopmessageandkindon Notification
File location
- Location:
.mind/hooks.jsonin 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.