SpyBara
Go Premium Account
2026
21 Feb 2026, 00:33
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
7 May 2026, 20:02
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

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 +553 −0 added

Details

1# Hooks

2 

3Hooks are an extensibility framework for Codex. They allow

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

5 

6- Send the conversation to a custom logging/analytics engine

7- Scan your team's prompts to block accidentally pasting API keys

8- Summarize conversations to create persistent memories automatically

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

10- Customize prompting when in a certain directory

11 

12Hooks are behind a feature flag in `config.toml`:

13 

14```toml

15[features]

16codex_hooks = true

17```

18 

19Runtime behavior to keep in mind:

20 

21- Matching hooks from multiple files all run.

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

23 so one hook cannot prevent another matching hook from starting.

24- `PreToolUse`, `PermissionRequest`, `PostToolUse`, `UserPromptSubmit`, and

25 `Stop` run at turn scope.

26 

27## Where Codex looks for hooks

28 

29Codex discovers hooks next to active config layers in either of these forms:

30 

31- `hooks.json`

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

33 

34Installed plugins can also bundle lifecycle config through their plugin

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

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

37plugin packaging rules.

38 

39In practice, the four most useful locations are:

40 

41- `~/.codex/hooks.json`

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

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

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

45 

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

47Higher-precedence config layers do not replace lower-precedence hooks.

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

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

50 

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

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

53active config layers.

54 

55## Config shape

56 

57Hooks are organized in three levels:

58 

59- A hook event such as `PreToolUse`, `PostToolUse`, or `Stop`

60- A matcher group that decides when that event matches

61- One or more hook handlers that run when the matcher group matches

62 

63```json

64{

65 "hooks": {

66 "SessionStart": [

67 {

68 "matcher": "startup|resume",

69 "hooks": [

70 {

71 "type": "command",

72 "command": "python3 ~/.codex/hooks/session_start.py",

73 "statusMessage": "Loading session notes"

74 }

75 ]

76 }

77 ],

78 "PreToolUse": [

79 {

80 "matcher": "Bash",

81 "hooks": [

82 {

83 "type": "command",

84 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py\"",

85 "statusMessage": "Checking Bash command"

86 }

87 ]

88 }

89 ],

90 "PermissionRequest": [

91 {

92 "matcher": "Bash",

93 "hooks": [

94 {

95 "type": "command",

96 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",

97 "statusMessage": "Checking approval request"

98 }

99 ]

100 }

101 ],

102 "PostToolUse": [

103 {

104 "matcher": "Bash",

105 "hooks": [

106 {

107 "type": "command",

108 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py\"",

109 "statusMessage": "Reviewing Bash output"

110 }

111 ]

112 }

113 ],

114 "UserPromptSubmit": [

115 {

116 "hooks": [

117 {

118 "type": "command",

119 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/user_prompt_submit_data_flywheel.py\""

120 }

121 ]

122 }

123 ],

124 "Stop": [

125 {

126 "hooks": [

127 {

128 "type": "command",

129 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/stop_continue.py\"",

130 "timeout": 30

131 }

132 ]

133 }

134 ]

135 }

136}

137```

138 

139Notes:

140 

141- `timeout` is in seconds.

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

143- `statusMessage` is optional.

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

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

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

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

148 

149Equivalent inline TOML in `config.toml`:

150 

151```toml

152[features]

153codex_hooks = true

154 

155[[hooks.PreToolUse]]

156matcher = "^Bash$"

157 

158[[hooks.PreToolUse.hooks]]

159type = "command"

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

161timeout = 30

162statusMessage = "Checking Bash command"

163 

164[[hooks.PostToolUse]]

165matcher = "^Bash$"

166 

167[[hooks.PostToolUse.hooks]]

168type = "command"

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

170timeout = 30

171statusMessage = "Reviewing Bash output"

172```

173 

174## Managed hooks from `requirements.toml`

175 

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

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

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

179 

180```toml

181[features]

182codex_hooks = true

183 

184[hooks]

185managed_dir = "/enterprise/hooks"

186windows_managed_dir = 'C:\enterprise\hooks'

187 

188[[hooks.PreToolUse]]

189matcher = "^Bash$"

190 

191[[hooks.PreToolUse.hooks]]

192type = "command"

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

194timeout = 30

195statusMessage = "Checking managed Bash command"

196```

197 

198Notes for managed hooks:

199 

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

201- `windows_managed_dir` is used on Windows.

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

203 tooling must install and update them separately.

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

205 managed directory.

206 

207## Matcher patterns

208 

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

210`""`, or omit `matcher` entirely to match every occurrence of a supported

