# Wave Hooks Configuration

Hooks allow you to automate tasks when certain events occur in Wave. This document provides detailed guidance on how to configure hooks in `settings.json`.

## Hook Events

Wave supports the following hook events:

- `PreToolUse`: Triggered before a tool is executed.
- `PostToolUse`: Triggered after a tool has finished executing.
- `UserPromptSubmit`: Triggered when a user submits a prompt.
- `PermissionRequest`: Triggered when Wave requests permission to use a tool.
- `Stop`: Triggered when Wave finishes its response cycle (no more tool calls).
- `SubagentStop`: Triggered when a subagent finishes its response cycle.
- `WorktreeCreate`: Triggered when a new worktree is created.
- `WorktreeRemove`: Triggered when a worktree is removed (e.g., via ExitWorktree with `action: "remove"`). Non-blocking. The hook receives `worktree_path` in the JSON input. Useful for cleanup tasks (e.g., `docker compose -p $(basename "$worktree_path") down`) after worktree deletion.
- `CwdChanged`: Triggered when the working directory changes (e.g., entering/exiting a worktree). Non-blocking.
- `SessionStart`: Triggered during session initialization. Hooks can inject `additionalContext` and `initialUserMessage` via stdout.
- `SessionEnd`: Triggered during agent destruction (fire-and-forget, non-blocking). Useful for cleanup, resource teardown, and analytics.
- `PreCompact`: Triggered before conversation compaction. Hook stdout is captured as additional instructions and merged into the compaction prompt.
- `PostCompact`: Triggered after conversation compaction completes. Receives the compact summary text.

## Hook Configuration Structure

Hooks are configured in the `hooks` field of `settings.json`. Each event can have multiple hook configurations.

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "command": "pnpm lint",
            "description": "Run lint before writing files"
          }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "command": "echo \"Permission requested for Bash tool\" >> hooks.log",
            "description": "Log permission requests for Bash"
          }
        ]
      }
    ]
  }
}
```

## Hook Configuration Fields

- `matcher`: (Optional) A pattern to match against the tool name (e.g., "Write", "Read*", "/^Edit/"). Only applicable for `PreToolUse`, `PostToolUse`, and `PermissionRequest`.
- `hooks`: An array of hook commands to execute.
  - `command`: The shell command to execute.
  - `description`: A brief description of the hook's purpose.
  - `async`: (Optional) Whether the hook should run in the background without blocking (default: `false`).
  - `timeout`: (Optional) Maximum execution time in seconds (default: `600`).

## Hook Input JSON

Wave provides detailed context to hook processes via `stdin` as a JSON object. This allows hooks to make informed decisions based on the current state.

### Common Fields
- `session_id`: The current session ID.
- `transcript_path`: Path to the session transcript file (JSON).
- `cwd`: The current working directory.
- `hook_event_name`: The name of the triggering event.

### Event-Specific Fields
- `tool_name`: (PreToolUse, PostToolUse, PermissionRequest) The name of the tool.
- `tool_input`: (PreToolUse, PostToolUse, PermissionRequest) The input parameters passed to the tool.
- `tool_response`: (PostToolUse) The result of the tool execution.
- `user_prompt`: (UserPromptSubmit) The text submitted by the user.
- `subagent_type`: (If executed by a subagent) The type of the subagent.
- `name`: (WorktreeCreate) The name of the new worktree.
- `worktree_path`: (WorktreeRemove) The absolute path to the removed worktree.
- `old_cwd`: (CwdChanged) The previous working directory.
- `new_cwd`: (CwdChanged) The new working directory.
- `compact_instructions`: (PreCompact) Custom instructions for the compaction, if any.
- `compact_summary`: (PostCompact) The AI-generated compaction summary text.
- `source`: (SessionStart) The session start source: `"startup"`, `"resume"`, or `"compact"`.
- `agent_type`: (SessionStart) The agent type identifier.
- `end_source`: (SessionEnd) The session end source: `"exit"`, `"stop"`, or `"compact"`.

## Hook Exit Codes

Hooks can communicate status and control Wave's behavior using exit codes:

- **Exit 0**: Success. Wave continues its normal execution.
- **Exit 2**: Blocking Error. Wave blocks the current operation and provides feedback based on the event:
    - `UserPromptSubmit`: Blocks prompt processing and shows `stderr` as a user error.
    - `PreToolUse`: Blocks tool execution and provides `stderr` to the agent as feedback.
    - `PostToolUse`: Appends `stderr` to the tool result as feedback for the agent.
    - `Stop`: Blocks the stop operation and provides `stderr` to the agent.
    - `WorktreeCreate` / `WorktreeRemove` / `CwdChanged` / `PreCompact` / `PostCompact`: Shows `stderr` in an error block, but does not block the operation.
    - `SessionStart` / `SessionEnd`: Shows `stderr` in an error block, but does not block startup or shutdown.
- **Other Exits (e.g., Exit 1)**: Non-blocking error. Wave continues execution but shows `stderr` as a warning to the user.

## SessionStart Hooks

`SessionStart` hooks fire during session initialization. They can inject context and messages into the session via stdout.

### Stdout Processing

Hook stdout is processed as follows:
- If stdout is valid JSON with `hookSpecificOutput.additionalContext` (Claude Code format), that value is injected as additional context.
- If stdout is valid JSON with `initialUserMessage` at the top level, that value is injected as the initial user message.
- If stdout is not JSON, the entire output is appended as additional context.

Example hook output:
```json
{"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "User prefers concise responses"}, "initialUserMessage": "Here is my current task..."}
```

### Example Configuration
```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"SessionStart\", \"additionalContext\": \"Project uses pnpm and TypeScript\"}}'",
            "description": "Inject project context at session start"
          }
        ]
      }
    ]
  }
}
```

## SessionEnd Hooks

`SessionEnd` hooks fire during agent destruction (fire-and-forget, non-blocking). They are useful for cleanup tasks, resource teardown, and analytics.

### Input
SessionEnd hooks receive `end_source` in the JSON input indicating how the session ended:
- `"exit"`: User exited the session
- `"stop"`: Session was explicitly stopped
- `"compact"`: Session was compacted

### Example Configuration
```json
{
  "hooks": {
    "SessionEnd": [
      {
        "hooks": [
          {
            "command": "echo '{\"session_id\": \"$WAVE_SESSION_ID\"}' >> /tmp/session-analytics.log",
            "description": "Log session end for analytics",
            "async": true
          }
        ]
      }
    ]
  }
}
```

## Live Reload

Hook configurations support **live reload**. When you modify hooks in `settings.json`, the changes take effect immediately without restarting Wave.

## Plugin Hooks

When hooks are registered via a **plugin**, Wave automatically:

1. Substitutes `${WAVE_PLUGIN_ROOT}` with the plugin's directory path in the command string
2. Injects `WAVE_PLUGIN_ROOT` as an environment variable into the hook process

```json
{
  "hooks": {
    "WorktreeCreate": [
      {
        "hooks": [
          {
            "command": "${WAVE_PLUGIN_ROOT}/scripts/setup-worktree.sh"
          }
        ]
      }
    ]
  }
}
```

The shell also receives `WAVE_PLUGIN_ROOT` as an env var, so `$WAVE_PLUGIN_ROOT` works in the hook script itself.

## Best Practices

- **Keep hooks fast**: Long-running hooks can slow down your workflow unless they are `async`.
- **Use descriptive names**: Help yourself and others understand what each hook does.
- **Test your hooks**: Run the commands manually first to ensure they work as expected.
- **Use local overrides**: For machine-specific hooks, use `.wave/settings.local.json`.
