- 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:sessionStart/sessionEnd- Observe chat session lifecycle for analytics and batchingsubagentStart/subagentStop- Observe Task-tool subagent lifecycle and add subagent-specific contextpreToolUse/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
Per-Script Configuration Options
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:Hook Events
sessionStart
Called when a chat session becomes active. Useful for session analytics, per-session bookkeeping, and initializing any per-conversation state you want to aggregate later.sessionEnd
Called when a chat session ends. Useful for batching or summarizing per-session activity such as skill usage, tool usage, or audit records.subagentStart
Called when theTask tool spawns a subagent. Useful for subagent analytics, auditing by agent type, or injecting additional context into the subagent before it begins.
subagentStop
Called when aTask-tool subagent finishes. Useful for per-subagent analytics, summaries, or cleanup keyed by subagent type.
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.postToolUse
Called after successful tool execution. Useful for auditing and analytics.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.afterMCPExecution
Fires after an MCP tool executes; includes the tool’s input parameters and full JSON result.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.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.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: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").