Skip to content

Load selected executor skills through extensions - #27184

Merged
jif-oai merged 7 commits into
mainfrom
jif/external-plugins-1
Jun 9, 2026
Merged

Load selected executor skills through extensions#27184
jif-oai merged 7 commits into
mainfrom
jif/external-plugins-1

Conversation

@jif-oai

@jif-oai jif-oai commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Why

CCA is moving toward a split runtime where the orchestrator may not have a filesystem, while executors can expose preinstalled plugins and skills. A thread therefore needs to select capabilities without asking app-server or core to interpret executor-owned paths through the orchestrator's filesystem.

The longer-term model is broader than executor skills:

  • A plugin is a bundle of skills, MCP servers, connectors/apps, and hooks.
  • A plugin root can be local, executor-owned, or hosted by a backend.
  • Components inside one plugin can use different access and execution mechanisms. A skill may be read from a filesystem or through backend tools; an HTTP MCP server can run without an executor; a stdio MCP server or hook needs an execution environment.
  • Core should carry generic extension initialization data. The extension that owns a component should discover it, expose it to the model, and invoke it through the appropriate runtime.

This PR establishes that architecture through one complete vertical: selecting a root on an executor, discovering the skills beneath it, exposing those skills to the model, and reading an explicitly invoked SKILL.md through the same executor.

Contract

thread/start gains an experimental selectedCapabilityRoots field:

{
  "selectedCapabilityRoots": [
    {
      "id": "deploy-plugin@1",
      "location": {
        "type": "environment",
        "environmentId": "workspace",
        "path": "/opt/codex/plugins/deploy"
      }
    }
  ]
}

The root is intentionally not classified as a "plugin" or "skill" in the API. It can point at a standalone skill, a directory containing several skills, or a plugin containing skills and other components. This PR only teaches the skills extension how to consume it; later extensions can resolve MCP, connector, and hook components from the same selection.

The platform-supplied id is stable selection identity. The location says which runtime owns the root and gives that runtime an opaque path. App-server does not inspect or canonicalize the path.

What changed

Generic thread extension initialization

App-server converts selected roots into ExtensionDataInit. Core carries that generic initialization value until the final thread ID is known, then creates thread-scoped ExtensionData before lifecycle contributors run.

This keeps Session and core independent of the capability-selection contract. The initialization value is consumed during construction; it is not retained as another long-lived Session field.

Executor-backed skills

The skills extension now owns an ExecutorSkillProvider that:

  • resolves the selected environment through EnvironmentManager
  • discovers, canonicalizes, and reads skills through that environment's ExecutorFileSystem
  • contributes the bounded selected-skill catalog as stable developer context
  • reads an explicitly invoked skill body through the authority that listed it
  • warns when an environment or root is unavailable
  • never falls back to the orchestrator filesystem for an executor-owned root

Skill catalog and instruction fragments have hard byte bounds, which also bound them below the 10K-token per-item context limit. If a selected executor skill has the same name as a legacy local skill, the executor selection owns that invocation and the local body is not injected a second time.

Existing local and bundled skill loading remains in place. Omitting selectedCapabilityRoots therefore preserves current local-only behavior.

Current semantics

  • Only environment-owned locations are represented in this first contract.
  • Roots are resolved by the destination extension, not by app-server or core.
  • An unavailable executor or invalid root produces a warning and no capabilities from that root; it does not trigger a local-filesystem fallback.
  • Selection applies to a newly started active thread.
  • MCP servers, connectors, and hooks beneath a selected plugin root are not activated yet.
  • Selection is not yet persisted or inherited across resume, fork, or subagent creation. Existing local capabilities continue to behave as they do today in those flows.

Planned vertical follow-ups

  1. Hosted HTTP MCP: add an extension-backed HTTP MCP source that works without an executor, then replace the special-purpose MCP plugins loader with that implementation.
  2. Executor MCP: register and execute stdio MCP servers through the environment that owns the selected plugin root.
  3. Backend skills: add a hosted skill source whose catalog and bodies are accessed through extension tools rather than a filesystem.
  4. Connectors and hooks: activate those components through their owning extensions, using the same selected-root boundary and component-specific runtime.
  5. Durable selection: define the desired-selection lifecycle, persist it, and make resume, fork, and subagent inheritance explicit rather than accidental.
  6. Local convergence: incrementally route existing local plugin, skill, and MCP loading through the same extension model while preserving current local behavior.

Each follow-up remains reviewable as an end-to-end capability. The platform selects roots, generic thread extension data carries the selection, and the owning extension resolves and operates its component.

Verification

Coverage added for:

  • app-server end-to-end discovery and explicit invocation of a skill inside an executor-selected plugin root
  • exclusive invocation when a selected executor skill collides with a local skill name
  • executor filesystem authority for discovery, canonicalization, and reads
  • thread extension initialization before lifecycle contributors run
  • stable executor catalog context, explicit invocation, context rebuilding, hidden skills, and preserved host/remote catalog behavior

Targeted protocol, core-skills, skills-extension, core lifecycle, and app-server executor-skill tests were run during development.

@jif-oai
jif-oai requested a review from a team as a code owner June 9, 2026 12:59

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d7823925c

ℹ️ 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".

Comment thread codex-rs/app-server/src/extensions.rs
Comment thread codex-rs/ext/skills/src/provider/executor.rs
Comment thread codex-rs/Cargo.toml
@jif-oai

jif-oai commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@jif-oai

jif-oai commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

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

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fec64281b4

ℹ️ 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".

Comment thread codex-rs/core/src/thread_manager.rs
Comment thread codex-rs/app-server/Cargo.toml

@anp-oai anp-oai left a comment

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.

Couple small things, lgtm overall

Comment thread codex-rs/protocol/src/capabilities.rs
Comment thread codex-rs/ext/skills/src/render.rs
@jif-oai
jif-oai merged commit 89ac3ec into main Jun 9, 2026
46 checks passed
@jif-oai
jif-oai deleted the jif/external-plugins-1 branch June 9, 2026 17:51
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 9, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants