SpyBara
Go Premium Account
2026
23 Apr 2026, 12:28
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
18 May 2026, 22:01
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
Fri 1 18:29 Sat 2 00:48 Sat 2 06:45 Tue 5 23:00 Thu 7 17:08 Thu 7 20:02 Mon 11 18:00 Tue 12 01:59 Wed 13 00:57 Thu 14 07:00 Thu 14 21:00 Mon 18 22:01 Tue 19 11:58

After 2026-05-02 06:45 UTC, this monitor no longer uses markdownified HTML/MDX. Comparisons across that boundary can therefore show more extensive diffs.

hooks.md +232 −69

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 


12- Run a custom validation check when a conversation turn stops, enforcing standards9- Run a custom validation check when a conversation turn stops, enforcing standards

13- Customize prompting when in a certain directory10- Customize prompting when in a certain directory

14 11 

15Hooks are behind a feature flag in `config.toml`:12Hooks are enabled by default. If you need to turn them off in `config.toml`,

13set:

16 14 

17```toml15```toml

18[features]16[features]

19codex_hooks = true17hooks = false

20```18```

21 19 

20Use `hooks` as the canonical feature key. `codex_hooks` still works as a

21deprecated alias.

22 

23Admins can force hooks off the same way in `requirements.toml` with

24`[features].hooks = false`.

25 

22Runtime behavior to keep in mind:26Runtime behavior to keep in mind:

23 27 

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

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

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

31- Non-managed command hooks must be reviewed and trusted before they run.

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

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

29- Hooks are currently disabled on Windows.

30 34 

31## Where Codex looks for hooks35## Where Codex looks for hooks

32 36 

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

38 

39- `hooks.json`

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

34 41 

35In practice, the two most useful locations are:42Installed plugins can also bundle lifecycle config through their plugin

