Skip to content

Add hooks/list app-server RPC#19778

Merged
abhinav-oai merged 39 commits intomainfrom
dev/abhinav/hooks-list-config
Apr 29, 2026
Merged

Add hooks/list app-server RPC#19778
abhinav-oai merged 39 commits intomainfrom
dev/abhinav/hooks-list-config

Conversation

@abhinav-oai
Copy link
Copy Markdown
Collaborator

@abhinav-oai abhinav-oai commented Apr 27, 2026

Why

We need a way to list the available hooks to expose via the TUI and App so users can view and manage their hooks

What

  • Adds hooks/list for one or more cwd values that returns discovered hook metadata

Stack

  1. Discover hooks bundled with plugins #19705
  2. This PR - Add hooks/list app-server RPC #19778
  3. Add persisted hook enablement state #19840
  4. Add /hooks browser for lifecycle hooks #19882

Review Notes

The generated schema files account for most of the raw diff, these files have the core change:

  • hooks/src/engine/discovery.rs builds the inventory entries during hook discovery while leaving runtime handlers focused on execution.
  • app-server/src/codex_message_processor.rs wires hooks/list into the app-server flow for each requested cwd.
  • app-server-protocol/src/protocol/v2.rs defines the new v2 request/response payloads exposed on the wire.

Core Changes

core/src/plugins/manager.rs adds plugins_for_layer_stack(...) so skills/list and hooks/listcan resolve plugin state for each requested cwd

Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request Apr 27, 2026
- anomalyco/opencode#24574 ignore: split up reasoning transforms (merge-as-is)
- anomalyco/opencode#24573 fix: vertex anthropic toolStreaming default (merge-as-is)
- openai/codex#19778 hooks/list + hooks/config/write APIs (merge-after-nits)
- openai/codex#19772 permissions: derive config defaults as profiles (merge-after-nits)
@abhinav-oai abhinav-oai changed the title Add hook listing and config APIs Add hooks/list inventory API Apr 27, 2026
@abhinav-oai abhinav-oai changed the title Add hooks/list inventory API Add hooks/list app-server RPC Apr 27, 2026
@abhinav-oai abhinav-oai marked this pull request as ready for review April 28, 2026 00:02
@abhinav-oai abhinav-oai requested a review from a team as a code owner April 28, 2026 00:02
…ry' into dev/abhinav/hooks-list-config

# Conflicts:
#	codex-rs/core-plugins/src/loader.rs
#	codex-rs/hooks/src/engine/discovery.rs
Comment thread codex-rs/core/src/plugins/manager.rs Outdated
configured_marketplace_upgrade_state: RwLock<ConfiguredMarketplaceUpgradeState>,
non_curated_cache_refresh_state: RwLock<NonCuratedCacheRefreshState>,
cached_enabled_outcome: RwLock<Option<PluginLoadOutcome>>,
cached_enabled_outcome: RwLock<Option<(bool, PluginLoadOutcome)>>,
Copy link
Copy Markdown
Collaborator Author

@abhinav-oai abhinav-oai Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need this in case the flag changes, we can't return the same cached results

temporary while plugin_hooks is under development, will rip all this out once the safety + trust has landed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment suggesting the meaning of this bool so people don't need to read the code?

