- Run formatters after edits
- Add analytics for events
- Scan for PII or secrets
- Gate risky operations (e.g., SQL writes)
Agent Support
Hooks work with Firebender Agent. The agent uses these hook events:preToolUse/postToolUse- Generic tool use hooks (fires for all tools)beforeShellExecution/afterShellExecution- Control shell commandsbeforeMCPExecution/afterMCPExecution- Control MCP tool usagebeforeReadFile/afterFileEdit- Control file access and editspreCompact- Observe context window compactionstop- Handle agent completion
Quickstart
Create ahooks.json file. You can create it at the project level (<project>/.firebender/hooks.json) or in your home directory (~/.firebender/hooks.json). Project-level hooks apply only to that specific project, while home directory hooks apply globally.
- User hooks (~/.firebender/)
- Project hooks (.firebender/)
For user-level hooks that apply globally, create Create your hook script at Make it executable:Restart your IDE. Your hook now runs after every file edit.
~/.firebender/hooks.json:~/.firebender/hooks/format.sh:Hook Types
Hooks support command-based hooks.Command-Based Hooks
Command hooks execute shell scripts that receive JSON input via stdin and return JSON output via stdout.- Exit code 0 - Hook succeeded, use the JSON output
- Exit code 2 - Block the action (equivalent to returning
permission: "deny") - Other exit codes - Hook failed, action proceeds (fail-open by default)
Configuration
Configuration File
This example shows a user-level hooks file (~/.firebender/hooks.json). For project-level hooks, change paths like ./hooks/script.sh to .firebender/hooks/script.sh:
Global Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
| version | number | 1 | Config schema version |
Per-Script Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
| command | string | required | Script path or command |
| type | ”command” | “prompt" | "command” | Hook execution type |
| timeout | number | platform default | Execution timeout in seconds |
| loop_limit | number | null | 5 | Per-script loop limit for stop hooks. null means no limit. |
| matcher | object | - | Filter criteria for when hook runs |
Matcher Configuration
Matchers let you filter when a hook runs. Which field the matcher applies to depends on the hook:beforeShellExecution: The matcher runs against the shell command string. Use it to run hooks only when the command matches a pattern (e.g. network calls, file deletions). The example above runs approve-network.sh only when the command contains curl, wget, or nc .
Available matchers by hook:
preToolUse(and other tool hooks): Filter by tool type — Shell, Read, Write, Grep, Delete, MCP, Task, etc.beforeShellExecution: Filter by the shell command text; the matcher is matched against the full command string.
Reference
Common Schema
Input (all hooks)
All hooks receive a base set of fields in addition to their hook-specific fields:| Field | Type | Description |
|---|---|---|
| conversation_id | string | Stable ID of the conversation across many turns |
| generation_id | string | The current generation that changes with every user message |
| model | string | The model configured for the composer that triggered the hook |
| hook_event_name | string | Which hook is being run |
| firebender_version | string | Firebender plugin version (e.g., “1.7.2”) |
| workspace_roots | string[] | The list of root folders in the workspace (normally just one, but multiroot workspaces can have multiple) |
| user_email | string | null | Email address of the authenticated user, if available |
| transcript_path | string | null | Path to the main conversation transcript file (null if transcripts disabled) |
Hook Events
preToolUse
Called before any tool execution. This is a generic hook that fires for all tool types (Shell, Read, Write, MCP, Task, etc.). Use matchers to filter by specific tools.| Output Field | Type | Description |
|---|---|---|
| decision | string | ”allow” to proceed, “deny” to block |
| reason | string (optional) | Explanation shown to agent when denied |
| updated_input | object (optional) | Modified tool input to use instead |
postToolUse
Called after successful tool execution. Useful for auditing and analytics.| Input Field | Type | Description |
|---|---|---|
| duration | number | Execution time in milliseconds |
| tool_output | string | Full output from the tool |
| Output Field | Type | Description |
|---|---|---|
| updated_mcp_tool_output | object (optional) | For MCP tools only: replaces the tool output seen by the model |
beforeShellExecution / beforeMCPExecution
Called before any shell command or MCP tool is executed. Return a permission decision.beforeMCPExecution uses fail-closed behavior. If the hook script fails to execute (crashes, times out, or returns invalid JSON), the MCP tool call will be blocked. This ensures MCP operations cannot bypass configured hooks.
afterShellExecution
Fires after a shell command executes; useful for auditing or collecting metrics from command output.| Field | Type | Description |
|---|---|---|
| command | string | The full terminal command that was executed |
| output | string | Full output captured from the terminal |
| duration | number | Duration in milliseconds spent executing the shell command (excludes approval wait time) |
afterMCPExecution
Fires after an MCP tool executes; includes the tool’s input parameters and full JSON result.| Field | Type | Description |
|---|---|---|
| tool_name | string | Name of the MCP tool that was executed |
| tool_input | string | JSON params string passed to the tool |
| result_json | string | JSON string of the tool response |
| duration | number | Duration in milliseconds spent executing the MCP tool (excludes approval wait time) |
afterFileEdit
Fires after the Agent edits a file; useful for formatters or accounting of agent-written code.beforeReadFile
Called before Agent reads a file. Use for access control to block sensitive files from being sent to the model. This hook uses fail-closed behavior. If the hook script fails to execute (crashes, times out, or returns invalid JSON), the file read will be blocked. This provides security guarantees for sensitive file access.| Input Field | Type | Description |
|---|---|---|
| file_path | string | Absolute path to the file being read |
| content | string | Full contents of the file |
| attachments | array | Context attachments associated with the prompt |
| Output Field | Type | Description |
|---|---|---|
| permission | string | ”allow” to proceed, “deny” to block |
| user_message | string (optional) | Message shown to user when denied |
preCompact
Called before context window compaction/summarization occurs. This is an observational hook that cannot block or modify the compaction behavior. Useful for logging when compaction happens or notifying users.| Input Field | Type | Description |
|---|---|---|
| trigger | string | What triggered the compaction: “auto” or “manual” |
| context_usage_percent | number | Current context window usage as a percentage (0-100) |
| context_tokens | number | Current context window token count |
| context_window_size | number | Maximum context window size in tokens |
| message_count | number | Number of messages in the conversation |
| messages_to_compact | number | Number of messages that will be summarized |
| is_first_compaction | boolean | Whether this is the first compaction for this conversation |
| Output Field | Type | Description |
|---|---|---|
| user_message | string (optional) | Message to show to the user when compaction occurs |
stop
Called when the agent loop ends. Can optionally auto-submit a follow-up user message to keep iterating.followup_message is a string. When provided and non-empty, Firebender will automatically submit it as the next user message. This enables loop-style flows (e.g., iterate until a goal is met).
The loop_count field indicates how many times the stop hook has already triggered an automatic follow-up for this conversation (starts at 0). To prevent infinite loops, a maximum of 5 auto follow-ups is enforced.
Environment Variables
Hook scripts receive environment variables when executed:| Variable | Description | Always Present |
|---|---|---|
| FIREBENDER_PROJECT_DIR | Workspace root directory | Yes |
| FIREBENDER_VERSION | Firebender version string | Yes |
| FIREBENDER_USER_EMAIL | Authenticated user email | If logged in |
Troubleshooting
How to confirm hooks are active
There is a Hooks tab in Firebender Settings to debug configured and executed hooks, as well as the Hooks output in~/.firebender/hooks-logs to see errors.
If hooks are not working
- Restart your IDE to ensure the hooks service is running.
- Check that relative paths are correct for your hook source:
- For project hooks, paths are relative to the project root (e.g.,
.firebender/hooks/script.sh) - For user hooks, paths are relative to
~/.firebender/(e.g.,./hooks/script.shorhooks/script.sh)
- For project hooks, paths are relative to the project root (e.g.,
Exit code blocking
Exit code 2 from command hooks blocks the action (equivalent to returningdecision: "deny").