Commit Graph
28 Commits
Author SHA1 Message Date
Eric Traut a9dee37f9c Add configurable goal token budget limits (#37878)
## What changed

- Add `goals.max_goal_token_budget` as a positive-integer configuration setting.
- Use the configured maximum as the default budget for new goals and when `tokenBudget` is reset to `null`.
- Reject goal creation and updates whose token budget exceeds the configured maximum, including requests through goal tools and `thread/goal/set`.
- Respect managed configuration precedence and per-thread configuration overrides.

## Testing

- Cover configuration parsing and managed overrides.
- Cover defaulting, resetting, and rejecting oversized budgets through the goal service, goal tools, and app-server API.

GitOrigin-RevId: f8d7e6418cdc237d454c8cf47bb32ba0d44a60cf
2026-08-10 21:00:00 +00:00
efrazer-oai bc8b25ea02 Add durable user-message queue dispatch (#37204)
## What changed

- Add a storage-neutral queue extension for listing, adding, editing, reordering, deleting, and explicitly starting queued user messages.
- Dispatch queued messages in FIFO order when a thread becomes idle after a completed turn, while leaving them queued after interruptions or failures.
- Wait for user input to be persisted before removing its queue item, and report hook rejection, task termination, and persistence failures distinctly.
- Snapshot local image and audio attachments into validated data URLs before storing them, enforce input limits, and emit `ThreadQueueChanged` events after mutations.

## Testing

- Cover queue mutations, automatic and explicit dispatch, interruption and failure behavior, hook rejection, invalid records, input limits, and local attachment snapshotting.

GitOrigin-RevId: 14f39d7c8cbaccb767a6da84b82cced0edfcb4b9
2026-08-06 03:11:42 +00:00
felixxia-oai 5dd992acd3 Route extension warnings to app-server threads (#35168)
## Why

Extension warnings need a stable thread target even when they are emitted outside an active turn.

## What changed

- Add `ExtensionWarning` and a dedicated `ExtensionEventSink::emit_warning` path with an explicit thread ID and optional turn ID.
- Deliver extension warnings as thread-scoped app-server `warning` notifications, preserving listener ordering and waiting briefly for a subscriber when no listener is active.
- Move skills warnings to the new path, limiting provider catalog warnings to four messages of 256 bytes each.

## Testing

- Cover warning routing, ordering, UTF-8-safe truncation, subscriber fallback, and invalid thread IDs.
- Verify skills warning bounds and app-server delivery of executor catalog budget warnings.

GitOrigin-RevId: 4dcb1ba7f17c0edb1a9d548f9568e0c734bffc15
2026-07-24 12:28:29 +00:00
jay 88eb3a2b8a Enable git attribution across Codex entry points (#34819)
## What changed

- Install the git attribution extension in the app server, MCP server, and `codex debug prompt-input` so authenticated workspace policy controls the commit and pull request attribution instructions sent to the model.
- Resolve attribution settings from the process-level ChatGPT base URL, independent of per-thread or per-tool configuration overrides.
- Treat git attribution as contextual developer content when mapping model events.

## Testing

- Cover policy fetch retries, workspace switches, rollbacks, cold thread resumes with legacy instructions, MCP tool calls, and prompt-debug output.

GitOrigin-RevId: 57d182c432c20d7c1c6c429057b6163c9f32088d
2026-07-22 20:23:35 +00:00
jif 0f2321f244 Refresh host skill catalogs through world state (#33425)
## Why

Host skills can change after a thread starts. Subsequent turns need the updated
catalog without reinjecting an unchanged catalog on every turn.

## What changed

- Register the host skill provider in app-server and project its catalog through
  a dedicated World State section.
- Render host skills with the existing metadata budget and usage instructions,
  including skill-root aliases when available.
- Suppress the legacy host catalog and contextual fragment when World State owns
  the catalog, while preserving host skills for explicit and shadow selection.

## Testing

Added an app-server test that installs a host skill at runtime and verifies the
catalog updates once and remains stable on the following turn.

GitOrigin-RevId: 4cacc6b2258fc3cab8499fbdf9aa6ab0324ec10d
2026-07-15 20:59:21 +00:00
jif c100109280 Add shadow metrics for lexical skill selection (#32761)
## What changed

- Add an opt-in `skill_search` feature that ranks prompt-visible skills against each turn's user input with a bounded weighted lexical selector.
- Keep the ranked selection out of model-visible context and record metrics for selection cost, catalog reduction, and whether later implicit or `skills.read` invocations matched the ranked candidates.
- Include host-provided skills in the experiment catalog without changing the rendered skill catalog.

## Testing

- Add selector unit tests covering ranking, limits, truncation, stop words, and deterministic tie-breaking.
- Add extension tests covering turn-local invocation recording and host-skill shadow selection.

GitOrigin-RevId: 4d00a1c805ea8b391d6c6ac6a8450afa88ca3e25
2026-07-13 10:38:37 +00:00
Won Park 61f5a84930 Let image generation extension hosts control output persistence (#29711)
## Why

Some extension hosts need generated images returned without writing them
to the local filesystem or giving the model a local path.

## What changed

**tl;dr**: we now conduct all extension operations in the image gen
extension

- Let hosts provide an optional image save root when installing the
extension.
- Save images and return path hints only when a save root is configured.
- Return image data without saving or adding a path hint when no save
root is configured.
- Preserve the extension-provided `saved_path` instead of persisting
extension images again in core.
- Leave built-in image generation unchanged.

## Validation

- `just test -p codex-image-generation-extension`
- `just test -p codex-app-server
standalone_image_generation_returns_saved_path_hint_to_model`
- `just test -p codex-core
extension_tool_uses_granted_turn_permissions_without_local_persistence`
- `just test -p codex-core tools::handlers::extension_tools::tests`
- tested on CODEX CLI on both save_root: CODEX_HOME and None 
- tested on CODEX APP on both as well
2026-06-23 18:51:49 -07:00
jif 81b000421d Add config toggles for orchestrator skills and MCP (#28942)
## Why

Orchestrator-provided skills and Codex Apps MCP tools add model-visible
instructions, resources, and tools beyond the local workspace. Hosts
need config-level switches to disable those orchestrator-owned surfaces
independently, without disabling regular skills or regular MCP servers.

## What changed

- Adds `[orchestrator.skills].enabled` and `[orchestrator.mcp].enabled`
config entries, both defaulting to `true`.
- Includes the new settings in `config.schema.json` and in the config
lock so resolved thread configuration preserves the same orchestrator
exposure decisions.
- Threads `orchestrator.skills.enabled` through the app-server skills
extension so disabled orchestrator skills do not expose the `skills`
namespace or inject orchestrator skill context.
- Gates Codex Apps MCP exposure, app instructions, and app auth
eligibility on `orchestrator.mcp.enabled` while leaving non-Codex-Apps
MCP tools available.
- Updates the thread-manager sample config to disable both
orchestrator-owned surfaces.

## Verification

- Added config parsing, loading, defaulting, and schema coverage for the
new settings.
- Added MCP exposure coverage that `orchestrator.mcp.enabled = false`
removes Codex Apps tools while preserving regular MCP tools.
- Added app-server coverage that `orchestrator.skills.enabled = false`
prevents orchestrator skill tools, prompts, and resource reads from
reaching the model turn.
2026-06-19 14:42:26 +02:00
jif c8c78b63a7 Activate selected executor plugin MCPs in app-server (#27893)
## Why

#27870 teaches the MCP extension how to discover stdio MCP servers
declared by a selected executor plugin, but app-server does not yet
install that contributor or initialize its per-thread state. As a
result, `thread/start.selectedCapabilityRoots` can select the plugin
while its MCP servers remain inactive.

This PR closes that app-server wiring gap:

```text
thread/start(selectedCapabilityRoots)
    -> initialize the thread's selected-plugin MCP snapshot
    -> read the selected plugin's .mcp.json through its environment
    -> start declared stdio servers in that environment
    -> expose their tools only on the selected thread
```

## What changed

- Install the selected-executor-plugin MCP contributor in app-server
using the existing shared `EnvironmentManager`.
- Initialize its frozen thread snapshot when `thread/start` includes
selected capability roots.
- Document that selected plugin stdio MCPs are activated in their owning
environment.
- Add an app-server E2E covering the complete selection-to-tool-call
path.

The E2E verifies that:

- the selected MCP process receives an executor-only environment value,
proving the tool runs through the selected environment;
- the MCP tool is advertised to the model and can be called;
- a normal MCP config reload does not discard the thread's frozen
selected-plugin registration;
- another thread without the selected root does not see the MCP server.

## Scope

- Existing sessions without `selectedCapabilityRoots` are unchanged.
- Only stdio MCP declarations are activated. HTTP declarations remain
inactive.
- This does not change selected-root persistence across resume/fork or
add hosted-plugin behavior.

## Verification

- Focused app-server E2E:
`selected_executor_plugin_exposes_its_stdio_mcp_only_to_that_thread`

## Stack

Stacked on #27870.
2026-06-15 16:23:37 +02:00
jif 267232f3af feat: disable orchestrator skills for now (#27646)
Temp disable orchestrator-only skills while waiting for the endpoint to
be fixed
2026-06-11 20:20:26 +02:00
jif 7c2394808e skills: decouple the skills extension from core (#27413)
## Why

`ext/skills` currently depends on `codex-core` for two host concerns:
reading the concrete `Config` type and borrowing core-owned
model-context fragment types. That coupling prevents the extension from
being assembled independently above core and leaves context that belongs
to the skills feature owned by core.

This stacked PR introduces the host boundary needed for the broader
extension migration while intentionally preserving existing skills
behavior. It is stacked on #27404.

## What changed

- Adds a small public `SkillsExtensionConfig` view and makes skills
installation generic over the host config type.
- Requires the host to map its config into that view; app-server
supplies the current `Config` values.
- Moves the available-skills and selected-skill context fragment
implementations into `ext/skills`, preserving their roles, markers, and
rendered bytes.
- Removes the direct `codex-core` dependency from
`codex-skills-extension`.
- Keeps local discovery, invocation, side effects, and the
`codex-core-skills` compatibility types unchanged for later staged PRs.

## Behavior

This adds no capability and is intended to have no user-visible or
model-visible behavior change. The install API and ownership boundary
change internally; emitted skills context remains byte-for-byte
compatible.

## Validation

- Updates the skills extension integration coverage to use a host-owned
test config.
- Asserts the complete rendered catalog and selected-skill fragments,
including their roles and markers.
- `just bazel-lock-check`
- Rust tests and Clippy were not run locally per request; CI will run
them.
2026-06-11 14:03:53 +02:00
jif a287c5dffd skills: make backend plugin skills invocable without an executor (#27387)
## Why

#27198 made the extension-owned `codex_apps` MCP connection the hosted
plugin runtime, but its `mcp/skill` resources still bypassed the skills
extension. App-server could list and read those resources through
generic MCP APIs, but a thread with no selected environment did not
expose them in the model's skills catalog or load their `SKILL.md`
through `$skill`.

Hosted skills should stay remote while using the same typed catalog,
source authority, deduplication, bounded contextual catalog, and
selected-skill prompt injection as host and executor skills. They should
not be downloaded or exposed as ambient filesystem paths.

## What changed

- Add a session-scoped `McpResourceClient` over the replaceable MCP
connection manager so resource list/read calls follow startup and
refresh replacements.
- Add a `BackendSkillProvider` that pages `codex_apps` resources,
accepts bounded and validated `mcp/skill` entries, and reads a selected
skill's `SKILL.md` through the same MCP connection.
- Register the remote provider in app-server and include it in the
skills catalog even when a thread has no selected capability roots or
executor.
- Contribute hosted skill metadata through the bounded
`AvailableSkillsInstructions` developer-context path, exclude remote
entries from per-turn catalog injection, and classify `<skills>`
messages as contextual developer content so rollback can trim and
rebuild them correctly.

## Testing

- Extend the app-server MCP resource integration test with
`environments: []` to exercise two-page discovery, filter a
non-`mcp/skill` resource, verify the escaped developer catalog entry and
user-role `<skill>` fragment containing the fetched `SKILL.md`, and
preserve generic MCP resource reads.
- Add core event-mapping coverage that classifies `<skills>` developer
messages as contextual history.
2026-06-11 11:28:16 +02:00
Michael Bolin 2e377ce5e5 feat: make ThreadStore available on ThreadExtensionDependencies (#27439)
Generally useful for extensions.
2026-06-10 15:17:15 -04:00
Adam Perry @ OpenAI e0cb4ede4e [codex] Fix post-merge analytics integration failures (#27285)
## Why

Recent merges left `main` with analytics integration build failures.
Local Cargo runs also made the trimmed-skills test depend on
developer-installed skills, while Bazel used an isolated home.

## What changed

- Clone `thread_metadata.thread_source` when constructing goal analytics
event parameters.
- Group app-server thread extension inputs into
`ThreadExtensionDependencies`.
- Isolate the trimmed-skills test home so its exact fixture count is
stable across Cargo and Bazel.

## Validation

- `cargo check -p codex-analytics`
- `just test -p codex-analytics` (71 tests)
- `just test -p codex-app-server` (837 tests; one unrelated zsh-fork
timeout passed on retry)
2026-06-09 20:52:09 -07:00
marksteinbrick-oai 608b8b1cc6 [codex-analytics] emit goal lifecycle analytics (#27078)
## Why
- Currently, there is no analytics event for `/goal` behavior
- Existing events cannot identify goal execution or its resulting
outcome
- The original update in
[#26182](https://github.com/openai/codex/pull/26182) was implemented
before `/goal` moved into `codex-goal-extension`.

## What Changed
- Adds `codex_goal_event` serialization and enrichment to
`codex-analytics`
- Emits goal events from the canonical `codex-goal-extension` mutation
and accounting paths:
  - `created` when a new logical goal is persisted
  - `usage_accounted` when cumulative goal usage is persisted
  - `status_changed` when the stored goal status changes
  - `cleared` when the goal is deleted
- Preserves causal `turn_id` for turn driven events and uses null
attribution for external or idle lifecycle events
- Changes goal deletion to return the deleted row so `cleared` retains
the stable goal ID

## Event Details

Includes standard analytics metadata along with goal specific fields:
- `goal_id`: Stable ID stored in the local SQLite goal row and shared
across the goal's events
- `event_kind`: Observed operation (see the 4 lifecycle events cited in
the above bullet)
- `goal_status`: Resulting or last stored status: `active`, `paused`,
`blocked`, `usage_limited`, etc.
  - `has_token_budget`: Indicates whether a token budget is configured
  - `turn_id`: Causal turn ID, or null when no causal turn exists
- `cumulative_tokens_accounted`: Cumulative tokens on `usage_accounted`
events; null otherwise
- `cumulative_time_accounted_seconds`: Cumulative active time on
`usage_accounted` events; null otherwise

## Validation
- `just test -p codex-analytics -p codex-state -p codex-goal-extension`
- `just test -p codex-core -E 'test(/goal/)'`
- `just test -p codex-app-server`
- `cargo build -p codex-analytics -p codex-core -p codex-state -p
codex-app-server`
2026-06-09 18:45:54 -07:00
jif 4ec3b8eeea Route hosted Apps MCP through extensions (#27191)
## Stack

- Base: #27184
- This PR is the second vertical and should be reviewed against
`jif/external-plugins-1`, not `main`.

## Why

CCA is moving toward a split runtime where the orchestrator may have no
filesystem or executor, but it still needs to activate remotely hosted
plugin components. HTTP MCP servers are the simplest complete example:
they need configuration and host authentication, but they do not need an
executor process.

The Apps MCP endpoint is currently synthesized by a special-purpose
loader inside the MCP runtime. That works locally, but it leaves hosted
MCP activation outside the extension model being established in #27184.
It also makes the Apps path a poor foundation for plugins whose skills,
MCP servers, connectors, and hooks may come from different sources or
execute in different places.

This PR moves that one behavior behind an extension-owned contribution
while preserving the existing local fallback. It deliberately does not
introduce a generic plugin activation framework.

## What changed

### MCP extension contribution

`codex-extension-api` gains an ordered `McpServerContributor` contract.
A contributor returns typed `Set` or `Remove` overlays for MCP server
configuration; later contributors win for the names they own.

The contract stays at the existing MCP configuration boundary.
Extensions do not create a second connection manager or transport
abstraction.

### Hosted Apps MCP extension

A new `codex-mcp-extension` contributes the reserved `codex_apps` server
from the existing Apps feature, ChatGPT base URL, path override, and
product SKU configuration.

When `apps_mcp_path_override` is enabled for `https://chatgpt.com`, the
resulting streamable HTTP endpoint is
`https://chatgpt.com/backend-api/ps/mcp`. The existing ChatGPT-auth gate
remains authoritative, so this server can run in an orchestrator-only
process without being exposed for API-key sessions.

### One resolved runtime view

`McpManager` now distinguishes three views:

- **configured:** config- and plugin-backed servers before extension
overlays;
- **runtime:** configured servers plus host-installed extension
contributions;
- **effective:** runtime servers after auth gating and compatibility
built-ins.

App-server installs the hosted MCP extension and uses the runtime view
for thread startup, refresh, status, threadless resource reads,
connector discovery, and MCP OAuth lookup. This keeps
`mcpServer/oauth/login` consistent with the servers exposed by the other
MCP APIs. The hosted Apps server itself continues to use existing
ChatGPT host authentication rather than MCP OAuth.

## Compatibility

Hosts that do not install the MCP extension retain the existing Apps MCP
synthesis path. This preserves current local-only, CLI, and
standalone-host behavior while app-server exercises the extension path.

Disabling Apps removes the reserved `codex_apps` entry, and losing
ChatGPT auth removes it from the effective runtime view. Executor
availability is not consulted for this HTTP transport.

## Follow-ups

The next vertical will resolve a manifest-declared stdio MCP server from
an executor-selected plugin root and execute it in the environment that
owns that root. Later verticals can add backend-owned skills, connector
metadata, hooks, durable selection semantics, and incremental local
convergence without changing the component-specific runtime boundaries
introduced here.

## Verification

Focused coverage was added for:

- contributing the hosted Apps MCP at `/backend-api/ps/mcp` without an
executor;
- requiring ChatGPT auth in the effective runtime view;
- removing a reserved configured Apps server when the Apps feature is
disabled.

`cargo check -p codex-app-server -p codex-mcp-extension -p
codex-extension-api -p codex-mcp` passed. Tests and Clippy were not run
locally under the current development instruction; CI provides the full
validation pass.
2026-06-09 22:44:16 +02:00
jif 89ac3ec27c Load selected executor skills through extensions (#27184)
## 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:

```json
{
  "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.
2026-06-09 19:51:54 +02:00
Eric Traut 479a14cf59 [2 of 2] Finish moving goal runtime to extension (#26548)
## Stack

1. [#26547](https://github.com/openai/codex/pull/26547) - [1 of 2] Align
goal extension with core behavior
2. [#26548](https://github.com/openai/codex/pull/26548) - [2 of 2] Move
goal runtime to extension

## Why

This PR completes the switch of the goal behavior to the
extension-backed runtime and removes the old core goal implementation.

## What Changed

- Installs the goal extension for app-server `ThreadManager` sessions.
- Routes app-server thread goal `get`, `set`, and `clear` through
`GoalService`.
- Uses thread-idle lifecycle emission after goal resume and snapshot
ordering so the extension can decide whether to continue the goal.
- Forwards extension goal updates through a FIFO async app-server
notification path so backpressure does not drop them or reorder updates.
- Keeps review turns from enabling goal runtime behavior.
- Plans extension tools before dynamic tools so built-in goal tool names
keep their old precedence when goals are enabled.
- Removes the old core goal runtime, core goal tool handlers, and core
goal tool specs.
- Updates tests that were coupled to the core-owned goal runtime while
leaving the legacy `<goal_context>` compatibility path in core for old
threads.
- Removes the stale cargo-shear ignore now that `codex-goal-extension`
is used by the workspace.
- Keeps realtime event matching exhaustive after removing the old
goal-specific realtime text path.


## Validation

- Ran manual `/goal` runs in TUI. Validated time accounting matched
wall-clock time and goal lifecycle state transitions.
2026-06-05 14:17:30 -07:00
Won Parkandjif-oai ecb41fcb64 Add feature-gated standalone image generation extension (#24723)
## Why

Add a standalone image generation path that can be exercised
independently of hosted Responses image generation, while retaining the
hosted tool as fallback unless the extension is actually available to
the model.

## What changed

- Added the `codex-image-generation-extension` crate with standalone
generate/edit execution, prior-image selection for edits, model-visible
image output, and local generated-image persistence.
- Installed the extension in app-server behind the disabled-by-default
`imagegenext` feature and backend eligibility checks.
- Updated core tool planning so eligible `image_gen.imagegen` exposure
replaces hosted `image_generation`, while unavailable configurations
retain hosted fallback.
- Added coverage for extension behavior, edit history reuse, feature
gating, auth eligibility, and hosted-tool replacement.
- The extension is installed through app-server only in this PR; other
execution paths retain hosted image generation because hosted
replacement occurs only when the standalone executor is actually
registered and model-visible.
- The initial extension contract intentionally fixes the image model to
`gpt-image-2` and uses automatic image parameters.
- Native generated-image history/card parity and rollout persistence
cleanup are intentionally deferred follow-up work.

## Validation

- `just test -p codex-image-generation-extension`
- `just test -p codex-features`
- `just test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates`
- `just test -p codex-app-server`
- `just fix -p codex-image-generation-extension -p codex-features -p
codex-core -p codex-app-server`
- `just fmt`
- `just bazel-lock-update`
- `just bazel-lock-check`

---------

Co-authored-by: jif-oai <jif@openai.com>
2026-05-28 11:44:55 -07:00
sayan-oai a22706dfae standalone websearch extension (#23823)
## Summary

Add the extension-backed standalone `web.run` tool so Codex can call the
standalone search endpoint through the `codex-api` search client and
return its encrypted output to Responses.

- gate the new tool behind `standalone_web_search`
- install the extension in the app-server thread registry and hide
hosted `web_search` when standalone search is enabled for OpenAI
providers so the two paths stay mutually exclusive
- build search context from persisted history using a small tail
heuristic: previous user message, assistant text between the last two
user turns capped at about 1k tokens, and current user message

## Test Plan

- `cargo test -p codex-web-search-extension`
- `cargo test -p codex-api`
- `cargo test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates`
2026-05-26 11:12:24 -07:00
jif-oai c4e53d103c Wire app-server extension event sink (#24586)
## Why

The goal extension already emits `ThreadGoalUpdated` events, but
production app-server thread extensions were built with the default
no-op extension event sink. That meant extension-driven goal updates
could be produced without ever reaching app-server clients.

## What changed

- Build app-server thread extensions with a host-provided
`ExtensionEventSink`.
- Add an app-server sink that converts extension `ThreadGoalUpdated`
events into `ServerNotification::ThreadGoalUpdated` broadcasts.
- Use the existing bounded outgoing message channel via `try_send` so
event forwarding cannot create an unbounded queue.
- Pass `NoopExtensionEventSink` in app-server tests that construct a
`ThreadManager` without an app-server host.
- Refresh `Cargo.lock` for the existing `codex-memories-extension`
`codex-otel` dependency.

## Verification

- `just test -p codex-app-server
extensions::tests::app_server_event_sink_forwards_thread_goal_updates`
2026-05-26 15:28:02 +02:00
jif-oai c37884d5eb Wire metrics client into memories extension (#24567)
## Summary

- let the memories extension capture the process-global OTEL metrics
client at install time
- keep app-server/TUI/exec extension construction APIs unchanged
- store the metrics client for future memory metrics without emitting
any metrics yet

## Test plan

- `just fmt`
- `just bazel-lock-update`
- `just bazel-lock-check`
- Not run: tests/clippy per request; CI will cover them
2026-05-26 13:56:46 +02:00
jif-oai cccde930ce Move memory prompt injection to app-server extension (#22841)
## Why

Memory prompt injection should be owned by the extension path that
app-server composes at runtime, not by an inlined special case inside
`codex-core`. This keeps `codex-core` focused on session orchestration
while allowing the memories extension to own its app-server prompt
behavior.

## What Changed

- Registers `codex-memories-extension` in the app-server extension
registry.
- Moves the memory developer-instruction injection out of
`core/src/session/mod.rs` and into the memories extension prompt
contributor.
- Adds config-change handling so the extension keeps its per-thread
memory settings in sync after startup.
- Leaves memories read/retrieval tools unregistered for now so this PR
only changes prompt injection.
- Removes the stale `cargo-shear` ignore now that app-server depends on
the extension crate.

## Validation

Not run locally; validation is left to CI.
2026-05-15 16:19:34 +02:00
Dylan Hurd d18a7c982e chore(config) rm Feature::CodexGitCommit (#22412)
## Summary
Removes the unused Feature::CodexGitCommit

## Testing
- [x] tests pass
2026-05-13 12:33:36 -07:00
jif-oai d996f5366f feat: guardian as an extension (contributors part) (#22216)
Part 1 of guardian as extension. This bind all the logic to spawn
another agent from an extension and it adds `ThreadId` in the start
thread collaborator
2026-05-12 14:41:45 +02:00
jif-oai ebd3d53451 feat: drop CodexExtension (#22140)
Drop `CodexExtension` as not needed for now
2026-05-11 14:19:51 +02:00
jif-oai 569ff6a1c4 extension: move git attribution into an extension (#21738)
## Why

Git commit attribution is prompt policy, not session orchestration.
After #21737 adds the extension-registry seam, this moves that
prompt-only behavior out of `codex-core` so `Session` can consume
extension-contributed prompt fragments instead of owning a one-off
policy path itself.

Before this PR, `Session` injected the trailer instruction directly from
`codex-core` ([session
assembly](https://github.com/openai/codex/blob/a57a747eb667753118217b8bb47dfd1fff88cbde/codex-rs/core/src/session/mod.rs#L2733-L2739),
[helper
module](https://github.com/openai/codex/blob/a57a747eb667753118217b8bb47dfd1fff88cbde/codex-rs/core/src/commit_attribution.rs#L1-L33)).
This branch moves that same responsibility into
[`codex-git-attribution`](https://github.com/openai/codex/blob/b5029a67360fe5c948aa849d4cf65fd2597ebaae/codex-rs/ext/git-attribution/src/lib.rs#L14-L100).

## What changed

- Added the `codex-git-attribution` extension crate.
- Snapshot `CodexGitCommit` plus `commit_attribution` at thread start,
then contribute the developer-policy fragment through the extension
registry.
- Register the extension in app-server thread extensions.
- Remove the old `codex-core` helper module and direct `Session`
injection path.

This keeps the existing behavior intact: the prompt is only contributed
when `CodexGitCommit` is enabled, blank attribution still disables the
trailer, and the default remains `Codex <noreply@openai.com>`.

## Stack

- Stacked on #21737.
2026-05-11 12:53:15 +02:00
jif-oai 436c0df658 extension: wire extension registries into sessions (#21737)
## Why

[#21736](https://github.com/openai/codex/pull/21736) introduces the
typed extension API, but the runtime does not yet carry a registry
through thread/session startup or give contributors host-owned stores to
read from. This PR wires that host-side path so later feature migrations
can move product-specific behavior behind typed contributions without
adding another bespoke seam directly to `codex-core`.

## What changed

- Thread `ExtensionRegistry<Config>` through `ThreadManager`,
`CodexSpawnArgs`, `Session`, and sub-agent spawn paths.
- Wire `ThreadStartContributor` and `ContextContributor`
- Expose the small supporting surface needed by non-core callers that
construct threads directly, including `empty_extension_registry()`
through `codex-core-api`.

This PR lands the host plumbing only: the app-server registry is still
empty, and concrete feature migrations are intended to follow
separately.
2026-05-11 11:38:18 +02:00