> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bricks.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Run custom commands on agent lifecycle events

Hooks let you run shell commands automatically when specific agent events occur — for example, enforcing coding standards before a tool writes a file, or logging every completed turn. The system follows the same conventions as Claude Code hooks.

## Configuration

Hooks are configured in JSON files at two levels:

| Scope       | File                                   | Managed via                                  |
| ----------- | -------------------------------------- | -------------------------------------------- |
| **Global**  | `~/.bricks-project-desktop/hooks.json` | **Settings > Agent > Hooks settings > Open** |
| **Project** | `<project>/.bricks/hooks.json`         | Edit directly                                |

Both files are merged additively. Identical handlers (same event, matcher, and command) are deduplicated.

### Config format

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "bash|write_file",
        "hooks": [
          {
            "type": "command",
            "command": "node check.js",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
```

The top-level `hooks` wrapper is optional — you can place event keys at the root.

Each event key maps to an array of rule objects. A rule has:

* **`matcher`** — which tool or trigger to match (see [Matchers](#matchers))
* **`hooks`** — an array of handler objects, each with:
  * `type` — always `"command"`
  * `command` — the shell command to run
  * `timeout` — per-handler timeout in seconds (default 60)

### Matchers

Matchers follow Claude Code semantics:

| Pattern                       | Behavior                                            |
| ----------------------------- | --------------------------------------------------- |
| Empty or `*`                  | Matches everything                                  |
| Word characters and `\|` only | Exact pipe-separated list (e.g. `bash\|write_file`) |
| Anything else                 | Treated as a regular expression                     |

## Events

| Event              | Matcher value                                  | Can block | Description                                      |
| ------------------ | ---------------------------------------------- | --------- | ------------------------------------------------ |
| `SessionStart`     | `startup` \| `resume`                          | No        | Fires when a session starts or resumes           |
| `UserPromptSubmit` | —                                              | Yes       | Runs before a user prompt is sent; can reject it |
| `PreToolUse`       | tool name                                      | Yes       | Runs before a tool call; can deny it             |
| `PostToolUse`      | tool name                                      | No        | Runs after a tool call; can append feedback      |
| `Stop`             | —                                              | No        | Fires when the agent finishes a turn             |
| `SubagentStart`    | agent name                                     | No        | Fires when a sub-agent spawns                    |
| `SubagentStop`     | agent name                                     | No        | Fires when a sub-agent finishes                  |
| `PreCompact`       | `manual` \| `auto`                             | No        | Fires before context compaction                  |
| `PostCompact`      | `manual` \| `auto`                             | No        | Fires after context compaction                   |
| `GoalUpdate`       | `set` \| `evaluated` \| `complete` \| `cancel` | No        | Fires on goal lifecycle changes                  |

## Execution protocol

Each matching handler runs through the shell with `cwd` set to the project path. A JSON payload is passed on **stdin** containing:

* `session_id` — the current session ID
* `cwd` — the project path
* `hook_event_name` — the event name

Plus per-event fields such as `tool_name`, `tool_input`, `tool_response`, `prompt`, `trigger`, `agent_type`, and `goal`.

The following environment variables are set:

| Variable             | Value              |
| -------------------- | ------------------ |
| `BRICKS_PROJECT_DIR` | Project path       |
| `BRICKS_SESSION_ID`  | Current session ID |
| `BRICKS_HOOK_EVENT`  | Event name         |

### Exit codes

| Exit code | Behavior                                               |
| --------- | ------------------------------------------------------ |
| `0`       | Success — stdout may carry a JSON decision (see below) |
| `2`       | Block — stderr is used as the block reason             |
| Any other | Non-blocking failure — logged and ignored              |

Timeouts are also treated as non-blocking failures.

### Decision output

On exit code `0`, stdout may contain a JSON object:

* **Block a tool call** (PreToolUse): `{"decision": "block", "reason": "..."}`
* **Deny with reason** (PreToolUse): `{"hookSpecificOutput": {"permissionDecision": "deny", "permissionDecisionReason": "..."}}`
* **Append feedback** (PostToolUse): `{"additionalContext": "..."}`

All matching handlers run in parallel. If any handler blocks, the tool call or prompt is denied and all block reasons are joined.

## Scope

Hooks apply across all agent contexts:

* **Main agent** tool calls
* **Sub-agent** tool calls (with `agent_type` in the payload)
* **GUI tool** calls
* **ACP tool** calls

`UserPromptSubmit` only gates user-typed prompts — goal continuations and internal session messages are not intercepted.

Hook engine failures never propagate into the agent loop.

## Examples

### Require a linter check before file writes

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "write_file",
        "hooks": [
          {
            "type": "command",
            "command": "node scripts/lint-check.js"
          }
        ]
      }
    ]
  }
}
```

### Log every completed turn

```json theme={null}
{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"Turn completed\" >> /tmp/ctor-events.log"
          }
        ]
      }
    ]
  }
}
```

## Data storage

| Data                 | Location                               |
| -------------------- | -------------------------------------- |
| Global hooks config  | `~/.bricks-project-desktop/hooks.json` |
| Project hooks config | `<project>/.bricks/hooks.json`         |