211event.

212 

213Only some current Codex events honor `matcher`:

214 

215| Event | What `matcher` filters | Notes |

216| ------------------- | ---------------------- | ------------------------------------------------------------ |

217| `PermissionRequest` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

218| `PostToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

219| `PreToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |

220| `SessionStart` | start source | Current runtime values are `startup`, `resume`, and `clear` |

221| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event |

222| `Stop` | not supported | Any configured `matcher` is ignored for this event |

223 

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

225 

226Examples:

227 

228- `Bash`

229- `^apply_patch$`

230- `Edit|Write`

231- `mcp__filesystem__read_file`

232- `mcp__filesystem__.*`

233- `startup|resume|clear`

234 

235## Common input fields

236 

237Every command hook receives one JSON object on `stdin`.

238 

239These are the shared fields you will usually use:

240 

241| Field | Type | Meaning |

242| ----------------- | ---------------- | ------------------------------------------- |

243| `session_id` | `string` | Current session or thread id. |

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

245| `cwd` | `string` | Working directory for the session |

246| `hook_event_name` | `string` | Current hook event name |

247| `model` | `string` | Active model slug |

248 

249Turn-scoped hooks list `turn_id` in their event-specific tables.

250 

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

252 

253## Common output fields

254 

255`SessionStart`, `UserPromptSubmit`, and `Stop` support these shared JSON

256fields:

257 

258```json

259{

260 "continue": true,

261 "stopReason": "optional",

262 "systemMessage": "optional",

263 "suppressOutput": false

264}

265```

266 

267| Field | Effect |

268| ---------------- | ----------------------------------------------- |

269| `continue` | If `false`, marks that hook run as stopped |

270| `stopReason` | Recorded as the reason for stopping |

271| `systemMessage` | Surfaced as a warning in the UI or event stream |

272| `suppressOutput` | Parsed today but not yet implemented |

273 

274Exit `0` with no output is treated as success and Codex continues.

275 

276`PreToolUse` and `PermissionRequest` support `systemMessage`, but `continue`,

277`stopReason`, and `suppressOutput` aren't currently supported for those events.

278 

279`PostToolUse` supports `systemMessage`, `continue: false`, and `stopReason`.

280`suppressOutput` is parsed but not currently supported for that event.

281 

282## Hooks

283 

284### SessionStart

285 

286`matcher` is applied to `source` for this event.

287 

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

289 

290| Field | Type | Meaning |

291| -------- | -------- | ---------------------------------------------- |

292| `source` | `string` | How the session started: `startup` or `resume` |

293 

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

295 

