Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/api/json/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,12 @@
"fileMatch": ["**/.codex/config.toml"],
"url": "https://developers.openai.com/codex/config-schema.json"
},
{
"name": "Codex Hooks",
"description": "OpenAI Codex hooks configuration file",
"fileMatch": ["**/.codex/hooks.json"],
"url": "https://www.schemastore.org/codex-hooks.json"
},
{
"name": "codemagic",
"description": "Codemagic CI/CD file configuration",
Expand Down
13 changes: 13 additions & 0 deletions src/negative_test/codex-hooks/invalid-event-shape.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"hooks": {
"SessionStart": {
"hooks": [
{
"command": "python3 .codex/hooks/session_start.py",
"type": "command"
}
],
"matcher": "startup"
}
}
}
14 changes: 14 additions & 0 deletions src/negative_test/codex-hooks/missing-command.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hooks": {
"Stop": [
{
"hooks": [
{
"timeout": 10,
"type": "command"
}
]
}
]
}
}
135 changes: 135 additions & 0 deletions src/schemas/json/codex-hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://json.schemastore.org/codex-hooks.json",
"title": "Codex hooks configuration",
"description": "Configuration for OpenAI Codex lifecycle hooks.\nhttps://developers.openai.com/codex/hooks",
"type": "object",
"required": ["hooks"],
"additionalProperties": true,
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for Codex hooks configuration."
},
"description": {
"type": "string",
"description": "Human-readable description of the hooks file."
},
"hooks": {
"type": "object",
"description": "Hook event registrations grouped by Codex lifecycle event.",
"minProperties": 1,
"additionalProperties": {
"$ref": "#/definitions/matcherGroups"
},
"properties": {
"SessionStart": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs when a Codex session starts. The matcher filters the start source, such as startup, resume, or clear."
},
"PreToolUse": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs before supported tool calls. The matcher filters tool names and aliases."
},
"PermissionRequest": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs before Codex asks for approval. The matcher filters tool names and aliases."
},
"PostToolUse": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs after supported tool calls. The matcher filters tool names and aliases."
},
"UserPromptSubmit": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs before a user prompt is submitted. Codex currently ignores matcher for this event."
},
"Stop": {
"$ref": "#/definitions/matcherGroups",
"description": "Runs when a turn stops. Codex currently ignores matcher for this event."
}
}
}
},
"definitions": {
"matcherGroups": {
"type": "array",
"description": "Matcher groups for one Codex hook event.",
"minItems": 1,
"items": {
"$ref": "#/definitions/matcherGroup"
}
},
"matcherGroup": {
"type": "object",
"description": "Matcher group that decides when one or more hook handlers run.",
"required": ["hooks"],
"additionalProperties": true,
"properties": {
"matcher": {
"type": "string",
"description": "Regex string that filters when hooks fire. Use *, an empty string, or omit matcher to match every supported occurrence."
},
"hooks": {
"type": "array",
"description": "Handlers to run when this matcher group matches.",
"minItems": 1,
"items": {
"$ref": "#/definitions/hookHandler"
}
}
}
},
"hookHandler": {
"anyOf": [
{
"$ref": "#/definitions/commandHandler"
},
{
"$ref": "#/definitions/skippedHandler"
}
]
},
"commandHandler": {
"type": "object",
"description": "Command hook handler. Commands run with the session cwd as their working directory.",
"required": ["type", "command"],
"additionalProperties": true,
"properties": {
"type": {
"const": "command",
"description": "Command handlers are the only hook handler type that runs in the current Codex runtime."
},
"command": {
"type": "string",
"description": "Command to execute.",
"minLength": 1
},
"timeout": {
"type": "number",
"description": "Timeout in seconds. Codex uses 600 seconds when omitted.",
"minimum": 0
},
"statusMessage": {
"type": "string",
"description": "Optional status text shown while the hook runs."
},
"async": {
"type": "boolean",
"description": "Parsed by Codex, but async command hooks are not supported yet and async handlers are skipped."
}
}
},
"skippedHandler": {
"type": "object",
"description": "Prompt and agent handlers are parsed by Codex but skipped in the current runtime.",
"required": ["type"],
"additionalProperties": true,
"properties": {
"type": {
"type": "string",
"enum": ["prompt", "agent"]
}
}
}
}
}
64 changes: 64 additions & 0 deletions src/test/codex-hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"$schema": "https://json.schemastore.org/codex-hooks.json",
"description": "Project-level Codex hooks",
"hooks": {
"PermissionRequest": [
{
"hooks": [
{
"command": "python3 .codex/hooks/permission_request.py",
"timeout": 30,
"type": "command"
}
],
"matcher": "Bash|apply_patch"
}
],
"PostToolUse": [
{
"hooks": [
{
"async": false,
"command": "python3 .codex/hooks/post_tool_use.py",
"statusMessage": "Reviewing tool output",
"type": "command"
}
],
"matcher": "mcp__filesystem__.*"
}
],
"SessionStart": [
{
"hooks": [
{
"command": "python3 .codex/hooks/session_start.py",
"statusMessage": "Loading session notes",
"type": "command"
}
],
"matcher": "startup|resume"
}
],
"Stop": [
{
"hooks": [
{
"command": "python3 .codex/hooks/stop.py",
"timeout": 10,
"type": "command"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"command": "python3 .codex/hooks/user_prompt_submit.py",
"type": "command"
}
]
}
]
}
}