The PreToolUse hook runs before a tool is executed.
Execution Flow
- When a tool is called, all
PreToolUse hooks with a matching matcher (or no matcher) run in parallel. - Duplicate commands are deduplicated.
- The hook receives a JSON payload on stdin and specific environment variables.
Hook Input (stdin)
{
"event": "PreToolUse",
"session_id": "abc-123",
"cwd": "/path/to/project",
"tool_name": "bash",
"tool_input": { "command": "ls -la" }
}
Hook Environment Variables
CRUSH_EVENT: Event name (e.g., PreToolUse).CRUSH_TOOL_NAME: Name of the tool being called.CRUSH_SESSION_ID: Current session ID.CRUSH_CWD: Current working directory.CRUSH_PROJECT_DIR: Project root directory.CRUSH_TOOL_INPUT_COMMAND: Value of command from tool input.CRUSH_TOOL_INPUT_FILE_PATH: Value of file_path from tool input.
Hook Output and Decisions
Hooks must return an exit code:
- Exit code 0: Success. Stdout is parsed as JSON to determine the decision.
- Exit code 2: The tool call is blocked. Stderr is used as the reason.
- Other exit codes: Non-blocking error; the tool call proceeds.
JSON Output Format (Stdout):
{
"decision": "allow|deny|none",
"reason": "explanation for deny",
"context": "optional context appended to tool result",
"updated_input": "replacement JSON for tool input"
}
Decision Aggregation Rules:
- Deny wins over allow: Any
deny decision blocks the call. - Allow wins over none: A lone
allow lets the call proceed. - Input updates: For
updated_input, the last non-empty value wins.
{
"decision": "allow",
"context": "optional context appended to tool result"
}