# Configuration

Hooks are configured in `settings.json`, **not** in `TABNINE.md`. Tabnine CLI merges configurations from multiple layers (highest to lowest precedence):

1. **Project settings**: `.tabnine/agent/settings.json` in the project root.
2. **User settings**: `~/.tabnine/agent/settings.json`.
3. **System settings**: Platform-specific system config directory.
4. **Extensions**: Hooks defined by installed extensions.

## Configuration schema

```json
{
  "hooksConfig": {
    "enabled": true,
    "disabled": [],
    "notifications": true
  },
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "write_file|replace",
        "sequential": true,
        "hooks": [
          {
            "type": "command",
            "command": "node $TABNINE_PROJECT_DIR/hooks/validate-write.js",
            "name": "validate-write",
            "description": "Validate file writes before execution",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}
```

## `hooksConfig` fields

| Field           | Type       | Default | Description                                                                           |
| --------------- | ---------- | ------- | ------------------------------------------------------------------------------------- |
| `enabled`       | `boolean`  | `true`  | Master toggle for the hooks system. Set to `false` to disable all.                    |
| `disabled`      | `string[]` | `[]`    | List of hook identifiers to skip. Matches against `name` if set, otherwise `command`. |
| `notifications` | `boolean`  | `true`  | Show visual indicators when hooks execute.                                            |

## Hook definition fields

Each event contains an array of **hook definitions**:

| Field        | Type      | Required | Description                                                                                                         |
| ------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `matcher`    | `string`  | No       | A regex for tool events (`BeforeTool`, `AfterTool`) or exact string for lifecycle events. Omit to match everything. |
| `sequential` | `boolean` | No       | If `true`, hooks in this group run sequentially. If `false` (default), they run in parallel.                        |
| `hooks`      | `array`   | **Yes**  | An array of **hook configurations** (see below).                                                                    |

## Hook configuration fields

| Field         | Type                     | Required | Description                                                                    |
| ------------- | ------------------------ | -------- | ------------------------------------------------------------------------------ |
| `type`        | `string`                 | **Yes**  | Must be `"command"`. No default — hooks without `type` are silently discarded. |
| `command`     | `string`                 | **Yes**  | The shell command to execute.                                                  |
| `name`        | `string`                 | No       | A friendly identifier for logs and the `disabled` list.                        |
| `description` | `string`                 | No       | A brief explanation of the hook's purpose.                                     |
| `timeout`     | `number`                 | No       | Timeout in **milliseconds**. Default: `60000` (60 seconds).                    |
| `env`         | `Record<string, string>` | No       | Additional environment variables to set for this hook.                         |

## Matchers

The `matcher` field controls which specific tools or triggers fire your hook:

* **Tool events** (`BeforeTool`, `AfterTool`): Matchers are **regular expressions** (e.g., `"write_file|replace"`, `"read_.*"`).
* **Lifecycle events**: Matchers are **exact strings** (e.g., `"startup"` for `SessionStart`).
* **Match all**: Omit `matcher` or set to `".*"` to match everything.

### Tool naming conventions

* **Built-in tools**: Match by their name (e.g., `read_file`, `run_shell_command`, `write_file`, `replace`).
* **MCP tools**: Follow the pattern `mcp_<server_name>_<tool_name>`.

## Multiple hooks

You can define multiple hooks for the same event. By default they run in parallel; set `sequential: true` to run them in order:

```json
{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": ".*",
        "sequential": true,
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/validate.js",
            "name": "validate"
          },
          {
            "type": "command",
            "command": "node ./hooks/log.js",
            "name": "log-tool"
          }
        ]
      }
    ]
  }
}
```

You can also define multiple hook definitions per event with different matchers:

```json
{
  "hooks": {
    "BeforeTool": [
      {
        "matcher": "write_file|replace",
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/validate-writes.js"
          }
        ]
      },
      {
        "matcher": "run_shell_command",
        "hooks": [
          {
            "type": "command",
            "command": "node ./hooks/validate-commands.js"
          }
        ]
      }
    ]
  }
}
```
