Files
deepseek-harness/packages/subagent/subagent-codex

@deepseek-ai/dsh-subagent-codex

English | 中文

This package registers the fixed codex subagent provider. Each accepted run starts the official package-local Codex wrapper with app-server --stdio in the delegating Session's workspace, creates one ephemeral Codex thread, submits one self-contained text task, and returns only the final answer through the shared dsh-subagent result contract.

Start and ownership

start(request) accepts only a non-empty sequence of text blocks and derives the child cwd from the parent Session. It then spawns the fixed command through dsh-subprocess, performs initializeinitializedthread/start { cwd, ephemeral: true }, and publishes the run only after Codex returns a valid ephemeral thread. A failure or cancellation before publication closes the wire, terminates the managed process tree, waits for it to exit, and rejects start().

The published run.result starts exactly one turn. It accepts only notifications for that run's thread and turn, then waits for the authoritative turn/completed terminal notification. The latest agentMessage with phase: "final_answer" wins; when Codex emits no explicit final phase, the latest message with phase: null is the compatibility fallback. Commentary never replaces either answer, and a successful turn with no nonblank answer settles as an error.

For command and file approvals, the unattended provider selects a non-approval decision offered by the request, preferring cancel; the stable 0.147.0 request shape without an offered-decision list falls back to decline. It answers permission requests with an empty turn-scoped permission set, answers user-input requests with no answers, and declines MCP elicitation. A request with no legal unattended response, or any unknown server request, fails the run.

Local cancellation wins the result race and maps to aborted. A failed turn whose codexErrorInfo is contextWindowExceeded maps to max-tokens; every other remote interrupted or failed turn maps to error, and the provider produces no refusal. dispose() is idempotent: it requests a best-effort turn/interrupt with both current ids when they are known, closes the JSON-RPC wire, ends stdin, invokes the shared process-tree termination escalation, and waits for whole-tree exit. Result failure and independent teardown failure remain separate.

Capabilities and context

The provider advertises no optional start-time capabilities and reports inheritsParentContext: false. Codex receives the standalone text task and the parent Session cwd, but not the parent conversation, persona, tool filter, depth policy, or structured-output contract. The ephemeral Codex thread id and turn id stay private to this run and are never persisted in the parent Session.

Configuration

Key Default Meaning
env {} Explicit child environment layered over the subprocess seam's credential-scrubbed parent environment.
disposeGraceMs 3000 Positive finite grace in milliseconds, no greater than MAX_TIMER_DELAY_MS, between the shared process-tree owner's termination tiers; disposal then waits for whole-tree exit.

Production resolves the codex bin declared by its pinned @openai/codex@0.147.0 dependency and launches that JavaScript wrapper with the current Node executable. The wrapper selects the matching native platform payload; the provider neither inspects nor falls back to a host codex on PATH. Native Codex configuration and authentication remain authoritative through the parent cwd, HOME, and CODEX_HOME. The plugin does not select a model, create a product home, log in, or probe an account. Credential-shaped ambient variables are removed by the subprocess seam before the explicit env overlay is applied.

This package is an optional Profile Bundle. Install it into the target Profile, then restart that Profile; installation brings the official wrapper and one compatible native platform payload into that Profile, while the declared cordis.patch.yml layer registers only the dormant codex Host provider and starts no Codex process. Removing the package withdraws that provider and its private runtime closure on the next Profile start.

dsh plugin --profile <name> add @deepseek-ai/dsh-subagent-codex
dsh plugin --profile <name> remove @deepseek-ai/dsh-subagent-codex
dsh --profile <name>

Installation controls Host availability, not model permission. Full Agent Presets carry the tool row below with disabled: true; copy a preset and remove that field to expose subagent_codex only to new agents composed from the copy. Its one-shot policy keeps omitted or false run_in_background calls in the foreground, while explicit true returns a parent-owned Job id for job_output or job_kill. The base Host and full presets already provide the generic Job registry and controls. The Profile's own patch can replace the Bundle row's complete config, while a custom Host composition can still mount the package directly.

# $DSH_HOME/profiles/<name>/cordis.patch.yml (optional provider override)
- id: subagent-codex
  config:
    env:
      OPENAI_API_KEY: !!js process.env.OPENAI_API_KEY
# A copied Agent Preset; remove `disabled` to grant this tool.
- id: tool-subagent-codex
  name: '@deepseek-ai/dsh-tool-subagent'
  disabled: true
  config:
    provider: codex
    toolName: subagent_codex
    backgroundMode: one-shot
    maxDepth: provider-managed

Product compatibility and evidence

The production wire intentionally implements only the app-server methods required by this one-shot contract. The runtime dependency and all six optional-dependency aliases are pinned to @openai/codex@0.147.0 / codex-cli 0.147.0. A normal install selects one payload for the current OS and CPU. For the current darwin-arm64 payload, npm pack --dry-run --json @openai/codex@0.147.0-darwin-arm64 reports 111,199,052 packed bytes and 274,777,843 unpacked bytes. That package contains native codex, codex-code-mode-host, rg, and zsh resources; other platforms may differ, and these values are disclosure rather than an installation threshold. The keyless real-product test drives the package wrapper against a loopback Responses fixture, observes the package-local argv, and proves wrapper and native descendants become quiescent.

Installing with optional dependencies omitted, using an unsupported platform, or losing the selected payload makes the first delegation fail with the wrapper's native-payload startup error. The provider neither probes a host CLI nor retries with one.

Model Experience

Child request

What the model sees

The Codex child receives the standalone text blocks as one turn in a fresh ephemeral thread. Its workspace is the parent Session cwd; its model, system instructions, tools, sandbox, and authentication come from native Codex configuration, while the executable version comes from the Bundle's pinned platform payload.

Token effect

The child pays for an independent Codex context and turn. Child tokens do not enter the parent's context.

KV Cache effect

Independent of the parent request cache. Reuse depends only on Codex's own provider, model, instructions, tools, and ephemeral-thread request.

Parent scheduling and results, indirectly

What the model sees

Through dsh-tool-subagent, a foreground call gives the parent the selected final Codex answer or the consumer's exact error for a non-completed result. A background call first returns a Job id; the generic job controls later deliver a completion notice, expose the final answer and status through job_output, and let job_kill request cancellation. Codex commentary, reasoning, tool activity, stderr, workspace diffs, usage, and product ids are not copied into the parent Session.

Token effect

Foreground input grows by the retained final answer or error. Background input also includes the start acknowledgement, completion notice, and any job_output, job_kill, or later status results; child tokens still do not enter the parent context. This provider adds no parent tool schema by itself.

KV Cache effect

Append-only: foreground adds one result after the reusable parent prefix, while background appends the Job acknowledgement, notice, and later control or collection results. Background scheduling can add a notice-driven turn, but none of these messages rewrites the earlier prefix.

Known Limitations and Deferred Work

  • One fresh process, thread, and turn per run — there is no continuation, resume, pooling, progress stream, or product-session persistence.
  • Authentication and account state remain native — the Bundle supplies the CLI but does not create an account, log in, trust a project, or rewrite Codex settings; configuration and authentication failures surface as startup or run errors.
  • The native platform payload is required at delegation time — installs that omit optional dependencies, unsupported platforms, and missing or damaged payloads fail at the first run; there is no host-CLI fallback.
  • Compatibility is pinned by development evidence — upgrading from the verified 0.147.0 protocol baseline requires regenerating upstream schema evidence and rerunning handshake, answer-selection, approval, cancellation, keyless real-product, and credentialed DeepSeek nonce tests.
  • No human approval path — known unattended approval requests are denied and unknown server requests fail closed; deployments cannot configure an allow policy through this package.
  • Product payload is final text only — reasoning, commentary, intermediate messages, tool traffic, usage, stderr, and workspace diffs remain product-local; generic Job ids, notices, and status come from the shared job runtime.
  • No optional shared capabilities — output schemas, child personas, tool filtering, and harness depth enforcement are rejected by the shared service for this provider.
  • No wall-clock timeout or side-effect rollback — the caller cancels long work, and files or external systems changed before cancellation are not restored.