SpyBara
Go Premium Account
2026
24 Apr 2026, 18:20
19 May 2026, 11:58 18 May 2026, 22:01 14 May 2026, 21:00 14 May 2026, 07:00 13 May 2026, 00:57 12 May 2026, 01:59 11 May 2026, 18:00 7 May 2026, 20:02 7 May 2026, 17:08 5 May 2026, 23:00 2 May 2026, 06:45 2 May 2026, 00:48 1 May 2026, 18:29 30 Apr 2026, 18:36 29 Apr 2026, 12:40 29 Apr 2026, 00:50 25 Apr 2026, 06:37 25 Apr 2026, 00:42 24 Apr 2026, 18:20 24 Apr 2026, 12:28 23 Apr 2026, 18:31 23 Apr 2026, 12:28 23 Apr 2026, 00:46 22 Apr 2026, 18:29 22 Apr 2026, 00:42 21 Apr 2026, 18:29 21 Apr 2026, 12:30 21 Apr 2026, 06:45 20 Apr 2026, 18:26 20 Apr 2026, 06:53 18 Apr 2026, 18:18 17 Apr 2026, 00:44 16 Apr 2026, 18:31 16 Apr 2026, 00:46 15 Apr 2026, 18:31 15 Apr 2026, 06:44 14 Apr 2026, 18:31 14 Apr 2026, 12:29 13 Apr 2026, 18:37 13 Apr 2026, 00:44 12 Apr 2026, 06:38 10 Apr 2026, 18:23 9 Apr 2026, 00:33 8 Apr 2026, 18:32 8 Apr 2026, 00:40 7 Apr 2026, 00:40 2 Apr 2026, 18:23 31 Mar 2026, 06:35 31 Mar 2026, 00:39 28 Mar 2026, 06:26 28 Mar 2026, 00:36 27 Mar 2026, 18:23 27 Mar 2026, 00:39 26 Mar 2026, 18:27 25 Mar 2026, 18:24 23 Mar 2026, 18:22 20 Mar 2026, 00:35 18 Mar 2026, 12:23 18 Mar 2026, 00:36 17 Mar 2026, 18:24 17 Mar 2026, 00:33 16 Mar 2026, 18:25 16 Mar 2026, 12:23 14 Mar 2026, 00:32 13 Mar 2026, 18:15 13 Mar 2026, 00:34 11 Mar 2026, 00:31 9 Mar 2026, 00:34 8 Mar 2026, 18:10 8 Mar 2026, 00:35 7 Mar 2026, 18:10 7 Mar 2026, 06:14 7 Mar 2026, 00:33 6 Mar 2026, 00:38 5 Mar 2026, 18:41 5 Mar 2026, 06:22 5 Mar 2026, 00:34 4 Mar 2026, 18:18 4 Mar 2026, 06:20 3 Mar 2026, 18:20 3 Mar 2026, 00:35 27 Feb 2026, 18:15 24 Feb 2026, 06:27 24 Feb 2026, 00:33 23 Feb 2026, 18:27 21 Feb 2026, 00:33 20 Feb 2026, 12:16 19 Feb 2026, 20:53 19 Feb 2026, 20:37
25 Apr 2026, 00:42
19 May 2026, 11:58 18 May 2026, 22:01 14 May 2026, 21:00 14 May 2026, 07:00 13 May 2026, 00:57 12 May 2026, 01:59 11 May 2026, 18:00 7 May 2026, 20:02 7 May 2026, 17:08 5 May 2026, 23:00 2 May 2026, 06:45 2 May 2026, 00:48 1 May 2026, 18:29 30 Apr 2026, 18:36 29 Apr 2026, 12:40 29 Apr 2026, 00:50 25 Apr 2026, 06:37 25 Apr 2026, 00:42 24 Apr 2026, 18:20 24 Apr 2026, 12:28 23 Apr 2026, 18:31 23 Apr 2026, 12:28 23 Apr 2026, 00:46 22 Apr 2026, 18:29 22 Apr 2026, 00:42 21 Apr 2026, 18:29 21 Apr 2026, 12:30 21 Apr 2026, 06:45 20 Apr 2026, 18:26 20 Apr 2026, 06:53 18 Apr 2026, 18:18 17 Apr 2026, 00:44 16 Apr 2026, 18:31 16 Apr 2026, 00:46 15 Apr 2026, 18:31 15 Apr 2026, 06:44 14 Apr 2026, 18:31 14 Apr 2026, 12:29 13 Apr 2026, 18:37 13 Apr 2026, 00:44 12 Apr 2026, 06:38 10 Apr 2026, 18:23 9 Apr 2026, 00:33 8 Apr 2026, 18:32 8 Apr 2026, 00:40 7 Apr 2026, 00:40 2 Apr 2026, 18:23 31 Mar 2026, 06:35 31 Mar 2026, 00:39 28 Mar 2026, 06:26 28 Mar 2026, 00:36 27 Mar 2026, 18:23 27 Mar 2026, 00:39 26 Mar 2026, 18:27 25 Mar 2026, 18:24 23 Mar 2026, 18:22 20 Mar 2026, 00:35 18 Mar 2026, 12:23 18 Mar 2026, 00:36 17 Mar 2026, 18:24 17 Mar 2026, 00:33 16 Mar 2026, 18:25 16 Mar 2026, 12:23 14 Mar 2026, 00:32 13 Mar 2026, 18:15 13 Mar 2026, 00:34 11 Mar 2026, 00:31 9 Mar 2026, 00:34 8 Mar 2026, 18:10 8 Mar 2026, 00:35 7 Mar 2026, 18:10 7 Mar 2026, 06:14 7 Mar 2026, 00:33 6 Mar 2026, 00:38 5 Mar 2026, 18:41 5 Mar 2026, 06:22 5 Mar 2026, 00:34 4 Mar 2026, 18:18 4 Mar 2026, 06:20 3 Mar 2026, 18:20 3 Mar 2026, 00:35 27 Feb 2026, 18:15 24 Feb 2026, 06:27 24 Feb 2026, 00:33 23 Feb 2026, 18:27 21 Feb 2026, 00:33 20 Feb 2026, 12:16 19 Feb 2026, 20:53 19 Feb 2026, 20:37
Thu 2 18:23 Tue 7 00:40 Wed 8 00:40 Wed 8 18:32 Thu 9 00:33 Fri 10 18:23 Sun 12 06:38 Mon 13 00:44 Mon 13 18:37 Tue 14 12:29 Tue 14 18:31 Wed 15 06:44 Wed 15 18:31 Thu 16 00:46 Thu 16 18:31 Fri 17 00:44 Sat 18 18:18 Mon 20 06:53 Mon 20 18:26 Tue 21 06:45 Tue 21 12:30 Tue 21 18:29 Wed 22 00:42 Wed 22 18:29 Thu 23 00:46 Thu 23 12:28 Thu 23 18:31 Fri 24 12:28 Fri 24 18:20 Sat 25 00:42 Sat 25 06:37 Wed 29 00:50 Wed 29 12:40 Thu 30 18:36

hooks.md +110 −48

Details

1# Hooks1# Hooks

2 2 

3Experimental. Hooks are under active development. Windows support temporarily

4disabled.

5 

6Hooks are an extensibility framework for Codex. They allow3Hooks are an extensibility framework for Codex. They allow

7you to inject your own scripts into the agentic loop, enabling features such as:4you to inject your own scripts into the agentic loop, enabling features such as:

8 5 


23 20 

24- Matching hooks from multiple files all run.21- Matching hooks from multiple files all run.

25- Multiple matching command hooks for the same event are launched concurrently,22- Multiple matching command hooks for the same event are launched concurrently,

26 so one hook can’t prevent another matching hook from starting.23 so one hook cannot prevent another matching hook from starting.

27- `PreToolUse`, `PermissionRequest`, `PostToolUse`, `UserPromptSubmit`, and24- `PreToolUse`, `PermissionRequest`, `PostToolUse`, `UserPromptSubmit`, and

28 `Stop` run at turn scope.25 `Stop` run at turn scope.

29- Hooks are currently disabled on Windows.

30 26 

31## Where Codex looks for hooks27## Where Codex looks for hooks

32 28 

33Codex discovers `hooks.json` next to active config layers.29Codex discovers hooks next to active config layers in either of these forms:

30 

