Hooks
Hooks are shell commands that fire automatically on events — before tool calls, after edits, when the model finishes. Configure in dynamo.yaml or .dynamo/hooks/*.yaml.
Configuration
hooks:
- event: PreToolUse
matcher: "run_command"
if: "rm -rf"
command: "echo 'blocked' >&2; exit 2"
- event: PostToolUse
matcher: "edit_file"
command: ".dynamo/hooks/lint.sh"
- event: Stop
command: ".dynamo/hooks/build-gate.sh"
timeout: 30000Hooks can also be defined in separate files under .dynamo/hooks/*.yaml (project) or ~/.config/dynamo/hooks/*.yaml (global).
Events
| Event | When | Use case |
|---|---|---|
| PreToolUse | Before tool executes | Block dangerous commands, modify input |
| PostToolUse | After tool executes | Auto-lint, inject build errors as context |
| Stop | Model finishes responding | Build gates — model auto-fixes errors |
| SessionStart | Session begins | Environment checks, context loading |
| SessionEnd | Session ends | Cleanup, metrics, logging |
Matching
- `matcher` — exact tool name, or several separated by
|(e.g."edit_file|write_file"). Only used onPreToolUseandPostToolUse; other events ignore it. - `if` — plain text that must appear somewhere in the tool call's input (case-sensitive).
"rm"also matches words likeformat, so make it specific, e.g."rm -rf".
Sequential execution, first block wins.
Exit Codes
| Code | Meaning |
|---|---|
0 | Approve — continue execution. Parse stdout as JSON for structured output. |
2 | Block — prevent the tool from executing |
| Other | Warn — show a warning but continue |
Hooks receive JSON on stdin: event, toolName, toolInput, toolOutput and toolIsError (PostToolUse), sessionId, timestamp, and stop_hook_active (Stop). On exit 0, stdout can be JSON with action, reason, updatedInput (PreToolUse: change the tool's input), additionalContext (added for the model), or continue: true (Stop: keep going). timeout is in milliseconds and defaults to 10000.
Managing Hooks

Use /hooks to browse configured hooks — a 3-level picker showing event types, numbered hook list, and detail view with execution history.
Trusting project hooks
Hooks that live in the project (dynamo.yaml or .dynamo/hooks/*.yaml) run only after you trust the folder once:
dynamo hooks trustTrust takes effect the next time you launch `dynamo` — the gate is read once at startup, and there's no in-session way to re-trust, so running the command in a second terminal while Dynamo is open won't make hooks start firing.
The trust check is fingerprinted over the hook set, so it asks again after you add or change a project hook — that's deliberate, since a hook is arbitrary shell. Personal hooks in your Dynamo config dir (~/.config/dynamo/hooks/ on macOS and Linux, %APPDATA%\dynamo\hooks\ on Windows) always run. Dynamo tells you at startup when project hooks are waiting on trust.
Examples
Auto-lint after edits
hooks:
- event: PostToolUse
matcher: "edit_file"
command: "jq -r '.toolInput.path' | xargs -r npx eslint --fix"Build gate on Stop
hooks:
- event: Stop
command: "npm run build 1>&2 || exit 2"
timeout: 30000When a Stop hook exits with code 2, Dynamo sends its stderr back to the model, which fixes the errors and tries again. Any other non-zero code only shows a warning.
Block dangerous commands
hooks:
- event: PreToolUse
matcher: "run_command"
if: "docker"
command: "echo 'Docker commands blocked' >&2; exit 2"