43manifest or a default `hooks/hooks.json` file. See [Build

44plugins](https://developers.openai.com/codex/plugins/build#bundled-mcp-servers-and-lifecycle-config) for the

45plugin packaging rules.

46 

47In practice, the four most useful locations are:

36 48 

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

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

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

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

53 

54If more than one hook source exists, Codex loads all matching hooks.

55Higher-precedence config layers don't replace lower-precedence hooks.

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

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

58 

59Plugin hooks are off by default in this release. If

60`[features].plugin_hooks = true`, Codex can also discover hooks bundled with

61enabled plugins. Otherwise, enabled plugins won't run bundled hooks.

62 

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

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

65active config layers.

39 66 

40If more than one `hooks.json` file exists, Codex loads all matching hooks.67## Review and manage hooks

41Higher-precedence config layers don’t replace lower-precedence hooks.68 

69Codex lists configured hooks before deciding which ones can run. Use `/hooks`

70in the CLI to inspect hook sources, review new or changed hooks, trust hooks, or

71disable individual non-managed hooks. If hooks need review at startup, Codex

72prints a warning that tells you to open `/hooks`.

73 

74Managed hooks from system, MDM, cloud, or `requirements.toml` sources are marked

75as managed, trusted by policy, and can't be disabled from the user hook browser.

42 76 

43## Config shape77## Config shape

44 78 


127Notes:161Notes:

128 162 

129- `timeout` is in seconds.163- `timeout` is in seconds.

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

131- If `timeout` is omitted, Codex uses `600` seconds.164- If `timeout` is omitted, Codex uses `600` seconds.

132- `statusMessage` is optional.165- `statusMessage` is optional.

166- `async` is parsed, but async command hooks aren't supported yet. Codex skips

167 handlers with `async: true`.

168- Only `type: "command"` handlers run today. `prompt` and `agent` handlers are

169 parsed but skipped.

133- Commands run with the session `cwd` as their working directory.170- Commands run with the session `cwd` as their working directory.

134- For repo-local hooks, prefer resolving from the git root instead of using a171- For repo-local hooks, prefer resolving from the git root instead of using a

135 relative path such as `.codex/hooks/...`. Codex may be started from a172 relative path such as `.codex/hooks/...`. Codex may be started from a

136 subdirectory, and a git-root-based path keeps the hook location stable.173 subdirectory, and a git-root-based path keeps the hook location stable.

137 174 

175Equivalent inline TOML in `config.toml`:

176 

177```toml

178[[hooks.PreToolUse]]

179matcher = "^Bash$"

180 

181[[hooks.PreToolUse.hooks]]

182type = "command"

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

184timeout = 30

185statusMessage = "Checking Bash command"

186 

187[[hooks.PostToolUse]]

188matcher = "^Bash$"

189 

190[[hooks.PostToolUse.hooks]]

191type = "command"

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

193timeout = 30

194statusMessage = "Reviewing Bash output"

195```

196 

197## Managed hooks from `requirements.toml`

198 

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

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

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

202To enforce managed hooks even for users who disabled hooks locally, pin

203`[features].hooks = true` in `requirements.toml` alongside `[hooks]`.

204 

205```toml

206[features]

207hooks = true

208 

209[hooks]

210managed_dir = "/enterprise/hooks"

211windows_managed_dir = 'C:\enterprise\hooks'

212 

213[[hooks.PreToolUse]]

214matcher = "^Bash$"

215 

216[[hooks.PreToolUse.hooks]]

217type = "command"

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

219timeout = 30

220statusMessage = "Checking managed Bash command"

221```

222 

223Notes for managed hooks:

224 

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

226- `windows_managed_dir` is used on Windows.

227- Codex doesn't distribute the scripts in `managed_dir`; your enterprise

228 tooling must install and update them separately.

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

230 managed directory.

231 

232## Plugin-bundled hooks

233 

234Plugin-bundled hooks are opt-in for this release. When

235`[features].plugin_hooks = true` and a plugin is enabled, Codex can load

236lifecycle hooks from that plugin alongside user, project, and managed hooks.

237 

238```toml

239[features]

240plugin_hooks = true

241```

242 

243By default, Codex looks for `hooks/hooks.json` inside the plugin root. A plugin

244manifest can override that default with a `hooks` entry in

245`.codex-plugin/plugin.json`. The manifest entry can be a `./`-prefixed path, an

246array of `./`-prefixed paths, an inline hooks object, or an array of inline

247hooks objects.

248 

249```json

250{

251 "name": "repo-policy",

252 "hooks": "./hooks/hooks.json"

253}

254```

255 

256Manifest hook paths are resolved relative to the plugin root and must stay

257inside that root. If a manifest defines `hooks`, Codex uses those manifest

258entries instead of the default `hooks/hooks.json`.

259 

260Plugin hook commands receive these environment variables:

261 

262- `PLUGIN_ROOT` is a Codex-specific extension that points to the installed

263 plugin root.

264- `PLUGIN_DATA` is a Codex-specific extension that points to the plugin's

265 writable data directory.

266- Codex also sets `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PLUGIN_DATA` for

267 compatibility with existing plugin hooks.

268 

269Plugin hooks use the same event schema as other hooks. They are non-managed

270hooks, so they require trust review before they run.

271 

138## Matcher patterns272## Matcher patterns

139 273 

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


144Only some current Codex events honor `matcher`:278Only some current Codex events honor `matcher`:

145 279 

146| Event | What `matcher` filters | Notes |280| Event | What `matcher` filters | Notes |

147| --- | --- | --- |281| ------------------- | ---------------------- | ------------------------------------------------------------ |

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

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

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

151| `SessionStart` | start source | Current runtime values are `startup` and `resume`. |285| `SessionStart` | start source | Current runtime values are `startup`, `resume`, and `clear` |

152| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event. |286| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event |

153| `Stop` | not supported | Any configured `matcher` is ignored for this event. |287| `Stop` | not supported | Any configured `matcher` is ignored for this event |

288 

289\*For `apply_patch`, `matcher` values can also use `Edit` or `Write`.

154 290 

155Examples:291Examples:

156 292 

157- `Bash`293- `Bash`

158- `startup|resume`294- `^apply_patch$`

159- `Edit|Write`295- `Edit|Write`

160 296- `mcp__filesystem__read_file`

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

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

163 299 

164## Common input fields300## Common input fields

165 301 


168These are the shared fields you will usually use:304These are the shared fields you will usually use:

169 305 

170| Field | Type | Meaning |306| Field | Type | Meaning |

171| --- | --- | --- |307| ----------------- | ---------------- | ------------------------------------------- |

172| `session_id` | `string` | Current session or thread id. |308| `session_id` | `string` | Current session or thread id. |

173| `transcript_path` | `string | null` | Path to the session transcript file, if any |309| `transcript_path` | `string \| null` | Path to the session transcript file, if any |

174| `cwd` | `string` | Working directory for the session |310| `cwd` | `string` | Working directory for the session |

175| `hook_event_name` | `string` | Current hook event name |311| `hook_event_name` | `string` | Current hook event name |

176| `model` | `string` | Active model slug |312| `model` | `string` | Codex-specific extension. Active model slug |

177 313 

178Turn-scoped hooks list `turn_id` in their event-specific tables.314Turn-scoped hooks list `turn_id` as a Codex-specific extension in their

315event-specific tables.

316 

317`SessionStart`, `PreToolUse`, `PermissionRequest`, `PostToolUse`,

318`UserPromptSubmit`, and `Stop` also include `permission_mode`, which describes

319the current permission mode as `default`, `acceptEdits`, `plan`, `dontAsk`, or

320`bypassPermissions`.

321 

322`transcript_path` points to a conversation transcript for convenience, but the

323transcript format is not a stable interface for hooks and may change over time.

179 324 

180If you need the full wire format, see [Schemas](#schemas).325If you need the full wire format, see [Schemas](#schemas).

181 326 


217Fields in addition to [Common input fields](#common-input-fields):362Fields in addition to [Common input fields](#common-input-fields):

218 363 

219| Field | Type | Meaning |364| Field | Type | Meaning |

220| --- | --- | --- |365| -------- | -------- | -------------------------------------------------------- |

221| `source` | `string` | How the session started: `startup` or `resume` |366| `source` | `string` | How the session started: `startup`, `resume`, or `clear` |

222 367 

223Plain text on `stdout` is added as extra developer context.368Plain text on `stdout` is added as extra developer context.

224 369 


238 383 

239### PreToolUse384### PreToolUse

240 385 

241Work in progress386`PreToolUse` can intercept Bash, file edits performed through `apply_patch`,

242 387and MCP tool calls. It's still a guardrail rather than a complete enforcement

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

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

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

246enforcement boundary

247 390 

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

249 `unified_exec` mechanism allows richer streaming stdin/stdout handling of392 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

250shell, but interception is incomplete. Similarly, this doesnt intercept MCP,393 shell, but interception is incomplete. Similarly, this doesn't intercept

251Write, WebSearch, or other non-shell tool calls.394 `WebSearch` or other non-shell, non-MCP tool calls.

252 395 

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

397`apply_patch`, `matcher` values can use `apply_patch`, `Edit`, or `Write`; hook input

398still reports `tool_name: "apply_patch"`.

254 399 

255Fields in addition to [Common input fields](#common-input-fields):400Fields in addition to [Common input fields](#common-input-fields):

256 401 

257| Field | Type | Meaning |402| Field | Type | Meaning |

258| --- | --- | --- |403| ------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |

259| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |404| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

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

261| `tool_use_id` | `string` | Tool-call id for this invocation |406| `tool_use_id` | `string` | Tool-call id for this invocation |

262| `tool_input.command` | `string` | Shell command Codex is about to run |407| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all arguments. |

263 408 

264Plain text on `stdout` is ignored.409Plain text on `stdout` is ignored.

265 410 

266JSON on `stdout` can use `systemMessage` and can block a Bash command with this411JSON on `stdout` can use `systemMessage`. To deny a supported tool call, return

267hook-specific shape:412this hook-specific shape:

268 413 

269```json414```json

270{415{


287 432 

288You can also use exit code `2` and write the blocking reason to `stderr`.433You can also use exit code `2` and write the blocking reason to `stderr`.

289 434 

290`permissionDecision: "allow"` and `"ask"`, legacy `decision: "approve"`,435To add model-visible context without blocking, return

291`updatedInput`, `additionalContext`, `continue: false`, `stopReason`, and436`hookSpecificOutput.additionalContext`:

292`suppressOutput` are parsed but not supported yet, so they fail open.

293 437 

294### PermissionRequest438```json

439{

440 "hookSpecificOutput": {

441 "hookEventName": "PreToolUse",

442 "additionalContext": "The pending command touches generated files."

443 }

444}

445```

295 446 

296Work in progress447`permissionDecision: "ask"`, legacy `decision: "approve"`, `updatedInput`,

448`continue: false`, `stopReason`, and `suppressOutput` are parsed but not

449supported yet, so they fail open.

450 

451### PermissionRequest

297 452 

298`PermissionRequest` runs when Codex is about to ask for approval, such as a453`PermissionRequest` runs when Codex is about to ask for approval, such as a

299shell escalation or managed-network approval. It can allow the request, deny454shell escalation or managed-network approval. It can allow the request, deny

300the request, or decline to decide and let the normal approval prompt continue.455the request, or decline to decide and let the normal approval prompt continue.

301It doesn't run for commands that don't need approval.456It doesn't run for commands that don't need approval.

302 457 

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

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

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

304 461 

305Fields in addition to [Common input fields](#common-input-fields):462Fields in addition to [Common input fields](#common-input-fields):

306 463 

307| Field | Type | Meaning |464| Field | Type | Meaning |

308| --- | --- | --- |465| ------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------- |

309| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |466| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

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

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

312| `tool_input.description` | `string | null` | Human-readable approval reason, when Codex has one |469| `tool_input.description` | `string \| null` | Human-readable approval reason, when Codex has one |

313 470 

314Plain text on `stdout` is ignored.471Plain text on `stdout` is ignored.

315 472 

473Some tool inputs may include a human-readable description, but don't rely on a

474`tool_input.description` field for every tool.

475 

316To approve the request, return:476To approve the request, return:

317 477 

318```json478```json


350 510 

351### PostToolUse511### PostToolUse

352 512 

353Work in progress513`PostToolUse` runs after supported tools produce output, including Bash,

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

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

356commands that exit successfully: non-interactive `exec_command` calls can still516already ran.

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

358side effects from the command that already ran.

359 517 

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

361 `unified_exec` mechanism allows richer streaming stdin/stdout handling of519 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

362shell, but interception is incomplete. Similarly, this doesnt intercept MCP,520 shell, but interception is incomplete. Similarly, this doesn't intercept

363Write, WebSearch, or other non-shell tool calls.521 `WebSearch` or other non-shell, non-MCP tool calls.

364 522 

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

524`apply_patch`, `matcher` values can use `apply_patch`, `Edit`, or `Write`; hook input

525still reports `tool_name: "apply_patch"`.

366 526 

367Fields in addition to [Common input fields](#common-input-fields):527Fields in addition to [Common input fields](#common-input-fields):

368 528 

369| Field | Type | Meaning |529| Field | Type | Meaning |

370| --- | --- | --- |530| --------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |

371| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |531| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

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

373| `tool_use_id` | `string` | Tool-call id for this invocation |533| `tool_use_id` | `string` | Tool-call id for this invocation |

374| `tool_input.command` | `string` | Shell command Codex just ran |534| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all arguments. |

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

376 536 

377Plain text on `stdout` is ignored.537Plain text on `stdout` is ignored.

378 538 


411Fields in addition to [Common input fields](#common-input-fields):571Fields in addition to [Common input fields](#common-input-fields):

412 572 

413| Field | Type | Meaning |573| Field | Type | Meaning |

414| --- | --- | --- |574| --------- | -------- | ---------------------------------------------- |

415| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |575| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

416| `prompt` | `string` | User prompt that's about to be sent |576| `prompt` | `string` | User prompt that's about to be sent |

417 577 


449Fields in addition to [Common input fields](#common-input-fields):609Fields in addition to [Common input fields](#common-input-fields):

450 610 

451| Field | Type | Meaning |611| Field | Type | Meaning |

452| --- | --- | --- |612| ------------------------ | ---------------- | ------------------------------------------------- |

453| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |613| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |

454| `stop_hook_active` | `boolean` | Whether this turn was already continued by `Stop` |614| `stop_hook_active` | `boolean` | Whether this turn was already continued by `Stop` |

455| `last_assistant_message` | `string | null` | Latest assistant message text, if available |615| `last_assistant_message` | `string \| null` | Latest assistant message text, if available |

456 616 

457`Stop` expects JSON on `stdout` when it exits `0`. Plain text output is invalid617`Stop` expects JSON on `stdout` when it exits `0`. Plain text output is invalid

458for this event.618for this event.


478 638 

479## Schemas639## Schemas

480 640 

641The linked `main` branch schemas may include hook fields that are not in the

642 current release. Use this page as the release behavior reference.

643 

481If you need the exact current wire format, see the generated schemas in the644If you need the exact current wire format, see the generated schemas in the

482[Codex GitHub repository](https://github.com/openai/codex/tree/main/codex-rs/hooks/schema/generated).645[Codex GitHub repository](https://github.com/openai/codex/tree/main/codex-rs/hooks/schema/generated).