31- `hooks.json`

32- inline `[hooks]` tables inside `config.toml`

34 33 

35In practice, the two most useful locations are:34In practice, the four most useful locations are:

36 35 

37- `~/.codex/hooks.json`36- `~/.codex/hooks.json`

37- `~/.codex/config.toml`

38- `<repo>/.codex/hooks.json`38- `<repo>/.codex/hooks.json`

39- `<repo>/.codex/config.toml`

39 40 

40If more than one `hooks.json` file exists, Codex loads all matching hooks.41If more than one hook source exists, Codex loads all matching hooks.

41Higher-precedence config layers don’t replace lower-precedence hooks.42Higher-precedence config layers do not replace lower-precedence hooks.

43If a single layer contains both `hooks.json` and inline `[hooks]`, Codex

44merges them and warns at startup. Prefer one representation per layer.

42 45 

43Project-local hooks load only when the project `.codex/` layer is trusted. In46Project-local hooks load only when the project `.codex/` layer is trusted. In

44untrusted projects, Codex still loads user and system hooks from their own47untrusted projects, Codex still loads user and system hooks from their own


131Notes:134Notes:

132 135 

133- `timeout` is in seconds.136- `timeout` is in seconds.

134- `timeoutSec` is also accepted as an alias.

135- If `timeout` is omitted, Codex uses `600` seconds.137- If `timeout` is omitted, Codex uses `600` seconds.

136- `statusMessage` is optional.138- `statusMessage` is optional.

137- Commands run with the session `cwd` as their working directory.139- Commands run with the session `cwd` as their working directory.


139 relative path such as `.codex/hooks/...`. Codex may be started from a141 relative path such as `.codex/hooks/...`. Codex may be started from a

140 subdirectory, and a git-root-based path keeps the hook location stable.142 subdirectory, and a git-root-based path keeps the hook location stable.

141 143 

144Equivalent inline TOML in `config.toml`:

145 

146```toml

147[features]

148codex_hooks = true

149 

150[[hooks.PreToolUse]]

151matcher = "^Bash$"

152 

153[[hooks.PreToolUse.hooks]]

154type = "command"

155command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'

156timeout = 30

157statusMessage = "Checking Bash command"

158 

159[[hooks.PostToolUse]]

160matcher = "^Bash$"

161 

162[[hooks.PostToolUse.hooks]]

163type = "command"

164command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py"'

165timeout = 30

166statusMessage = "Reviewing Bash output"

167```

168 

169## Managed hooks from `requirements.toml`

170 

171Enterprise-managed requirements can also define hooks inline under `[hooks]`.

172This is useful when admins want to enforce the hook configuration while

173delivering the actual scripts through MDM or another device-management system.

174 

175```toml

176[features]

177codex_hooks = true

178 

179[hooks]

180managed_dir = "/enterprise/hooks"

181windows_managed_dir = 'C:\enterprise\hooks'

182 

183[[hooks.PreToolUse]]

184matcher = "^Bash$"

185 

186[[hooks.PreToolUse.hooks]]

187type = "command"

188command = "python3 /enterprise/hooks/pre_tool_use_policy.py"

189timeout = 30

190statusMessage = "Checking managed Bash command"

191```

192 

193Notes for managed hooks:

194 

195- `managed_dir` is used on macOS and Linux.

196- `windows_managed_dir` is used on Windows.

197- Codex does not distribute the scripts in `managed_dir`; your enterprise

198 tooling must install and update them separately.

199- Managed hook commands should use absolute script paths under the configured

200 managed directory.

201 

142## Matcher patterns202## Matcher patterns

143 203 

144The `matcher` field is a regex string that filters when hooks fire. Use `"*"`,204The `matcher` field is a regex string that filters when hooks fire. Use `"*"`,


149 209 

150| Event | What `matcher` filters | Notes |210| Event | What `matcher` filters | Notes |

151| --- | --- | --- |211| --- | --- | --- |

152| `PermissionRequest` | tool name | Current Codex runtime only emits `Bash`. |212| `PermissionRequest` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

153| `PostToolUse` | tool name | Current Codex runtime only emits `Bash`. |213| `PostToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

154| `PreToolUse` | tool name | Current Codex runtime only emits `Bash`. |214| `PreToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

155| `SessionStart` | start source | Current runtime values are `startup` and `resume`. |215| `SessionStart` | start source | Current runtime values are `startup`, `resume`, and `clear` |

156| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event. |216| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event |

157| `Stop` | not supported | Any configured `matcher` is ignored for this event. |217| `Stop` | not supported | Any configured `matcher` is ignored for this event |

218 

219\*For `apply_patch`, matchers can also use `Edit` or `Write`.

158 220 

159Examples:221Examples:

160 222 

161- `Bash`223- `Bash`

162- `startup|resume`224- `^apply_patch$`

163- `Edit|Write`225- `Edit|Write`

164 226- `mcp__filesystem__read_file`

165That last example is still a valid regex, but current Codex `PreToolUse` and227- `mcp__filesystem__.*`

166`PostToolUse` events only emit `Bash`, so it won’t match anything today.228- `startup|resume|clear`

167 229 

168## Common input fields230## Common input fields

169 231 


242 304 

243### PreToolUse305### PreToolUse

244 306 

245Work in progress307`PreToolUse` can intercept Bash, file edits performed through `apply_patch`,

246 308and MCP tool calls. It is still a guardrail rather than a complete enforcement

247Currently `PreToolUse` only supports Bash tool interception. The model can309boundary because Codex can often perform equivalent work through another

248still work around this by writing its own script to disk and then running that310supported tool path.

249script with Bash, so treat this as a useful guardrail rather than a complete

250enforcement boundary

251 311 

252This doesn't intercept all shell calls yet, only the simple ones. The newer312This doesn't intercept all shell calls yet, only the simple ones. The newer

253 `unified_exec` mechanism allows richer streaming stdin/stdout handling of313 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

254shell, but interception is incomplete. Similarly, this doesnt intercept MCP,314 shell, but interception is incomplete. Similarly, this doesn't intercept

255Write, WebSearch, or other non-shell tool calls.315 `WebSearch` or other non-shell, non-MCP tool calls.

256 316 

257`matcher` is applied to `tool_name`, which currently always equals `Bash`.317`matcher` is applied to `tool_name` and matcher aliases. For file edits through

318`apply_patch`, matchers can use `apply_patch`, `Edit`, or `Write`; hook input

319still reports `tool_name: "apply_patch"`.

258 320 

259Fields in addition to [Common input fields](#common-input-fields):321Fields in addition to [Common input fields](#common-input-fields):

260 322 

261| Field | Type | Meaning |323| Field | Type | Meaning |

262| --- | --- | --- |324| --- | --- | --- |

263| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |325| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

264| `tool_name` | `string` | Currently always `Bash` |326| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

265| `tool_use_id` | `string` | Tool-call id for this invocation |327| `tool_use_id` | `string` | Tool-call id for this invocation |

266| `tool_input.command` | `string` | Shell command Codex is about to run |328| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

267 329 

268Plain text on `stdout` is ignored.330Plain text on `stdout` is ignored.

269 331 


297 359 

298### PermissionRequest360### PermissionRequest

299 361 

300Work in progress

301 

302`PermissionRequest` runs when Codex is about to ask for approval, such as a362`PermissionRequest` runs when Codex is about to ask for approval, such as a

303shell escalation or managed-network approval. It can allow the request, deny363shell escalation or managed-network approval. It can allow the request, deny

304the request, or decline to decide and let the normal approval prompt continue.364the request, or decline to decide and let the normal approval prompt continue.

305It doesn't run for commands that don't need approval.365It doesn't run for commands that don't need approval.

306 366 

307`matcher` is applied to `tool_name`, which currently always equals `Bash`.367`matcher` is applied to `tool_name` and matcher aliases. Current canonical

368values include `Bash`, `apply_patch`, and MCP tool names such as

369`mcp__server__tool`; `apply_patch` also matches `Edit` and `Write`.

308 370 

309Fields in addition to [Common input fields](#common-input-fields):371Fields in addition to [Common input fields](#common-input-fields):

310 372 

311| Field | Type | Meaning |373| Field | Type | Meaning |

312| --- | --- | --- |374| --- | --- | --- |

313| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |375| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

314| `tool_name` | `string` | Currently always `Bash` |376| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

315| `tool_input.command` | `string` | Shell command associated with the approval request |377| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

316| `tool_input.description` | `string | null` | Human-readable approval reason, when Codex has one |378| `tool_input.description` | `string | null` | Human-readable approval reason, when Codex has one |

317 379 

318Plain text on `stdout` is ignored.380Plain text on `stdout` is ignored.


354 416 

355### PostToolUse417### PostToolUse

356 418 

357Work in progress419`PostToolUse` runs after supported tools produce output, including Bash,

358 420`apply_patch`, and MCP tool calls. For Bash, it also runs after commands that

359Currently `PostToolUse` only supports Bash tool results. It’s not limited to421exit with a non-zero status. It can't undo side effects from the tool that

360commands that exit successfully: non-interactive `exec_command` calls can still422already ran.

361trigger `PostToolUse` when Codex emits a Bash post-tool payload. It can’t undo

362side effects from the command that already ran.

363 423 

364This doesn't intercept all shell calls yet, only the simple ones. The newer424This doesn't intercept all shell calls yet, only the simple ones. The newer

365 `unified_exec` mechanism allows richer streaming stdin/stdout handling of425 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

366shell, but interception is incomplete. Similarly, this doesnt intercept MCP,426 shell, but interception is incomplete. Similarly, this doesn't intercept

367Write, WebSearch, or other non-shell tool calls.427 `WebSearch` or other non-shell, non-MCP tool calls.

368 428 

369`matcher` is applied to `tool_name`, which currently always equals `Bash`.429`matcher` is applied to `tool_name` and matcher aliases. For file edits through

430`apply_patch`, matchers can use `apply_patch`, `Edit`, or `Write`; hook input

431still reports `tool_name: "apply_patch"`.

370 432 

371Fields in addition to [Common input fields](#common-input-fields):433Fields in addition to [Common input fields](#common-input-fields):

372 434 

373| Field | Type | Meaning |435| Field | Type | Meaning |

374| --- | --- | --- |436| --- | --- | --- |

375| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |437| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

376| `tool_name` | `string` | Currently always `Bash` |438| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

377| `tool_use_id` | `string` | Tool-call id for this invocation |439| `tool_use_id` | `string` | Tool-call id for this invocation |

378| `tool_input.command` | `string` | Shell command Codex just ran |440| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

379| `tool_response` | `JSON value` | Bash tool output payload. Today this is usually a JSON string |441| `tool_response` | `JSON value` | Tool-specific output. For MCP tools, this is the MCP call result. |

380 442 

381Plain text on `stdout` is ignored.443Plain text on `stdout` is ignored.

382 444