Hooks are designed for power users and enterprise teams who need fine-grained control over Cascade’s behavior. They require basic shell scripting knowledge.
What You Can Build
Hooks unlock a wide range of automation and governance capabilities:- Logging & Analytics: Track every file read, code change, command executed, user prompt, or Cascade response for compliance and usage analysis
- Security Controls: Block Cascade from accessing sensitive files, running dangerous commands, or processing policy-violating prompts
- Quality Assurance: Run linters, formatters, or tests automatically after code modifications
- Custom Workflows: Integrate with issue trackers, notification systems, or deployment pipelines
- Team Standardization: Enforce coding standards and best practices across your organization
How Hooks Work
Hooks are shell commands that run automatically when specific Cascade actions occur. Each hook:- Receives context (details about the action being performed) via JSON as standard input
- Executes your script - Python, Bash, Node.js, or any executable
- Returns a result via exit code and output streams
2. This makes pre-hooks ideal for implementing security policies or validation checks.
Configuration
Hooks are configured in JSON files that can be placed at three different levels. Cascade loads and merges hooks from all locations, giving teams flexibility in how they distribute and manage hook configurations.System-Level
System-level hooks are ideal for organization-wide policies enforced on shared development machines. For example, you can use them to enforce security policies, compliance requirements, or mandatory code review workflows. Enterprise teams can also configure hooks via the cloud dashboard without managing local files.- macOS:
/Library/Application Support/Windsurf/hooks.json - Linux/WSL:
/etc/windsurf/hooks.json - Windows:
C:\ProgramData\Windsurf\hooks.json
User-Level
User-level hooks are perfect for personal preferences and optional workflows.- Windsurf IDE:
~/.codeium/windsurf/hooks.json - JetBrains Plugin:
~/.codeium/hooks.json
Workspace-Level
Workspace-level hooks allow teams to version control project-specific policies alongside their code. They may include custom validation rules, project-specific integrations, or team-specific workflows.- Location:
.windsurf/hooks.jsonin your workspace root
Hooks from all three locations are merged together. If the same hook event is configured in multiple locations, all hooks will execute in order: system → user → workspace.
Basic Structure
Here is an example of the basic structure of the hooks configuration:Configuration Options
Each hook accepts the following parameters:| Parameter | Type | Description |
|---|---|---|
command | string | The shell command to execute. Can be any valid executable with arguments. |
show_output | boolean | Whether to display the hook’s stdout/stderr output on the user-facing Cascade UI. Useful for debugging. |
working_directory | string | Optional. The directory to execute the command from. Defaults to your workspace root. |
About the
working_directory parameter:- In multi-repo workspaces, the default is the root of the repo currently being worked on
- Relative paths resolve from the default location (workspace or repo root)
- Absolute paths are supported
- Using
~for home directory expansion is not supported
Hook Events
Cascade provides twelve hook events that cover the most critical actions in the agent workflow.Common Input Structure
All hooks receive a JSON object with the following common fields:| Field | Type | Description |
|---|---|---|
agent_action_name | string | The hook event name (e.g., “pre_read_code”, “post_write_code”) |
trajectory_id | string | Unique identifier for the overall Cascade conversation |
execution_id | string | Unique identifier for the single agent turn |
timestamp | string | ISO 8601 timestamp when the hook was triggered |
tool_info | object | Event-specific information (varies by hook type) |
pre_read_code
Triggered before Cascade reads a code file. This may block the action if the hook exits with code 2. Use cases: Restrict file access, log read operations, check permissions Input JSON:file_path may be a directory path when Cascade reads a directory recursively.
post_read_code
Triggered after Cascade successfully reads a code file. Use cases: Log successful reads, track file access patterns Input JSON:file_path may be a directory path when Cascade reads a directory recursively.
pre_write_code
Triggered before Cascade writes or modifies a code file. This may block the action if the hook exits with code 2. Use cases: Prevent modifications to protected files, backup files before changes Input JSON:post_write_code
Triggered after Cascade writes or modifies a code file. Use cases: Run linters, formatters, or tests; log code changes Input JSON:pre_run_command
Triggered before Cascade executes a terminal command. This may block the action if the hook exits with code 2. Use cases: Block dangerous commands, log all command executions, add safety checks Input JSON:post_run_command
Triggered after Cascade executes a terminal command. Use cases: Log command results, trigger follow-up actions Input JSON:pre_mcp_tool_use
Triggered before Cascade invokes an MCP (Model Context Protocol) tool. This may block the action if the hook exits with code 2. Use cases: Log MCP usage, restrict which MCP tools can be used Input JSON:post_mcp_tool_use
Triggered after Cascade successfully invokes an MCP tool. Use cases: Log MCP operations, track API usage, see MCP results Input JSON:pre_user_prompt
Triggered before Cascade processes the text of a user’s prompt. This may block the action if the hook exits with code 2. Use cases: Log all user prompts for auditing, block potentially harmful or policy-violating prompts Input JSON:show_output configuration option does not apply to this hook.
post_cascade_response
Triggered asynchronously after Cascade completes a response to a user’s prompt. This hook receives the full Cascade response ever since the last user input. Use cases: Log all Cascade responses for auditing, analyze response patterns, send responses to external systems for compliance review Input JSON:response field contains the markdown-formatted content of Cascade’s response since the last user input. This includes planner responses, tool actions (file reads, writes, commands), and any other steps Cascade took. It also includes information about which rules were triggered. See the Tracking Triggered Rules example for how to parse rule usage.
The show_output configuration option does not apply to this hook.
post_cascade_response_with_transcript
Triggered asynchronously after Cascade completes a response to a user’s prompt, similar topost_cascade_response. Instead of providing a markdown summary inline, this hook writes the full conversation transcript (from the beginning of the conversation) to a local JSONL file and provides the file path.
Use cases: Enterprise audit and compliance logging, tracking AI-generated contributions, feeding transcripts to external observability or analytics tools
Input JSON:
transcript_path points to a JSONL file at ~/.windsurf/transcripts/{trajectory_id}.jsonl. Each line is a JSON object representing a single step in the conversation, with a type and status field plus step-specific data. For example:
0600 permissions. Windsurf automatically limits the transcripts directory to 100 files, pruning the oldest by modification time.
The show_output configuration option does not apply to this hook.
This table shows the key differences between post_cascade_response and post_cascade_response_with_transcript hooks:
post_cascade_response | post_cascade_response_with_transcript | |
|---|---|---|
| Data scope | Only the steps since the last user input | The full conversation from the beginning |
| Format | Markdown summary in tool_info.response | Structured JSONL file at tool_info.transcript_path |
| Detail level | Condensed, human-readable summary | Detailed, machine-readable data (file contents, command output, etc.) |
| Delivery | Inline via stdin JSON | File on disk (~/.windsurf/transcripts/) |
post_setup_worktree
Triggered after a new git worktree is created and configured. The hook is executed inside the new worktree directory. Use cases: Copy.env files or other untracked files into the worktree, install dependencies, run setup scripts
Environment Variables:
| Variable | Description |
|---|---|
$ROOT_WORKSPACE_PATH | The absolute path to the original workspace. Use this to access files or run commands relative to the original repository. |
Exit Codes
Your hook scripts communicate results through exit codes:| Exit Code | Meaning | Effect |
|---|---|---|
0 | Success | Action proceeds normally |
2 | Blocking Error | The Cascade agent will see the error message from stderr. For pre-hooks, this blocks the action. |
| Any other | Error | Action proceeds normally |
show_output is true.
Example Use Cases
Logging All Cascade Actions
Track every action Cascade takes for auditing purposes. Config:log_input.py):
Restricting File Access
Prevent Cascade from reading files outside a specific directory. Config:block_read_access.py):
Blocking Dangerous Commands
Prevent Cascade from executing potentially harmful commands. Config:block_dangerous_commands.py):
Blocking Policy-Violating Prompts
Prevent users from submitting prompts that violate organizational policies. Config:block_bad_prompts.py):
Logging Cascade Responses
Track all Cascade responses for compliance auditing or analytics. Config:log_cascade_response.py):
Tracking Triggered Rules
Track which rules were applied during Cascade interactions for observability and metrics. Config:track_rules.py):
Always On- Rules that are always includedModel Decision- Rules whose descriptions were shown to the model for conditional applicationManual- Rules explicitly @-mentioned in user inputGlobal- Global rules fromglobal_rules.mdGlob- Rules triggered by file access matching glob patterns
This tracks which rules were presented to the model or triggered by file access, but does not indicate whether the model actually followed a rule. Rules that have already been shown recently in the conversation are deduplicated and may not appear again until later.
Running Code Formatters After Edits
Automatically format code files after Cascade modifies them. Config:format_code.sh):
Setting Up Worktrees
Copy environment files and install dependencies when a new worktree is created. Config (in.windsurf/hooks.json):
hooks/setup_worktree.sh):
Best Practices
Security
- Validate all inputs: Never trust the input JSON without validation, especially for file paths and commands.
- Use absolute paths: Always use absolute paths in your hook configurations to avoid ambiguity.
- Protect sensitive data: Avoid logging sensitive information like API keys or credentials.
- Review permissions: Ensure your hook scripts have appropriate file system permissions.
- Audit before deployment: Review every hook command and script before adding to your configuration.
- Test in isolation: Run hooks in a test environment before enabling them on your primary development machine.
Performance Considerations
- Keep hooks fast: Slow hooks will impact Cascade’s responsiveness. Aim for sub-100ms execution times.
- Use async operations: For non-blocking hooks, consider logging to a queue or database asynchronously.
- Filter early: Check the action type at the start of your script to avoid unnecessary processing.
Error Handling
- Always validate JSON: Use try-catch blocks to handle malformed input gracefully.
- Log errors properly: Write errors to
stderrso they’re visible whenshow_outputis enabled. - Fail safely: If your hook encounters an error, consider whether it should block the action or allow it to proceed.
Testing Your Hooks
- Start with logging: Begin by implementing a simple logging hook to understand the data flow.
- Use
show_output: true: Enable output during development to see what your hooks are doing. - Test blocking behavior: Verify that exit code 2 properly blocks actions in pre-hooks.
- Check all code paths: Test both success and failure scenarios in your scripts.
Enterprise Distribution
Enterprise organizations need to enforce security policies, compliance requirements, and development standards that individual users cannot bypass. Cascade Hooks supports two enterprise distribution methods:- Cloud Dashboard - Configure hooks via Team Settings in the Windsurf dashboard
- System-Level Files - Deploy hooks via MDM or configuration management tools
Cloud Dashboard Configuration
Team admins can configure Cascade Hooks directly from the Windsurf dashboard. Requirements:- Enterprise plan
TEAM_SETTINGS_UPDATEpermission
- Navigate to Team Settings in the Windsurf dashboard
- Find the Cascade Hooks section
- Enter your hooks configuration in JSON format
- Save your changes
When multiple team configurations are merged, hooks are combined per action rather than overwritten. This means hooks from all applicable team configs will run together.
System-Level File Deployment
For organizations that prefer file-based configuration or need hooks to work offline, deploy your mandatoryhooks.json configuration to these OS-specific locations:
macOS:
/usr/local/share/windsurf-hooks/ on Unix systems).
System-level hooks take precedence over user and workspace hooks, and cannot be disabled by end users without root permissions.
MDM and Configuration Management
Enterprise IT teams can deploy system-level hooks using standard tools: Mobile Device Management (MDM)- Jamf Pro (macOS) - Deploy via configuration profiles or scripts
- Microsoft Intune (Windows/macOS) - Use PowerShell scripts or policy deployment
- Workspace ONE, Google Endpoint Management, and other MDM solutions
- Ansible, Puppet, Chef, SaltStack - Use your existing infrastructure automation
- Custom deployment scripts - Shell scripts, PowerShell, or your preferred tooling
Verification and Auditing
After deployment, verify that hooks are properly installed:Important: System-level hooks are entirely managed by your IT or security team. Windsurf does not deploy or manage files at system-level paths. Ensure your internal teams handle deployment, updates, and compliance according to your organization’s policies.
Workspace Hooks for Team Projects
For project-specific conventions, teams can use workspace-level hooks in version control:Additional Resources
- MCP Integration: Learn more about Model Context Protocol in Windsurf
- Workflows: Discover how to combine hooks with Cascade Workflows
- Analytics: Track Cascade usage with Team Analytics