Skip to content

Managed providers: Codex app-server adapter; Codex/OpenCode/Remote Control evidence (#339, #340) - #380

Draft
raiseCatError wants to merge 2 commits into
release/v0.18.0from
feature/codex-app-server-adapter
Draft

raiseCatError wants to merge 2 commits into
release/v0.18.0from
feature/codex-app-server-adapter

Conversation

@raiseCatError

@raiseCatError raiseCatError commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

#339 and #340. Based on release/v0.18.0. New files only; the session manager and harness registry are untouched because #347 changes them.

Codex adapter (src/agents/sessions/codexAdapter.ts), same contract as ClaudeSession:

  • codex app-server over stdio, JSON-RPC shapes taken from the schema codex-cli 0.162.1 generates (codex app-server generate-json-schema); the CLI marks app-server experimental, which codexCapabilities keeps so the UI can say so.
  • Codex's approval policy, sandbox and model are not overridden; approvals are answered only with the person's choice (accept once or decline, never acceptForSession or policy amendments); unimplemented server requests get a JSON-RPC error so Codex never waits; cancellation is reported only when turn/completed says interrupted; failed turns carry Codex's own message; frames bounded to 8 MiB.
  • Tests (tests/codexAdapter.test.ts) run it against tests/fixtures/fake-codex-app-server.mjs: handshake, queued first message, approve, decline, refused unsupported request, interrupt acknowledgement, failure reason, refused initialization, garbage and an oversized frame.

Research (docs/design/managed-providers.md): capability evidence matrix for Claude / Codex / OpenCode; OpenCode stays "shown, not controlled" (its server page documents v1 endpoints while 2.0.18 serves "the v2 API"; the next step is pinning to a running server's /doc); Remote Control: no-go for Managed targets (the documented modes are interactive and server mode; the stream-json transport is not documented as capable), pass-through for raw Claude, no Never/Ask/Always policy until a probe or documentation shows support.

Remaining (listed in the doc): wiring codex-app-server into the harness registry and manager after #347; plan/token-usage normalization with #332's task model; physical QA with signed-in Codex/OpenCode/Claude accounts (not performed).

Security fix (8854bb7), found by review: approval prompts could hide what they approve. A command approval showed only its first line (a harmless first line could hide curl … | sh below it) — now every line is shown (⏎ between lines, cut at 600 characters with an explicit remainder count); this also fixes the shipped Claude adapter's permission prompts (approvalTarget, a narrow change outside the lines #347 edits). A Codex file-change approval named no files — it now names the files of its fileChange item or says they were not reported. Codex's model-written reason is labelled reasonFromCodex.

…dex, OpenCode and Remote Control

#339 and #340.

src/agents/sessions/codexAdapter.ts drives `codex app-server` (JSON-RPC over
stdio, shapes from the protocol schema codex-cli 0.162.1 generates) with the
same contract as the Claude adapter:
- Codex's own approval policy, sandbox and model are not overridden;
- messages sent before the thread exists are queued; the thread is reported
  once whatever order thread/started and the thread/start response arrive in;
- approvals are answered only with the person's choice, `accept` once or
  `decline`, never "for the session" or a policy amendment;
- every server request NMSh does not implement is refused with a JSON-RPC
  error, so Codex never waits on NMSh;
- cancellation is reported only when the turn completes as `interrupted`;
- a failed turn carries Codex's own error message, never an invented one;
- frames are bounded; unknown or malformed messages produce nothing.
The CLI's `[experimental]` label is kept as a capability so it can be shown.
The adapter is not wired into the session manager or harness registry yet:
both are changed by the managed-agent workspace PR (#347).

Tests drive it against a fixture server speaking the documented shapes:
handshake, queued message, approve, decline, refused request, interrupt
acknowledgement, failure reason, refused initialization, hostile output.

docs/design/managed-providers.md records the per-provider evidence matrix,
why OpenCode gets no adapter yet (v1 docs vs. the v2 server), and the Remote
Control findings: no-go for Managed targets (the stream-json transport is
not documented as Remote Control capable), pass-through for raw Claude, no
Never/Ask/Always policy until a probe or documentation shows support.
…labelled reasons

From a security review of the Codex adapter; the same pattern was in the
Claude adapter's permission prompts.

- A command approval showed only the command's first line, so a harmless
  first line could hide what followed. Approval targets now show every line
  (line breaks as " ⏎ "), cut at 600 characters with an explicit "N more
  characters; see details"; the complete command stays in the details. This
  applies to Codex command approvals and Claude permission prompts
  (approvalTarget; tool rows keep their compact form, now with "+N more
  lines").
- A Codex file-change approval named no files, only Codex's own reason. It
  now names the files of the fileChange item it refers to, or says
  "files not reported by Codex".
- Codex's reason is model-written: it is kept as `reasonFromCodex`, never
  presented as NMSh's own words.
- A response-order assertion in the session test no longer races.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant