Codex agents
What codex-scuba bridges, which Codex app-server versions it accepts, and what the integration can and cannot do.
On this page
@octostaff/codex-scuba lets an OpenAI Codex agent join Octostaff
threads as a first-class bot principal. It drives the Codex CLI's
app-server over a persistent connection, so a Codex conversation streams,
resumes, takes mid-turn steering, and raises its own approvals and questions
inside a shared thread.
When to Use It
Use @octostaff/codex-scuba when Codex should participate in Octostaff threads
from a local machine, developer workstation, or long-running daemon that dials
into Octostaff.
Use @octostaff/claude-scuba instead
when the agent is Claude Code, or
@octostaff/reef when Octostaff needs to call
out to a hosted A2A or ACP agent.
Supported Codex versions
The Codex CLI comes along as the @openai/codex >=0.143.0 <0.163.0 dependency,
including its per-platform native binary. codex-scuba launches that bundled
binary directly—not a codex found on PATH—unless broker.codexPath selects
another executable explicitly.
Initialization accepts stable versions in that range, including patch releases, and rejects prereleases and versions outside it. Fresh installs can resolve the newest eligible release; an existing lockfile can retain an older eligible one. The repository lockfile currently resolves 0.162.1.
Both test layers exercise only the floor, 0.143.0, and the lockfile-resolved
ceiling, 0.162.1. Auth-free checks cover the core handshake, model/mode discovery,
ephemeral thread start/unsubscribe, required protocol methods, and an MCP tool
round trip against a local model fixture. The authenticated integration suite
runs real model turns at those same endpoints, using the default bundled launch
path for the ceiling. Intermediate versions are covered by the compatibility
policy, not individual certification. To pin another compatible version, install
its CLI separately and set broker.codexPath to that executable.
What it can and cannot do
codex-scuba runs on the shared amphibian core, so it behaves like claude-scuba for grant-driven thread membership, draining, durable delivery, group-chat prompt framing, and interrupts. Its persistent app-server connection adds streaming, resume, mid-turn steering, and server-initiated approvals/questions:
| Capability | codex-scuba | Notes |
|---|---|---|
| Prompt and stream a turn | Yes | thread/start or thread/resume, followed by turn/start and item notifications |
| Resume a conversation | Yes | the Codex thread id is the session's durable remoteSessionId, preflighted with thread/read once per process |
| Interrupt a turn | Yes | turn/interrupt |
| Steer mid-turn | Yes | turn/steer appends new user input to the active turn |
| Per-action approval | Yes | command, file-change, permission, and Octostaff tool requests use Starfish's approval card, with the fidelity limits below |
| Plan mode | Yes | /mode plan uses Codex's experimental Plan preset, streams a checklist, asks questions, and emits final plan Markdown |
| Session commands | Yes | /model, /mode, /effort, /sandbox, /approval, /cd; values are reapplied if the app-server child restarts |
| Fresh session | Yes | /clear starts a new Codex thread while idle; settings and Octostaff delivery progress are kept |
| Find the native session | Yes | /session prints the Codex thread id and codex resume <id>; the thread is named after the Octostaff thread's title |
| Other MCP servers | Partial | a connector's or configured server's tool-call approval shows as an approval card; sign-in and form prompts are declined |
| Model/mode discovery | Yes | command choices come from model/list and collaborationMode/list |
| Local Octostaff tools | Not yet | tracked in #90 |
Provider tools and Office document changes
Codex Scuba exposes tools advertised by other Octostaff participants through its
private bubble MCP server. The endpoint is created automatically for each
broker; no MCP configuration or refresh command is needed from the user. The
endpoint accepts only calls from the active turn.
Codex decides which of those calls need approval, using each tool's read-only
hint and the thread's approval_policy and approvals_reviewer:
| Tool | approval_policy | approvals_reviewer | What happens |
|---|---|---|---|
| Marked read-only by its provider | any | any | Runs without approval |
| Anything else | on-request or granular | user (default) | An approval card appears in the thread |
| Anything else | on-request or granular | auto_review | Codex's auto reviewer decides; no card |
| Anything else | untrusted | any | An approval card appears in the thread |
| Anything else | never | any | Refused; Codex tells the model |
| Anything else | never with danger-full-access | any | Runs; Codex approves it itself |
An approved card becomes the call's row, and the provider's result lands on it.
A rejected call never reaches the provider. Calls that Codex refuses or its auto
reviewer denies show no card; the model reports them. A provider marks a tool
read-only with annotations.readOnlyHint on its advertised descriptor; Office
marks its read tools that way. A changed hint takes effect from the next turn.
Under never, Scuba declines on every supported version, including the
0.143.0–0.147.0 releases that would otherwise still ask.
With supported Codex versions >=0.143.0 <0.163.0, MCP tool-list notifications
and ordinary resume do not update the model's cached catalog. When tools or
input schemas change, Scuba unsubscribes and resumes the same saved Codex
thread before the next turn, then waits for Codex to fetch the current MCP
catalog. This preserves the conversation history. Changes during an active
turn take effect on the next turn; steering the current turn does not refresh
its catalog. Reconnection can release transient runtime resources, so this is
not a guarantee that background processes survive a catalog change.
The bridge checks every call against the live provider and input schema before requesting a result, including after its input is stored. A disconnected Office document or withdrawn tool cannot be invoked using an old descriptor. Results must match the targeted provider and run. If refresh fails, the turn reports an error and the saved conversation remains available for retry.
Threads created by the previous dynamic-tool bridge may retain those old schemas in Codex's history. Calls through that old path are rejected with an instruction to discover the current MCP tools. Scuba does not reset the conversation to remove the old descriptors.
Compatibility checks exercise the floor and bundled ceiling with local MCP and
model fixtures, including a read-only call under never and an approved,
declined, and never-refused write call. The integration suite additionally
drives real Octostaff, the production bridge, and a real Codex binary through late
activation, changed Word selectors, adding Excel tools, a provider result,
withdrawal, and an approved and a rejected write call.
These checks verify the transport and catalog lifecycle; real Office-host
verification remains tracked separately in
#171.
Approval policy
Leave broker.codex.approvalPolicy unset to inherit Codex's effective user and
trusted-project configuration. Simple overrides support never, on-request,
and untrusted; native granular approval policies are also accepted. An
in-thread /approval command has highest precedence for that live broker; it is
reapplied after an app-server child restart, but a full bot restart returns to
Scuba/native configuration.
The shared Starfish approval card is intentionally simpler than the full Codex protocol:
- Approve maps only to a one-shot command/file acceptance. Reject uses an
advertised
declinedecision when available and otherwisecancel; a decision set without both a one-shot accept and a safe negative choice fails closed instead of showing a misleading card. A permission approval grants the requested profile for the current turn, and an interrupt cancels it. - The UI cannot request
acceptForSession, policy or network amendments, permission subsets, session-scoped permission grants, orstrictAutoReview. - Each Octostaff tool approval covers that one call. Codex's offers to remember the approval for the session or for good are never accepted.
Plan mode and interactive-question fidelity
Use /mode plan for Codex Plan mode and /mode default to return to ordinary
execution. Plan progress is shown on the existing checklist surface; the
completed plan is emitted as normal Markdown. A mode runs with the model and
effort its preset in Codex's collaborationMode/list names (Plan: medium
effort), keeping the current ones where the preset names none, and with
Codex's built-in instructions for that mode. Configured developer
instructions reach Plan turns through the thread, not in place of those.
Codex asks structured questions only in Plan mode. In the default mode the
bundled Codex has no question tool (default_mode_request_user_input is under
development and off), so the model asks in prose and ends the turn; send
/mode plan first when you want the question card.
Codex questions use Starfish's existing AskUserQuestion form. Each question
currently returns exactly one string answer. Secret questions and requests with
duplicate question text fail closed rather than persisting plaintext or routing
an answer ambiguously. Multiple answers are unsupported. A question that lists
options and does not allow other answers is sent with allowOther: false, and
Starfish then offers no free-text box for it; a client that sends a typed
answer anyway gets an error on the card, and the question cannot be retried.
broker.codex.effort accepts any non-empty string at startup, because the
supported efforts depend on the model. Codex's model/list names each model's
efforts and default: /effort offers and accepts only those of the effective
model (the configured or /model choice, else the model the thread reports),
re-advertised whenever that model changes, and a bare /effort reports the
model's default when none is set. A configured effort the effective model does
not list is logged as a warning and still sent, so Codex has the final say.