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

# Hooks

> Run custom scripts at key moments in Cline's workflow to validate operations, enforce guardrails, and inject context.

Hooks are scripts that run at key moments in Cline's workflow. Because they execute at known points with consistent inputs and outputs, hooks bring determinism to the non-deterministic nature of AI models — enforcing guardrails, validations, and context injection. You can validate operations before they execute, monitor tool usage, and shape how Cline makes decisions.

## What you can build

* Stop operations before they cause problems (like creating `.js` files in a TypeScript project)
* Run linters or custom validators before files get saved
* Prevent operations that violate security policies
* Track everything for analytics or compliance
* Trigger external tools or services at the right moments
* Add context to the conversation based on what Cline is doing

## Hook types

Cline supports 8 hook types that run at different points in the task lifecycle:

| Hook type          | When it runs                                                      |
| ------------------ | ----------------------------------------------------------------- |
| `TaskStart`        | When you start a new task                                         |
| `TaskResume`       | When you resume an interrupted task                               |
| `TaskCancel`       | When you cancel a running task                                    |
| `TaskComplete`     | When a task finishes successfully                                 |
| `PreToolUse`       | Before Cline executes a tool (`read_file`, `write_to_file`, etc.) |
| `PostToolUse`      | After a tool execution completes                                  |
| `UserPromptSubmit` | When you submit a message to Cline                                |
| `PreCompact`       | Before Cline truncates conversation history to free up context    |

## Hook locations

Hooks can be stored globally or in a project workspace:

* **Global hooks**: `~/Documents/Cline/Hooks/` — applies to all projects
* **Project hooks**: `.clinerules/hooks/` in your repo — can be committed to version control

When both global and workspace hooks exist for the same hook type, both run. Global hooks execute first, then workspace hooks. If either returns `cancel: true`, the operation stops.

## Creating a hook

<Steps>
  <Step title="Open the Hooks tab">
    Click the scale icon at the bottom of the Cline panel, to the left of the model selector. Switch to the **Hooks** tab.
  </Step>

  <Step title="Create a new hook">
    Click the **New hook...** dropdown and select a hook type (e.g., `PreToolUse`, `TaskStart`).
  </Step>

  <Step title="Review the hook's code">
    Click the pencil icon to open and edit the hook script. Cline generates a template with examples.
  </Step>

  <Step title="Enable the hook">
    Toggle the switch to activate the hook once you understand what it does.
  </Step>
</Steps>

<Warning>
  Always review a hook's code before enabling it. Hooks execute automatically during your workflow and can block operations or run shell commands.
</Warning>

### Platform requirements

<Note>
  Hook filenames are platform-specific:

  * **macOS/Linux**: extensionless `HookName` (e.g., `PreToolUse`) — must be marked executable with `chmod +x`
  * **Windows**: `HookName.ps1` PowerShell script files (e.g., `PreToolUse.ps1`)

  Wrong-platform naming is silently ignored by hook discovery.
</Note>

## How hooks work

Hooks are executable scripts that receive JSON input via stdin and return JSON output via stdout.

### Input structure

Every hook receives a JSON object with common fields plus hook-specific data:

```json theme={null}
{
  "taskId": "abc123",
  "hookName": "PreToolUse",
  "clineVersion": "3.17.0",
  "timestamp": "1736654400000",
  "workspaceRoots": ["/path/to/project"],
  "userId": "user_123",
  "model": {
    "provider": "openrouter",
    "slug": "anthropic/claude-sonnet-4.5"
  },

  // Hook-specific field (name matches hook type in camelCase)
  "preToolUse": {
    "tool": "write_to_file",
    "parameters": {
      "path": "src/config.ts",
      "content": "..."
    }
  }
}
```

Hook-specific field names and their contents:

| Hook type          | Field              | Contents                                                                                     |
| ------------------ | ------------------ | -------------------------------------------------------------------------------------------- |
| `TaskStart`        | `taskStart`        | `{ task: string }`                                                                           |
| `TaskResume`       | `taskResume`       | `{ task: string }`                                                                           |
| `TaskCancel`       | `taskCancel`       | `{ task: string }`                                                                           |
| `TaskComplete`     | `taskComplete`     | `{ task: string }`                                                                           |
| `PreToolUse`       | `preToolUse`       | `{ tool: string, parameters: object }`                                                       |
| `PostToolUse`      | `postToolUse`      | `{ tool: string, parameters: object, result: string, success: boolean, durationMs: number }` |
| `UserPromptSubmit` | `userPromptSubmit` | `{ prompt: string }`                                                                         |
| `PreCompact`       | `preCompact`       | `{ conversationLength: number, estimatedTokens: number }`                                    |

