Add persisted hook enablement state (#19840)

## Why

After `hooks/list` exposes the hook inventory, clients need a way to
persist user hook preferences, make those changes effective in
already-open sessions, and distinguish user-controllable hooks from
managed requirements without adding another bespoke app-server write
API.

## What

- Extends `hooks/list` entries with effective `enabled` state.
- Persists user-level hook state under `hooks.state.<hook-id>` so the
model can grow beyond a single boolean over time.
- Uses the existing `config/batchWrite` path for hook state updates
instead of introducing a dedicated hook write RPC.
- Refreshes live session hook engines after config writes so
already-open threads observe updated enablement without a restart.

## Stack

1. openai/codex#19705
2. openai/codex#19778
3. This PR - openai/codex#19840
4. openai/codex#19882

## Reviewer Notes

The generated schema files account for much of the raw diff. The core
behavior is in:

- `hooks/src/config_rules.rs`, which resolves per-hook user state from
the config layer stack.
- `hooks/src/engine/discovery.rs`, which projects effective enablement
into `hooks/list` from source-derived managedness.
- `config/src/hook_config.rs`, which defines the new `hooks.state`
representation.
- `core/src/session/mod.rs`, which rebuilds live hook state after user
config reloads.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
AbhinavandCodex authored and GitHub committed 2026-04-30 04:46:32 +00:00
1 parent ac4332c05b
commit 8f3c06cc97
39 files changed
+1212 -181

No files matched your search

+63 -49
View File
@@ -884,53 +884,6 @@
}
]
},
"HookEventsToml": {
"properties": {
"PermissionRequest": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"PostToolUse": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"PreToolUse": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"SessionStart": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"Stop": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"UserPromptSubmit": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
}
},
"type": "object"
},
"HookHandlerConfig": {
"oneOf": [
{
@@ -995,6 +948,67 @@
}
]
},
"HookStateToml": {
"properties": {
"enabled": {
"type": "boolean"
}
},
"type": "object"
},
"HooksToml": {
"properties": {
"PermissionRequest": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"PostToolUse": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"PreToolUse": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"SessionStart": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"Stop": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"UserPromptSubmit": {
"default": [],
"items": {
"$ref": "#/definitions/MatcherGroup"
},
"type": "array"
},
"state": {
"additionalProperties": {
"$ref": "#/definitions/HookStateToml"
},
"type": "object"
}
},
"type": "object"
},
"KeybindingsSpec": {
"anyOf": [
{
@@ -3653,10 +3667,10 @@
"hooks": {
"allOf": [
{
"$ref": "#/definitions/HookEventsToml"
"$ref": "#/definitions/HooksToml"
}
],
"description": "Lifecycle hooks configured inline in TOML."
"description": "Lifecycle hooks configured inline in TOML plus user-level overrides."
},
"include_apps_instructions": {
"description": "Whether to inject the `<apps_instructions>` developer block.",