@abhinav-oai
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 425cd2d72b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

)
.await;
let hooks = codex_hooks::list_hooks(codex_hooks::HooksConfig {
feature_enabled: config.features.enabled(Feature::CodexHooks),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use per-cwd feature flags when listing hooks

hooks_list_response resolves a config layer stack for each requested cwd, but it gates plugin hooks and codex hooks using config.features loaded once before the loop. If different cwds have different feature settings (e.g. features.codex_hooks or features.plugin_hooks), the API returns incorrect hook inventories for non-primary paths.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

@abhinav-oai abhinav-oai Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think codex is just getting tripped up by the naming

  1. we check the features from the actual cwd that codex is running from
  2. the cwds that get provided to hooks/list (also skills/list) is just a list of dirs to look for hooks.json files. we don't wanna respect any potential features in those dirs

abhinav-oai added a commit that referenced this pull request Apr 28, 2026
## Why

Plugins can bundle lifecycle hooks, but Codex previously only discovered
hooks from user, project, and managed config layers. This adds the
plugin discovery and runtime plumbing needed for plugin-bundled hooks
while keeping execution behind the `plugin_hooks` feature flag.

## What

- Discovers plugin hook sources from each plugin's default
`hooks/hooks.json`.
- Supports `plugin.json` manifest `hooks` entries as either relative
paths or inline hook objects.
- Plumbs discovered plugin hook sources through plugin loading into the
hook runtime when `plugin_hooks` is enabled.
- Marks plugin-originated hook runs as `HookSource::Plugin`.
- Injects `PLUGIN_ROOT` and `CLAUDE_PLUGIN_ROOT` into plugin hook
command environments.
- Updates generated schemas and hook source metadata for the plugin hook
source.

## Stack

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

## Reviewer Notes

- Core logic is in `codex-rs/core-plugins/src/loader.rs` and
`codex-rs/hooks/src/engine/discovery.rs`
- Moved existing / adding new tests to
`codex-rs/core-plugins/src/loader_tests.rs` hence the large diff there
- Otherwise mostly plumbing and minor schema updates

### Core Changes

The `codex-rs/core` changes are limited to wiring plugin hook support
into existing core flows:

- `core/src/session/session.rs` conditionally pulls effective plugin
hook sources and plugin hook load warnings from `PluginsManager` when
`plugin_hooks` is enabled, then passes them into `HooksConfig`.
- `core/src/hook_runtime.rs` adds the `plugin` metric tag for
`HookSource::Plugin`.
- `core/config.schema.json` picks up the new `plugin_hooks` feature
flag, and `core/src/plugins/manager_tests.rs` updates fixtures for the
added plugin hook fields.

---------

Co-authored-by: Codex <noreply@openai.com>
Base automatically changed from dev/abhinav/plugin-hooks-discovery to main April 28, 2026 21:17
…t-config

# Conflicts:
#	codex-rs/app-server-protocol/schema/json/ClientRequest.json
#	codex-rs/core-plugins/src/loader.rs
#	codex-rs/hooks/src/engine/discovery.rs
#	codex-rs/hooks/src/engine/mod.rs
…t-config

# Conflicts:
#	codex-rs/app-server-protocol/schema/json/ClientRequest.json
#	codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json
#	codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json
#	codex-rs/app-server-protocol/schema/typescript/v2/index.ts
#	codex-rs/hooks/src/lib.rs
@eternal-openai
Copy link
Copy Markdown
Contributor

PR reads well! One minor concern. Can you pull on this thread:

hooks/list resolves a per-cwd ConfigLayerStack, but then uses a single process-global Config snapshot to decide plugins, plugin_hooks, and codex_hooks. If the app-server was started in repo A and the client asks for hooks in repo B, differing feature flags in B's .codex/config.toml are ignored: hooks can disappear when B enables them, or be exposed when B disables them. Because the RPC is explicitly multi-cwd, its enablement checks need to be derived from each requested cwd's effective config/layer stack.

So my understanding of this issue:

  • Start app-server while sitting in repo A
  • Repo A has .codex/config.toml with codex_hooks = false
  • Repo B has .codex/config.toml with codex_hooks = true, plus hooks configured
  • Call hooks/list for repo B

What happens now:

The RPC correctly loads repo B’s hook definitions via repo B’s ConfigLayerStack. Then it passes feature_enabled: config.features.enabled(Feature::CodexHooks) from the global config, which still reflects repo A

Result: hooks/list says “no hooks” for repo B

…t-config

# Conflicts:
#	codex-rs/app-server/src/codex_message_processor.rs
#	codex-rs/core/src/plugins/manager.rs
#	codex-rs/core/src/session/handlers.rs
@abhinav-oai abhinav-oai enabled auto-merge (squash) April 29, 2026 21:51
@abhinav-oai abhinav-oai merged commit 8774229 into main Apr 29, 2026
34 of 36 checks passed
@abhinav-oai abhinav-oai deleted the dev/abhinav/hooks-list-config branch April 29, 2026 23:40
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants