hooks.md +309 −62
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
9- Send the conversation to a custom logging/analytics engine6- Send the conversation to a custom logging/analytics engine
10- Scan your team's prompts to block accidentally pasting API keys7- Scan your team's prompts to block accidentally pasting API keys
11- Summarize conversations to create persistent memories automatically8- Summarize conversations to create persistent memories automatically
129- Run a custom validator when a conversation turn stops, enforcing standards- 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
1512Hooks are behind a feature flag in `config.toml`:Hooks are enabled by default. If you need to turn them off in `config.toml`,
13set:
16 14
17```toml15```toml
18[features]16[features]
1917codex_hooks = truehooks = 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 cannot prevent another matching hook from starting.30 so one hook cannot prevent another matching hook from starting.
2731- `PreToolUse`, `PostToolUse`, `UserPromptSubmit`, and `Stop` run at turn- Non-managed command hooks must be reviewed and trusted before they run.
2832 scope.- `PreToolUse`, `PermissionRequest`, `PostToolUse`, `UserPromptSubmit`, and
2933- Hooks are currently disabled on Windows. `Stop` run at turn scope.
30 34
31## Where Codex looks for hooks35## Where Codex looks for hooks
32 36
3337Codex discovers `hooks.json` next to active config layers.Codex 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
3542In practice, the two most useful locations are:Installed 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.
39 62
4063If more than one `hooks.json` file exists, Codex loads all matching hooks.Project-local hooks load only when the project `.codex/` layer is trusted. In
4164Higher-precedence config layers do not replace lower-precedence hooks.untrusted projects, Codex still loads user and system hooks from their own
65active config layers.
66
67## Review and manage 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
75 ]109 ]
76 }110 }
77 ],111 ],
112 "PermissionRequest": [
113 {
114 "matcher": "Bash",
115 "hooks": [
116 {
117 "type": "command",
118 "command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",
119 "statusMessage": "Checking approval request"
120 }
121 ]
122 }
123 ],
78 "PostToolUse": [124 "PostToolUse": [
79 {125 {
80 "matcher": "Bash",126 "matcher": "Bash",
115Notes:161Notes:
116 162
117- `timeout` is in seconds.163- `timeout` is in seconds.
118- `timeoutSec` is also accepted as an alias.
119- If `timeout` is omitted, Codex uses `600` seconds.164- If `timeout` is omitted, Codex uses `600` seconds.
120- `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.
121- Commands run with the session `cwd` as their working directory.170- Commands run with the session `cwd` as their working directory.
122- 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
123 relative path such as `.codex/hooks/...`. Codex may be started from a172 relative path such as `.codex/hooks/...`. Codex may be started from a
124 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.
125 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
126## Matcher patterns272## Matcher patterns
127 273
128The `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 `"*"`,
132Only some current Codex events honor `matcher`:278Only some current Codex events honor `matcher`:
133 279
134| Event | What `matcher` filters | Notes |280| Event | What `matcher` filters | Notes |
135281| --- | --- | --- || ------------------- | ---------------------- | ------------------------------------------------------------ |
136282| `PostToolUse` | tool name | Current Codex runtime only emits `Bash`. || `PermissionRequest` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |
137283| `PreToolUse` | tool name | Current Codex runtime only emits `Bash`. || `PostToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |
138284| `SessionStart` | start source | Current runtime values are `startup` and `resume`. || `PreToolUse` | tool name | Support includes `Bash`, `apply_patch`\*, and MCP tool names |
139285| `UserPromptSubmit` | not supported | Any configured `matcher` is ignored for this event. || `SessionStart` | start source | Current runtime values are `startup`, `resume`, and `clear` |
140286| `Stop` | not supported | Any configured `matcher` is ignored for this event. || `UserPromptSubmit` | 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`.
141 290
142Examples:291Examples:
143 292
144- `Bash`293- `Bash`
145294- `startup|resume`- `^apply_patch$`
146- `Edit|Write`295- `Edit|Write`
147296 - `mcp__filesystem__read_file`
148297That last example is still a valid regex, but current Codex `PreToolUse` and- `mcp__filesystem__.*`
149298`PostToolUse` events only emit `Bash`, so it will not match anything today.- `startup|resume|clear`
150 299
151## Common input fields300## Common input fields
152 301
155These are the shared fields you will usually use:304These are the shared fields you will usually use:
156 305
157| Field | Type | Meaning |306| Field | Type | Meaning |
158307| --- | --- | --- || ----------------- | ---------------- | ------------------------------------------- |
159| `session_id` | `string` | Current session or thread id. |308| `session_id` | `string` | Current session or thread id. |
160309| `transcript_path` | `string | null` | Path to the session transcript file, if any || `transcript_path` | `string \| null` | Path to the session transcript file, if any |
161| `cwd` | `string` | Working directory for the session |310| `cwd` | `string` | Working directory for the session |
162| `hook_event_name` | `string` | Current hook event name |311| `hook_event_name` | `string` | Current hook event name |
163312| `model` | `string` | Active model slug || `model` | `string` | Codex-specific extension. Active model slug |
313
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`.
164 321
165322Turn-scoped hooks list `turn_id` in their event-specific tables.`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.
166 324
167If you need the full wire format, see [Schemas](#schemas).325If you need the full wire format, see [Schemas](#schemas).
168 326
189 347
190Exit `0` with no output is treated as success and Codex continues.348Exit `0` with no output is treated as success and Codex continues.
191 349
192350`PreToolUse` supports `systemMessage`, but `continue`, `stopReason`, and`PreToolUse` and `PermissionRequest` support `systemMessage`, but `continue`,
193351`suppressOutput` are not currently supported for that event.`stopReason`, and `suppressOutput` aren't currently supported for those events.
194 352
195`PostToolUse` supports `systemMessage`, `continue: false`, and `stopReason`.353`PostToolUse` supports `systemMessage`, `continue: false`, and `stopReason`.
196`suppressOutput` is parsed but not currently supported for that event.354`suppressOutput` is parsed but not currently supported for that event.
204Fields in addition to [Common input fields](#common-input-fields):362Fields in addition to [Common input fields](#common-input-fields):
205 363
206| Field | Type | Meaning |364| Field | Type | Meaning |
207365| --- | --- | --- || -------- | -------- | -------------------------------------------------------- |
208366| `source` | `string` | How the session started: `startup` or `resume` || `source` | `string` | How the session started: `startup`, `resume`, or `clear` |
209 367
210Plain text on `stdout` is added as extra developer context.368Plain text on `stdout` is added as extra developer context.
211 369
225 383
226### PreToolUse384### PreToolUse
227 385
228386Currently `PreToolUse` only supports Bash tool interception. The model can`PreToolUse` can intercept Bash, file edits performed through `apply_patch`,
229387still work around this by writing its own script to disk and then running thatand MCP tool calls. It's still a guardrail rather than a complete enforcement
230388script with Bash, so treat this as a useful guardrail rather than a completeboundary because Codex can often perform equivalent work through another
231389enforcement boundary.supported tool path.
232 390
233391`matcher` is applied to `tool_name`, which currently always equals `Bash`.This doesn't intercept all shell calls yet, only the simple ones. The newer
392 `unified_exec` mechanism allows richer streaming stdin/stdout handling of
393 shell, but interception is incomplete. Similarly, this doesn't intercept
394 `WebSearch` or other non-shell, non-MCP tool calls.
395
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"`.
234 399
235Fields in addition to [Common input fields](#common-input-fields):400Fields in addition to [Common input fields](#common-input-fields):
236 401
237| Field | Type | Meaning |402| Field | Type | Meaning |
238403| --- | --- | --- || ------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |
239| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |404| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |
240405| `tool_name` | `string` | Currently always `Bash` || `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |
241| `tool_use_id` | `string` | Tool-call id for this invocation |406| `tool_use_id` | `string` | Tool-call id for this invocation |
242407| `tool_input.command` | `string` | Shell command Codex is about to run || `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all arguments. |
243 408
244Plain text on `stdout` is ignored.409Plain text on `stdout` is ignored.
245 410
246411JSON on `stdout` can use `systemMessage` and can block a Bash command with thisJSON on `stdout` can use `systemMessage`. To deny a supported tool call, return
247412hook-specific shape:this hook-specific shape:
248 413
249```json414```json
250{415{
267 432
268You 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`.
269 434
270435`permissionDecision: "allow"` and `"ask"`, legacy `decision: "approve"`,To add model-visible context without blocking, return
271436`updatedInput`, `additionalContext`, `continue: false`, `stopReason`, and`hookSpecificOutput.additionalContext`:
272437`suppressOutput` are parsed but not supported yet, so they fail open.
438```json
439{
440 "hookSpecificOutput": {
441 "hookEventName": "PreToolUse",
442 "additionalContext": "The pending command touches generated files."
443 }
444}
445```
446
447`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
452
453`PermissionRequest` runs when Codex is about to ask for approval, such as a
454shell escalation or managed-network approval. It can allow the request, deny
455the request, or decline to decide and let the normal approval prompt continue.
456It doesn't run for commands that don't need approval.
457
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`.
461
462Fields in addition to [Common input fields](#common-input-fields):
463
464| Field | Type | Meaning |
465| ------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------- |
466| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |
467| `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |
468| `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all the args. |
469| `tool_input.description` | `string \| null` | Human-readable approval reason, when Codex has one |
470
471Plain text on `stdout` is ignored.
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
476To approve the request, return:
477
478```json
479{
480 "hookSpecificOutput": {
481 "hookEventName": "PermissionRequest",
482 "decision": {
483 "behavior": "allow"
484 }
485 }
486}
487```
488
489To deny the request, return:
490
491```json
492{
493 "hookSpecificOutput": {
494 "hookEventName": "PermissionRequest",
495 "decision": {
496 "behavior": "deny",
497 "message": "Blocked by repository policy."
498 }
499 }
500}
501```
502
503If multiple matching hooks return decisions, any `deny` wins. Otherwise, an
504`allow` lets the request proceed without surfacing the approval prompt. If no
505matching hook decides, Codex uses the normal approval flow.
506
507Don't return `updatedInput`, `updatedPermissions`, or `interrupt` for
508`PermissionRequest`; those fields are reserved for future behavior and fail
509closed today.
273 510
274### PostToolUse511### PostToolUse
275 512
276513Currently `PostToolUse` only supports Bash tool results. It is not limited to`PostToolUse` runs after supported tools produce output, including Bash,
277514commands that exit successfully: non-interactive `exec_command` calls can still`apply_patch`, and MCP tool calls. For Bash, it also runs after commands that
278515trigger `PostToolUse` when Codex emits a Bash post-tool payload. It cannot undoexit with a non-zero status. It can't undo side effects from the tool that
279516side effects from the command that already ran.already ran.
517
518This doesn't intercept all shell calls yet, only the simple ones. The newer
519 `unified_exec` mechanism allows richer streaming stdin/stdout handling of
520 shell, but interception is incomplete. Similarly, this doesn't intercept
521 `WebSearch` or other non-shell, non-MCP tool calls.
280 522
281523`matcher` is applied to `tool_name`, which currently always equals `Bash`.`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"`.
282 526
283Fields in addition to [Common input fields](#common-input-fields):527Fields in addition to [Common input fields](#common-input-fields):
284 528
285| Field | Type | Meaning |529| Field | Type | Meaning |
286530| --- | --- | --- || --------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |
287| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |531| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |
288532| `tool_name` | `string` | Currently always `Bash` || `tool_name` | `string` | Canonical hook tool name, such as `Bash`, `apply_patch`, or an MCP name like `mcp__fs__read` |
289| `tool_use_id` | `string` | Tool-call id for this invocation |533| `tool_use_id` | `string` | Tool-call id for this invocation |
290534| `tool_input.command` | `string` | Shell command Codex just ran || `tool_input` | `JSON value` | Tool-specific input. `Bash` and `apply_patch` use `tool_input.command` while MCP tools send all arguments. |
291535| `tool_response` | `JSON value` | Bash tool output payload. Today this is usually a JSON string || `tool_response` | `JSON value` | Tool-specific output. For MCP tools, this is the MCP call result. |
292 536
293Plain text on `stdout` is ignored.537Plain text on `stdout` is ignored.
294 538
307 551
308That `additionalContext` text is added as extra developer context.552That `additionalContext` text is added as extra developer context.
309 553
310554For this event, `decision: "block"` does not undo the completed Bash command.For this event, `decision: "block"` doesn't undo the completed Bash command.
311Instead, Codex records the feedback, replaces the tool result with that555Instead, Codex records the feedback, replaces the tool result with that
312feedback, and continues the model from the hook-provided message.556feedback, and continues the model from the hook-provided message.
313 557
322 566
323### UserPromptSubmit567### UserPromptSubmit
324 568
325569`matcher` is not currently used for this event.`matcher` isn't currently used for this event.
326 570
327Fields in addition to [Common input fields](#common-input-fields):571Fields in addition to [Common input fields](#common-input-fields):
328 572
329| Field | Type | Meaning |573| Field | Type | Meaning |
330574| --- | --- | --- || --------- | -------- | ---------------------------------------------- |
331| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |575| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |
332576| `prompt` | `string` | User prompt that is about to be sent || `prompt` | `string` | User prompt that's about to be sent |
333 577
334Plain text on `stdout` is added as extra developer context.578Plain text on `stdout` is added as extra developer context.
335 579
360 604
361### Stop605### Stop
362 606
363607`matcher` is not currently used for this event.`matcher` isn't currently used for this event.
364 608
365Fields in addition to [Common input fields](#common-input-fields):609Fields in addition to [Common input fields](#common-input-fields):
366 610
367| Field | Type | Meaning |611| Field | Type | Meaning |
368612| --- | --- | --- || ------------------------ | ---------------- | ------------------------------------------------- |
369| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |613| `turn_id` | `string` | Codex-specific extension. Active Codex turn id |
370| `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` |
371615| `last_assistant_message` | `string | null` | Latest assistant message text, if available || `last_assistant_message` | `string \| null` | Latest assistant message text, if available |
372 616
373`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
374for this event.618for this event.
385 629
386You can also use exit code `2` and write the continuation reason to `stderr`.630You can also use exit code `2` and write the continuation reason to `stderr`.
387 631
388632For this event, `decision: "block"` does not reject the turn. Instead, it tellsFor this event, `decision: "block"` doesn't reject the turn. Instead, it tells
389Codex to continue and automatically creates a new continuation prompt that acts633Codex to continue and automatically creates a new continuation prompt that acts
390as a new user prompt, using your `reason` as that prompt text.634as a new user prompt, using your `reason` as that prompt text.
391 635
394 638
395## Schemas639## Schemas
396 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
397If 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
398[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).