<Note>
  `timestamp` is a string (milliseconds since epoch). `workspaceRoots` is an array — use `.workspaceRoots[0]` if you need a single path.
</Note>

### Output structure

Hooks return a JSON object to stdout:

```json theme={null}
{
  "cancel": false,
  "contextModification": "Optional text to add to the conversation",
  "errorMessage": ""
}
```

| Field                 | Type    | Description                                              |
| --------------------- | ------- | -------------------------------------------------------- |
| `cancel`              | boolean | If `true`, stops the operation                           |
| `contextModification` | string  | Text injected into the conversation as context for Cline |
| `errorMessage`        | string  | Shown to the user if `cancel` is `true`                  |

<Note>
  Use stderr (`>&2`) for debug logging. Only stdout is parsed as the hook response.
</Note>

### Context modification

The `contextModification` field lets hooks inject information into the conversation. Context affects **future** AI decisions, not the current tool execution — by the time a `PreToolUse` hook runs, Cline has already decided what parameters to use. The injected context influences the next API request.

Useful for:

* Adding project-specific context when a task starts
* Providing validation results that Cline should consider for future steps
* Flagging that a file is auto-generated or should not be modified

## Hook reference

<AccordionGroup>
  <Accordion title="TaskStart">
    Runs when you start a new task. Use it to log task start time, add project context, check prerequisites, or notify external systems.

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    TASK=$(echo "$INPUT" | jq -r '.taskStart.task')
    WORKSPACE=$(echo "$INPUT" | jq -r '.workspaceRoots[0] // empty')

    # Inject project context if available
    if [[ -f "$WORKSPACE/.project-context" ]]; then
      CONTEXT=$(cat "$WORKSPACE/.project-context")
      echo "{\"cancel\":false,\"contextModification\":\"Project context: $CONTEXT\"}"
    else
      echo '{"cancel":false}'
    fi
    ```
  </Accordion>

  <Accordion title="TaskResume">
    Runs when you resume an interrupted task instead of `TaskStart`. Use it to check for changes since the task was paused, refresh context with the latest project state, or notify that work is resuming.

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    echo '[TaskResume] Task resumed' >&2
    echo '{"cancel":false}'
    ```
  </Accordion>

  <Accordion title="TaskCancel">
    Runs when you cancel a running task. Use it to clean up temporary files or resources, notify external systems, or log cancellation for analytics. This hook cannot itself be cancelled.

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    TASK_ID=$(echo "$INPUT" | jq -r '.taskId')
    echo "$(date -Iseconds) | task $TASK_ID cancelled" >> ~/.cline/task-log.txt
    echo '{"cancel":false}'
    ```
  </Accordion>

  <Accordion title="TaskComplete">
    Runs when a task completes successfully. Use it to run tests or validation after changes, generate reports or summaries, notify stakeholders, or trigger CI/CD pipelines.

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    TASK_ID=$(echo "$INPUT" | jq -r '.taskId')
    echo "$(date -Iseconds) | task $TASK_ID completed" >> ~/.cline/task-log.txt
    echo '{"cancel":false}'
    ```
  </Accordion>

  <Accordion title="PreToolUse">
    Runs before any tool executes. This is the most powerful hook for validation and safety. The operation can be blocked by returning `cancel: true`.

    Input includes the tool name and its parameters:

    ```json theme={null}
    {
      "preToolUse": {
        "tool": "write_to_file",
        "parameters": {
          "path": "src/config.ts",
          "content": "..."
        }
      }
    }
    ```

    Example that blocks `.js` files in a TypeScript project:

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
    FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // empty')

    if [[ "$TOOL" == "write_to_file" && "$FILE_PATH" == *.js ]]; then
      echo '{"cancel":true,"errorMessage":"Use .ts files instead of .js in this TypeScript project"}'
      exit 0
    fi

    echo '{"cancel":false}'
    ```
  </Accordion>

  <Accordion title="PostToolUse">
    Runs after a tool completes (success or failure). Use it to audit tool usage, validate results, trigger follow-up actions, or monitor performance.

    Input includes execution results:

    ```json theme={null}
    {
      "postToolUse": {
        "tool": "execute_command",
        "parameters": { "command": "npm test" },
        "result": "All tests passed",
        "success": true,
        "durationMs": 3450
      }
    }
    ```

    <Note>
      `PostToolUse` hooks can return `cancel: true` to stop the task, but they cannot undo the tool execution that already happened.
    </Note>
  </Accordion>

  <Accordion title="UserPromptSubmit">
    Runs when you send a message to Cline. Use it to log prompts for analytics, add context based on prompt content, or validate prompts.

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    PROMPT=$(echo "$INPUT" | jq -r '.userPromptSubmit.prompt')
    echo "$(date -Iseconds) | prompt: $PROMPT" >> ~/.cline/prompt-log.txt
    echo '{"cancel":false}'
    ```
  </Accordion>

  <Accordion title="PreCompact">
    Runs before Cline truncates conversation history to stay within context limits. Use it to archive important conversation parts before they're removed, or log compaction events.

    Input includes context metrics:

    ```json theme={null}
    {
      "preCompact": {
        "conversationLength": 45,
        "estimatedTokens": 125000
      }
    }
    ```

    ```bash theme={null}
    #!/usr/bin/env bash
    INPUT=$(cat)
    TOKENS=$(echo "$INPUT" | jq -r '.preCompact.estimatedTokens')
    echo "$(date -Iseconds) | compacting at $TOKENS tokens" >> ~/.cline/compact-log.txt
    echo '{"cancel":false}'
    ```
  </Accordion>
</AccordionGroup>

## Examples

### TypeScript enforcement

Block creation of `.js` files in a TypeScript project:

```bash theme={null}
#!/usr/bin/env bash
# PreToolUse hook — save as: .clinerules/hooks/PreToolUse
# Make executable: chmod +x .clinerules/hooks/PreToolUse

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // empty')

if [[ "$TOOL" == "write_to_file" && "$FILE_PATH" == *.js ]]; then
  echo '{"cancel":true,"errorMessage":"Use .ts files instead of .js in this TypeScript project"}'
  exit 0
fi

echo '{"cancel":false}'
```

### Tool usage logging

Log all tool executions with timing information:

```bash theme={null}
#!/usr/bin/env bash
# PostToolUse hook

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.postToolUse.tool')
SUCCESS=$(echo "$INPUT" | jq -r '.postToolUse.success')
DURATION=$(echo "$INPUT" | jq -r '.postToolUse.durationMs')
FILE_PATH=$(echo "$INPUT" | jq -r '.postToolUse.parameters.path // "N/A"')

echo "$(date -Iseconds) | $TOOL | path=$FILE_PATH | success=$SUCCESS | ${DURATION}ms" >> ~/.cline/tool-log.txt

echo '{"cancel":false}'
```

### Add project context on task start

Inject project-specific information when a task begins:

```bash theme={null}
#!/usr/bin/env bash
# TaskStart hook

INPUT=$(cat)
WORKSPACE=$(echo "$INPUT" | jq -r '.workspaceRoots[0] // empty')

# Read project info if available
if [[ -f "$WORKSPACE/.project-context" ]]; then
  CONTEXT=$(cat "$WORKSPACE/.project-context")
  echo "{\"cancel\":false,\"contextModification\":\"Project context: $CONTEXT\"}"
else
  echo '{"cancel":false}'
fi
```

### Block writes to protected paths

Prevent Cline from modifying generated or read-only files:

```bash theme={null}
#!/usr/bin/env bash
# PreToolUse hook

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // empty')

PROTECTED_PATHS=("src/generated/" "dist/" "build/")

for PROTECTED in "${PROTECTED_PATHS[@]}"; do
  if [[ "$FILE_PATH" == *"$PROTECTED"* ]]; then
    echo "{\"cancel\":true,\"errorMessage\":\"Cannot modify files in $PROTECTED — this directory contains generated code\"}"
    exit 0
  fi
done

echo '{"cancel":false}'
```

## Troubleshooting

**Hook not running?**

* On macOS/Linux: check that the file is executable (`chmod +x hookname`) and uses extensionless naming (`PreToolUse`, not `PreToolUse.sh`)
* On Windows: ensure the hook file is named `<HookName>.ps1` and PowerShell is available
* Verify that Hooks are enabled in **Settings → Features → Enable Hooks**

**Hook output not parsed?**

* Ensure output is valid JSON on a single line to stdout
* Use stderr (`>&2`) for debug logging, not stdout
* Check for trailing characters or newlines before the JSON

**Hook blocking unexpectedly?**

* Review the hook's logic and test with sample input piped to the script
* Check both global and workspace hooks — both run if they exist
* Remember that if any hook returns `cancel: true`, the operation is blocked
