openai / openai/codex

App Server: installed Skills are global, but model-visible Skill context needs per-thread selection

Open
#42,440 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

app-server enhancement skills
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What variant of Codex are you using?

App Server v2 (host integration)

What feature would you like to see?

Summary

Codex owns Skill discovery, provider precedence, validation, and lazy loading, but an app-server host has no supported way to decide which already-discovered Skills enter the model-visible context of one loaded thread.

A concrete consumer is hev, a Session-scoped Skill Environment manager. hev keeps the harness's native, globally installed Skill catalog, then assigns each host Session a deliberately smaller Environment for automatic model discovery. Its DSH adapter can apply that policy at DSH's Skill Registry boundary: native providers still discover and resolve Skills, while the selected Environment projects the winners into one Session's model-visible catalog.

A Codex adapter currently has no equivalent projection point. It should not have to reimplement Skill discovery, move Skills between directories, or inject a prompt telling the model to ignore most of them. It needs one smaller primitive: before a future model step, select which entries from Codex's resolved Skill catalog are automatically visible in that thread.

This is also the missing substrate for host-owned binding policies such as "always", "every N turns", or one-shot activation. The host evaluates those policies and supplies the resulting view for the next step; Codex does not need to own an Environment model or scheduler.

This is intentionally narrower than the plugin / MCP / capability-profile selection requested in #30967.

Concrete use case

Assume one Codex installation can discover these Skills:

github
code-review
release-check
incident-debugging

Two concurrent threads using the same app-server process and CODEX_HOME should be able to behave differently:

Thread A, Environment "review"
  automatic model catalog: github, code-review

Thread B, no Environment selected
  automatic model catalog: native Codex view

If release-check has an "every 5 turns" policy, the host can include it in Thread A's view for the due step and remove it again for the following step. If the policy means the full Skill instructions must run on that step, the host can combine this view with the existing explicit skill input item. The new primitive is not the scheduler; it is the ability to make automatic Skill context agree with the host's decision.

At no point is a Skill uninstalled or globally disabled. A user can still explicitly invoke a globally installed, user-invocable Skill such as $incident-debugging.

The gap on current main

Checked against 5eea8d0dd3f6b38b0e457d266fd7c918eb189bb6.

  • SkillsExtension::contribute builds the merged catalog and renders it into turn context, but there is no thread-supplied projection over that resolved catalog.
  • Model-facing skills.list and skills.read read the provider catalog directly and apply native visibility/enabled checks, not a host-selected per-thread view.
  • skills/extraRoots/set changes process-level discovery roots.
  • skills/config/write changes user-level Skill configuration.
  • selectedCapabilityRoots adds environment-owned capability roots, but does not restrict the normal user/provider catalog.
  • An explicit skill input item injects one selected Skill's full instructions, but does not remove unrelated Skill metadata from automatic model context.

So the available controls act at discovery/configuration time or explicit invocation time. There is no runtime view over the already-resolved catalog for one thread.

Why the existing workarounds are not equivalent

  • Rewriting config.toml or calling skills/config/write is shared mutation. Concurrent threads with different Environments race with each other and the user's configuration is changed as a side effect.
  • Creating a separate CODEX_HOME per Environment duplicates installation and state merely to get a different catalog view.
  • Moving or copying Skill directories makes the host take over discovery and source resolution that Codex already owns.
  • Telling the model to ignore Skills leaves their metadata in context and does not make skills.list / skills.read agree with the prompt.
  • Injecting full Skill bodies as ordinary input spends more context and still does not define which other Skills are automatically discoverable.

Proposed experimental API

{
  "method": "thread/skillCatalog/set",
  "params": {
    "threadId": "thr_...",
    "visibility": {
      "type": "allowList",
      "names": ["github", "code-review"]
    }
  }
}

Restore the ordinary Codex view with:

{
  "method": "thread/skillCatalog/set",
  "params": {
    "threadId": "thr_...",
    "visibility": { "type": "native" }
  }
}

Proposed semantics:

  • native: preserve the visibility supplied by Codex and its Skill providers.
  • allowList: only named Skills are exposed for automatic model discovery and model-facing skills.list / skills.read calls.
  • An empty allowlist exposes no Skills automatically.
  • Explicit user selection remains a separate native path. This controls automatic catalog/context visibility; it is not a global disable or uninstall operation.
  • A hidden Skill explicitly selected for the current turn must retain enough authorization for its referenced resources to remain readable during that turn, including across compaction.
  • The setting is runtime-only and affects future model steps. A host that owns durable Environment policy reapplies it after unload/resume.
  • Each model step captures the visibility once and uses the same snapshot for prompt context, world-state Skill catalogs, automatic selection, and Skill tools. An update during a running step must not make that step advertise one set but read another.

A turn/start field could provide atomic per-turn selection instead if that fits the app-server lifecycle better. The important contract is a step-consistent, per-thread view over the native resolved catalog, not the exact RPC spelling.

Why this boundary belongs in Codex

Only Codex has the complete resolved catalog across host, executor, orchestrator, bundled, and filesystem providers, and only Codex knows every surface where that catalog enters model context or backs a Skill tool. Filtering one upstream root or one rendered prompt is therefore incomplete.

The host should own product policy—Environment selection, counters, schedules, persistence, and UI. Codex should own discovery and consistently apply the host-provided projection at the model boundary.

What this does not cover

  • No Environment, policy, counter, or scheduler type in Codex core.
  • No change to Skill installation, provider precedence, validation, or lazy body loading.
  • No plugin, MCP server, Tool, permission, or model-profile selection; those broader questions remain in #30967.
  • No retroactive history rewrite. Skill instructions already injected into the transcript remain historical input.
  • No required persistence of the host's policy inside Codex.

Existing prototype

I have a local prototype implementing the experimental app-server v2 types, a thread-owned runtime setting, and a model-step visibility snapshot. It applies the same snapshot to prompt/world-state catalogs and model-facing Skill list/read tools, while preserving explicit user selection.

The prototype also carries a bounded, harness-authenticated resource-read receipt for an explicitly selected hidden Skill so compaction does not turn previously injected instructions into an unusable or falsely denied Skill.

Integration coverage exercises per-thread isolation, catalog filtering, tool consistency, empty allowlists, explicit hidden-Skill selection, and compaction behavior. I can prepare a focused PR after maintainer feedback on whether this is the right first-stage boundary and whether thread/skillCatalog/set or a turn/start field is the preferred experimental shape.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with SkillsExtension::contribute in codex-rs/ext/skills/src/extension.rs and the model-facing skills.list and skills.read entry points in codex-rs/ext/skills/src/tools/. Review the existing app-server v2 prototype and integration coverage, then confirm the preferred API shape. Done means a per-thread, step-consistent catalog view applies across prompt context and Skill tools without changing global discovery or explicit selection.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.