296JSON on `stdout` supports [Common output fields](#common-output-fields) and this

297hook-specific shape:

298 

299```json

300{

301 "hookSpecificOutput": {

302 "hookEventName": "SessionStart",

303 "additionalContext": "Load the workspace conventions before editing."

304 }

305}

306```

307 

308That `additionalContext` text is added as extra developer context.

309 

310### PreToolUse

311 

312`PreToolUse` can intercept Bash, file edits performed through `apply_patch`,

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

314boundary because Codex can often perform equivalent work through another

315supported tool path.

316 

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

318 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

319 shell, but interception is incomplete. Similarly, this doesn't intercept

320 `WebSearch` or other non-shell, non-MCP tool calls.

321 

322`matcher` is applied to `tool_name` and matcher aliases. For file edits through

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

324still reports `tool_name: "apply_patch"`.

325 

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

327 

328| Field | Type | Meaning |

329| ------------- | ------------ | --------------------------------------------------------------------------------------------------------- |

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

331| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

332| `tool_use_id` | `string` | Tool-call id for this invocation |

333| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

334 

335Plain text on `stdout` is ignored.

336 

337JSON on `stdout` can use `systemMessage` and can block a Bash command with this

338hook-specific shape:

339 

340```json

341{

342 "hookSpecificOutput": {

343 "hookEventName": "PreToolUse",

344 "permissionDecision": "deny",

345 "permissionDecisionReason": "Destructive command blocked by hook."

346 }

347}

348```

349 

350Codex also accepts this older block shape:

351 

352```json

353{

354 "decision": "block",

355 "reason": "Destructive command blocked by hook."

356}

357```

358 

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

360 

361`permissionDecision: "allow"` and `"ask"`, legacy `decision: "approve"`,

362`updatedInput`, `additionalContext`, `continue: false`, `stopReason`, and

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

364 

365### PermissionRequest

366 

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

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

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

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

371 

372`matcher` is applied to `tool_name` and matcher aliases. Current canonical

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

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

375 

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

377 

378| Field | Type | Meaning |

379| ------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------- |

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

381| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

382| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

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

384 

385Plain text on `stdout` is ignored.

386 

387To approve the request, return:

388 

389```json

390{

391 "hookSpecificOutput": {

392 "hookEventName": "PermissionRequest",

393 "decision": {

394 "behavior": "allow"

395 }

396 }

397}

398```

399 

400To deny the request, return:

401 

402```json

403{

404 "hookSpecificOutput": {

405 "hookEventName": "PermissionRequest",

406 "decision": {

407 "behavior": "deny",

408 "message": "Blocked by repository policy."

409 }

410 }

411}

412```

413 

414If multiple matching hooks return decisions, any `deny` wins. Otherwise, an

415`allow` lets the request proceed without surfacing the approval prompt. If no

416matching hook decides, Codex uses the normal approval flow.

417 

418Don't return `updatedInput`, `updatedPermissions`, or `interrupt` for

419`PermissionRequest`; those fields are reserved for future behavior and fail

420closed today.

421 

422### PostToolUse

423 

424`PostToolUse` runs after supported tools produce output, including Bash,

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

426exit with a non-zero status. It can't undo side effects from the tool that

427already ran.

428 

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

430 `unified_exec` mechanism allows richer streaming stdin/stdout handling of

431 shell, but interception is incomplete. Similarly, this doesn't intercept

432 `WebSearch` or other non-shell, non-MCP tool calls.

433 

434`matcher` is applied to `tool_name` and matcher aliases. For file edits through

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

436still reports `tool_name: "apply_patch"`.

437 

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

439 

440| Field | Type | Meaning |

441| --------------- | ------------ | --------------------------------------------------------------------------------------------------------- |

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

443| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |

444| `tool_use_id` | `string` | Tool-call id for this invocation |

445| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |

446| `tool_response` | `JSON value` | Tool-specific output. For MCP tools, this is the MCP call result. |

447 

448Plain text on `stdout` is ignored.

449 

450JSON on `stdout` can use `systemMessage` and this hook-specific shape:

451 

452```json

453{

454 "decision": "block",

455 "reason": "The Bash output needs review before continuing.",

456 "hookSpecificOutput": {

457 "hookEventName": "PostToolUse",

458 "additionalContext": "The command updated generated files."

459 }

460}

461```

462 

463That `additionalContext` text is added as extra developer context.

464 

465For this event, `decision: "block"` doesn't undo the completed Bash command.

466Instead, Codex records the feedback, replaces the tool result with that

467feedback, and continues the model from the hook-provided message.

468 

469You can also use exit code `2` and write the feedback reason to `stderr`.

470 

471To stop normal processing of the original tool result after the command has

472already run, return `continue: false`. Codex will replace the tool result with

473your feedback or stop text and continue from there.

474 

475`updatedMCPToolOutput` and `suppressOutput` are parsed but not supported yet,

476so they fail open.

477 

478### UserPromptSubmit

479 

480`matcher` isn't currently used for this event.

481 

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

483 

484| Field | Type | Meaning |

485| --------- | -------- | ---------------------------------------------- |

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

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

488 

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

490 

491JSON on `stdout` supports [Common output fields](#common-output-fields) and

492this hook-specific shape:

493 

494```json

495{

496 "hookSpecificOutput": {

497 "hookEventName": "UserPromptSubmit",

498 "additionalContext": "Ask for a clearer reproduction before editing files."

499 }

500}

501```

502 

503That `additionalContext` text is added as extra developer context.

504 

505To block the prompt, return:

506 

507```json

508{

509 "decision": "block",

510 "reason": "Ask for confirmation before doing that."

511}

512```

513 

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

515 

516### Stop

517 

518`matcher` isn't currently used for this event.

519 

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

521 

522| Field | Type | Meaning |

523| ------------------------ | ---------------- | ------------------------------------------------- |

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

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

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

527 

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

529for this event.

530 

531JSON on `stdout` supports [Common output fields](#common-output-fields). To keep

532Codex going, return:

533 

534```json

535{

536 "decision": "block",

537 "reason": "Run one more pass over the failing tests."

538}

539```

540 

541You can also use exit code `2` and write the continuation reason to `stderr`.

542 

543For this event, `decision: "block"` doesn't reject the turn. Instead, it tells

544Codex to continue and automatically creates a new continuation prompt that acts

545as a new user prompt, using your `reason` as that prompt text.

546 

547If any matching `Stop` hook returns `continue: false`, that takes precedence

548over continuation decisions from other matching `Stop` hooks.

549 

550## Schemas

551 

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

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