hooks.mdx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. ---
  2. title: "Hooks"
  3. sidebarTitle: "Hooks"
  4. description: "Inject custom logic into Cline's workflow to validate operations and shape Cline's decisions."
  5. ---
  6. 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 by enforcing guardrails, validations, and context injection. You can validate operations before they execute, monitor tool usage, and shape how Cline makes decisions.
  7. ## What You Can Build
  8. - Stop operations before they cause problems (like creating `.js` files in a TypeScript project)
  9. - Run linters or custom validators before files get saved
  10. - Prevent operations that violate security policies
  11. - Track everything for analytics or compliance
  12. - Trigger external tools or services at the right moments
  13. - Add context to the conversation based on what Cline is doing
  14. ## Hook Types
  15. Cline supports 8 hook types that run at different points in the task lifecycle:
  16. | Hook Type | When It Runs |
  17. |-----------|--------------|
  18. | TaskStart | When you start a new task |
  19. | TaskResume | When you resume an interrupted task |
  20. | TaskCancel | When you cancel a running task |
  21. | TaskComplete | When a task finishes successfully |
  22. | PreToolUse | Before Cline executes a tool (read_file, write_to_file, etc.) |
  23. | PostToolUse | After a tool execution completes |
  24. | UserPromptSubmit | When you submit a message to Cline |
  25. | PreCompact | Before Cline truncates conversation history to free up context |
  26. ## Hook Lifecycle
  27. ```mermaid
  28. flowchart TD
  29. %% Styling
  30. classDef hook fill:#FFB74D,stroke:#E65100,stroke-width:2px,color:black,rx:5,ry:5;
  31. classDef state fill:#E1F5FE,stroke:#0277BD,stroke-width:2px,color:black;
  32. classDef action fill:#FFFFFF,stroke:#333,stroke-width:1px,color:black,stroke-dasharray: 5 5;
  33. %% Entry Points
  34. Start((Start)) --> CheckType{New or<br/>Resume?}
  35. %% Initialization Hooks
  36. CheckType -- New Task --> H_Start[TaskStart]:::hook
  37. CheckType -- Resume --> H_Resume[TaskResume]:::hook
  38. %% Main Loop
  39. H_Start --> Loop(Task Active Loop):::state
  40. H_Resume --> Loop
  41. subgraph Conversation Cycle
  42. direction TB
  43. Loop -- User sends message --> H_Submit[UserPromptSubmit]:::hook
  44. H_Submit --> Thinking[Cline Processes Context]:::state
  45. %% Context Compaction Path
  46. Thinking -. Context Limit Reached .-> H_Compact[PreCompact]:::hook
  47. H_Compact -.-> Thinking
  48. %% Tool Execution Path
  49. Thinking -- Decides to use tool --> H_PreTool[PreToolUse]:::hook
  50. H_PreTool -- Allowed --> ToolExec[Tool Executes]:::action
  51. H_PreTool -- Cancelled --> Thinking
  52. ToolExec --> H_PostTool[PostToolUse]:::hook
  53. H_PostTool --> Thinking
  54. end
  55. %% Termination Paths
  56. Thinking -- Task Successfully Finished --> H_Complete[TaskComplete]:::hook
  57. Loop -- User Cancels Task --> H_Cancel[TaskCancel]:::hook
  58. %% End
  59. H_Complete --> End((End))
  60. H_Cancel --> End
  61. ```
  62. The diagram shows the complete hook lifecycle:
  63. 1. **Entry**: When you start a task, either **TaskStart** (new task) or **TaskResume** (interrupted task) runs first
  64. 2. **Conversation Cycle**: Each time you send a message, **UserPromptSubmit** runs, then Cline processes your request
  65. 3. **Tool Execution**: When Cline decides to use a tool, **PreToolUse** runs first-if allowed, the tool executes, then **PostToolUse** runs
  66. 4. **Context Management**: If the conversation approaches context limits, **PreCompact** runs before truncation
  67. 5. **Exit**: The task ends with either **TaskComplete** (success) or **TaskCancel** (user cancellation)
  68. Orange nodes represent hooks where you can inject custom logic. The cycle repeats as you continue the conversation.
  69. ## Hook Locations
  70. Hooks can be stored globally or in a project workspace. See [Storage Locations](/customization/overview#storage-locations) for guidance on when to use each.
  71. - **Global hooks**: `~/Documents/Cline/Hooks/`
  72. - **Project hooks**: `.clinerules/hooks/` in your repo (can be committed to version control)
  73. 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.
  74. ## Creating a Hook
  75. <Steps>
  76. <Step title="Open the Hooks tab">
  77. Click the scale icon at the bottom of the Cline panel, to the left of the model selector. Switch to the Hooks tab.
  78. </Step>
  79. <Step title="Create a new hook">
  80. Click **"New hook..."** dropdown and select a hook type (e.g., PreToolUse, TaskStart).
  81. </Step>
  82. <Step title="Review the hook's code">
  83. Click the pencil icon to open and edit the hook script. Cline generates a template with examples.
  84. </Step>
  85. <Step title="Enable the hook">
  86. Toggle the switch to activate the hook once you understand what it does.
  87. </Step>
  88. </Steps>
  89. <Warning>
  90. Always review a hook's code before enabling it. Hooks execute automatically during your workflow and can block operations or run shell commands.
  91. </Warning>
  92. ## Quick Start: Your First Hook
  93. Let's create a simple hook that logs every file Cline reads or writes. You'll see results in seconds.
  94. ### The Hook
  95. Create a file called `file-logger` in your hooks directory with this content:
  96. ```bash
  97. #!/bin/bash
  98. # Logs all file operations to ~/cline-activity.log
  99. INPUT=$(cat)
  100. TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
  101. FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // "N/A"')
  102. # Log to file
  103. echo "$(date '+%H:%M:%S') - $TOOL: $FILE_PATH" >> ~/cline-activity.log
  104. # Always allow the operation
  105. echo '{"cancel":false}'
  106. ```
  107. ### Setup
  108. <Steps>
  109. <Step title="Create the hook file">
  110. Save the script above as `~/Documents/Cline/Hooks/file-logger` or create it through the Hooks UI.
  111. </Step>
  112. <Step title="Make it executable">
  113. On macOS/Linux, run `chmod +x ~/Documents/Cline/Hooks/file-logger`.
  114. </Step>
  115. <Step title="Enable it (macOS/Linux only)">
  116. In Cline's Hooks tab, find "file-logger" under PreToolUse hooks and toggle it on.
  117. </Step>
  118. </Steps>
  119. <Note>
  120. On Windows, hooks are executed with PowerShell and run whenever the hook file exists. In this
  121. foundation PR, hook enable/disable toggling is not yet supported on Windows.
  122. </Note>
  123. <Note>
  124. Coming next: JSON-backed hook enabled/disabled state across platforms, so toggle behavior is
  125. consistent on Windows, macOS, and Linux.
  126. </Note>
  127. <Note>
  128. Hook filenames are platform-specific:
  129. - **Windows**: only `HookName.ps1` is supported (PowerShell script files)
  130. - **macOS/Linux**: only extensionless `HookName` is supported (executable files like bash scripts or binaries)
  131. Wrong-platform naming is ignored by hook discovery.
  132. </Note>
  133. ### Test It
  134. Ask Cline to read any file in your project: "What's in package.json?"
  135. Then check the log:
  136. ```bash
  137. cat ~/cline-activity.log
  138. ```
  139. You'll see entries like:
  140. ```text
  141. 14:23:45 - read_file: /path/to/package.json
  142. 14:23:47 - search_files: /path/to/src
  143. ```
  144. ### Customize It
  145. Try modifying the hook to:
  146. - Filter specific file types (only log `.ts` files)
  147. - Add the task ID to each log entry
  148. - Send notifications for write operations
  149. - Block operations on certain paths
  150. The sections below explain how hooks receive input and return output, plus more examples.
  151. ## How Hooks Work
  152. Hooks are executable scripts that receive JSON input via stdin and return JSON output via stdout.
  153. ### Input Structure
  154. Every hook receives a JSON object with common fields plus hook-specific data:
  155. ```json
  156. {
  157. "taskId": "abc123",
  158. "hookName": "PreToolUse",
  159. "clineVersion": "3.17.0",
  160. "timestamp": "1736654400000",
  161. "workspaceRoots": ["/path/to/project"],
  162. "userId": "user_123",
  163. "model": {
  164. "provider": "openrouter",
  165. "slug": "anthropic/claude-sonnet-4.5"
  166. },
  167. // Hook-specific field (name matches hook type in camelCase)
  168. "taskStart": {
  169. "task": "Add authentication to the API"
  170. }
  171. }
  172. ```
  173. `model.provider` and `model.slug` are machine-stable identifiers for the active provider/model at hook execution time. If unavailable, Cline sends deterministic fallback values: `"unknown"`.
  174. <Note>
  175. Migration note for existing hook scripts:
  176. - `timestamp` is a string (milliseconds since epoch), not a number
  177. - `workspaceRoots` is an array of workspace root paths and replaces the old singular `workspacePath`
  178. If your scripts previously read `.workspacePath`, switch to `.workspaceRoots[0]` (or iterate all roots).
  179. </Note>
  180. The hook-specific field name matches the hook type:
  181. - `taskStart`, `taskResume`, `taskCancel`, `taskComplete` contain `{ task: string }`
  182. - `preToolUse` contains `{ tool: string, parameters: object }`
  183. - `postToolUse` contains `{ tool: string, parameters: object, result: string, success: boolean, durationMs: number }`
  184. - `userPromptSubmit` contains `{ prompt: string }`
  185. - `preCompact` contains `{ conversationLength: number, estimatedTokens: number }`
  186. ### Output Structure
  187. Hooks return a JSON object to stdout:
  188. ```json
  189. {
  190. "cancel": false,
  191. "contextModification": "Optional text to add to the conversation",
  192. "errorMessage": ""
  193. }
  194. ```
  195. | Field | Type | Description |
  196. |-------|------|-------------|
  197. | `cancel` | boolean | If `true`, stops the operation (blocks the tool, cancels the task start, etc.) |
  198. | `contextModification` | string | Optional text that gets injected into the conversation as context for Cline |
  199. | `errorMessage` | string | Shown to the user if `cancel` is `true` |
  200. ### Context Modification
  201. The `contextModification` field lets hooks inject information into the conversation. This is useful for:
  202. - Adding project-specific context when a task starts
  203. - Providing validation results that Cline should consider
  204. - Injecting environment information before tool execution
  205. For example, a PreToolUse hook could add: `"Note: This file is auto-generated. Edits may be overwritten."`
  206. ## Hook Reference
  207. ### Task Lifecycle Hooks
  208. #### TaskStart
  209. Runs when you start a new task. Use it to:
  210. - Log task start time for analytics
  211. - Add project context to the conversation
  212. - Check prerequisites before work begins
  213. - Notify external systems (Slack, issue trackers)
  214. ```bash
  215. #!/bin/bash
  216. INPUT=$(cat)
  217. TASK=$(echo "$INPUT" | jq -r '.taskStart.task')
  218. echo "[TaskStart] Starting: $TASK" >&2
  219. echo '{"cancel":false,"contextModification":"","errorMessage":""}'
  220. ```
  221. #### TaskResume
  222. Runs when you resume an interrupted task (instead of TaskStart). Use it to:
  223. - Check for changes since the task was paused
  224. - Refresh context with latest project state
  225. - Notify that work is resuming
  226. #### TaskCancel
  227. Runs when you cancel a running task. Use it to:
  228. - Clean up temporary files or resources
  229. - Notify external systems about cancellation
  230. - Log cancellation for analytics
  231. #### TaskComplete
  232. Runs when a task completes successfully. Use it to:
  233. - Run tests or validation after changes
  234. - Generate reports or summaries
  235. - Notify stakeholders
  236. - Trigger CI/CD pipelines
  237. ### Tool Hooks
  238. #### PreToolUse
  239. Runs before any tool executes. This is the most powerful hook for validation and safety. Use it to:
  240. - Block dangerous operations
  241. - Validate parameters before execution
  242. - Add context about the file or resource being accessed
  243. - Log tool usage
  244. The input includes the tool name and its parameters:
  245. ```json
  246. {
  247. "preToolUse": {
  248. "tool": "write_to_file",
  249. "parameters": {
  250. "path": "src/config.ts",
  251. "content": "..."
  252. }
  253. }
  254. }
  255. ```
  256. Example that blocks `.js` files in a TypeScript project:
  257. ```bash
  258. #!/bin/bash
  259. INPUT=$(cat)
  260. TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
  261. FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // empty')
  262. if [[ "$TOOL" == "write_to_file" && "$FILE_PATH" == *.js ]]; then
  263. echo '{"cancel":true,"errorMessage":"Use .ts files instead of .js in this TypeScript project"}'
  264. exit 0
  265. fi
  266. echo '{"cancel":false}'
  267. ```
  268. #### PostToolUse
  269. Runs after a tool completes (success or failure). Use it to:
  270. - Audit tool usage
  271. - Validate results
  272. - Trigger follow-up actions
  273. - Monitor performance
  274. The input includes execution results:
  275. ```json
  276. {
  277. "postToolUse": {
  278. "tool": "execute_command",
  279. "parameters": { "command": "npm test" },
  280. "result": "All tests passed",
  281. "success": true,
  282. "durationMs": 3450
  283. }
  284. }
  285. ```
  286. <Note>
  287. PostToolUse hooks can return `cancel: true` to stop the task, but they cannot undo the tool execution that already happened.
  288. </Note>
  289. ### Other Hooks
  290. #### UserPromptSubmit
  291. Runs when you send a message to Cline. Use it to:
  292. - Log prompts for analytics
  293. - Add context based on prompt content
  294. - Validate or sanitize prompts
  295. #### PreCompact
  296. Runs before Cline truncates conversation history to stay within context limits. Use it to:
  297. - Archive important conversation parts before they're removed
  298. - Log compaction events
  299. - Add a summary of what's being removed
  300. The input includes context metrics:
  301. ```json
  302. {
  303. "preCompact": {
  304. "conversationLength": 45,
  305. "estimatedTokens": 125000
  306. }
  307. }
  308. ```
  309. ## Examples
  310. ### TypeScript Enforcement
  311. Block creation of `.js` files in a TypeScript project:
  312. ```bash
  313. #!/bin/bash
  314. # PreToolUse hook
  315. INPUT=$(cat)
  316. TOOL=$(echo "$INPUT" | jq -r '.preToolUse.tool')
  317. FILE_PATH=$(echo "$INPUT" | jq -r '.preToolUse.parameters.path // empty')
  318. if [[ "$TOOL" == "write_to_file" && "$FILE_PATH" == *.js ]]; then
  319. echo '{"cancel":true,"errorMessage":"Use .ts files instead of .js in this TypeScript project"}'
  320. exit 0
  321. fi
  322. echo '{"cancel":false}'
  323. ```
  324. ### Tool Usage Logging
  325. Log all tool executions to a file:
  326. ```bash
  327. #!/bin/bash
  328. # PostToolUse hook
  329. INPUT=$(cat)
  330. TOOL=$(echo "$INPUT" | jq -r '.postToolUse.tool')
  331. SUCCESS=$(echo "$INPUT" | jq -r '.postToolUse.success')
  332. DURATION=$(echo "$INPUT" | jq -r '.postToolUse.durationMs')
  333. echo "$(date -Iseconds) | $TOOL | success=$SUCCESS | ${DURATION}ms" >> ~/.cline-tool-log.txt
  334. echo '{"cancel":false}'
  335. ```
  336. ### Add Project Context on Task Start
  337. Inject project-specific information when a task begins:
  338. ```bash
  339. #!/bin/bash
  340. # TaskStart hook
  341. INPUT=$(cat)
  342. WORKSPACE=$(echo "$INPUT" | jq -r '.workspaceRoots[0] // empty')
  343. # Read project info if available
  344. if [[ -f "$WORKSPACE/.project-context" ]]; then
  345. CONTEXT=$(cat "$WORKSPACE/.project-context")
  346. echo "{\"cancel\":false,\"contextModification\":\"Project context: $CONTEXT\"}"
  347. else
  348. echo '{"cancel":false}'
  349. fi
  350. ```
  351. ## CLI Support
  352. Hooks are available in the [Cline CLI](/cline-cli/getting-started):
  353. ```bash
  354. # Enable hooks for a task
  355. cline "What does this repo do?" -s hooks_enabled=true
  356. # Configure hooks globally
  357. cline config set hooks-enabled=true
  358. ```
  359. <Note>
  360. Windows hooks require PowerShell (`powershell.exe`) available on your PATH.
  361. </Note>
  362. ## Troubleshooting
  363. **Hook not running?**
  364. - On macOS/Linux, check that the file is executable (`chmod +x hookname`)
  365. - On Windows, ensure PowerShell is available (`powershell -NoProfile -Command "$PSVersionTable.PSVersion"`)
  366. - On Windows, ensure the hook file is named `<HookName>.ps1` (for example `PreToolUse.ps1`)
  367. - On macOS/Linux, ensure the hook file uses extensionless `<HookName>` naming (for example `PreToolUse`)
  368. - On macOS/Linux, verify the hook is enabled (toggle is on in the Hooks tab)
  369. - Check that Hooks are enabled globally in Settings
  370. **Hook output not parsed?**
  371. - Ensure output is valid JSON on a single line to stdout
  372. - Use stderr (`>&2`) for debug logging, not stdout
  373. - Check for trailing characters or newlines before the JSON
  374. **Hook blocking unexpectedly?**
  375. - Review the hook's logic and test with sample input
  376. - Check both global and workspace hooks (both run if they exist)
  377. ## Related Features
  378. - [Rules](/customization/cline-rules) define high-level guidance that hooks can enforce programmatically
  379. - [Checkpoints](/core-workflows/checkpoints) let you roll back if a hook didn't catch an issue
  380. - [Auto-Approve](/features/auto-approve) works well with hooks as safety nets