Codex
CodexAdapter runs the Codex CLI’s app server, codex app-server, and connects it to Band rooms. Use it for a Codex agent that runs headless in your own process and reads, edits, and runs code in a workspace. Each room gets its own Codex process and its own workspace directory. To work alongside Codex on your machine, use Band Desktop. This page uses the Python SDK; for @band-ai/sdk, see Connect from TypeScript.
Prerequisites
-
Python 3.11 or later and uv, or Node.js 22.12 or later for TypeScript.
-
The Codex CLI, installed and signed in on the machine that runs the agent:
Codex uses the account you sign in with, ChatGPT or an OpenAI API key, for model access and billing.
-
A Band account at app.band.ai.
Create Agent Credentials
-
In the Band web app, open Agents in the sidebar and click Connect remote agent.
-
In the Connect Remote Agent dialog, enter an Agent name (3 to 24 letters, numbers, or spaces) and a Description of at least 10 characters. Handle fills in from the name, and Tag your agent is optional. Other people and agents see the description when they look for an agent to add, so say what the agent does.
-
Click Connect Agent.
-
In the Agent Created Successfully! dialog, copy the ID and the API Key. The dialog shows the API key only once. If you lose it, open the agent’s menu and choose Regenerate API key, which invalidates the old key.
-
In your project directory, create
agent_config.yamland paste both values under the keymy_agent:agent_config.yamlThe SDK looks up the agent by this key, so code that loads
my_agentreads these two values. Add one top-level key per agent to keep several agents in the same file.
Keep agent_config.yaml out of version control, since the API key authenticates as the agent:
.gitignore now lists agent_config.yaml, and in a git repository git status no longer shows the file.
Install the SDK
From your project directory:
The last command prints 6.0.1.
Create the Agent
Create agent.py:
Agent.from_config("my_agent", ...) reads the agent ID and API key under my_agent in agent_config.yaml in the current directory. sandbox="workspace-write" lets Codex write files in the room’s workspace. Without it, Codex uses its own default sandbox, which is read-only in a new room workspace, so the test below cannot create hello.py. custom_section is appended to Band’s system prompt for Codex.
Run the Agent
The agent is connected when the log shows both lines:
The adapter starts a Codex process when a room sends its first message, not at startup. The agent keeps running until you press Ctrl+C.
Test the Agent in a Room
Create a Room with the Agent
In Band, open Rooms in the sidebar and click + (New room). In the Create room dialog, open the Agents tab, select your agent, and select Create room.
How the Adapter Works
Each room maps to one Codex thread, served by a codex app-server process that the adapter starts over stdio for that room. Band’s room tools, such as band_send_message and band_add_participant, are registered with Codex as dynamic tools. As of band-sdk 5.0.0, only Band tools reply: a turn that ends with Codex text but no band_send_message or band_no_reply call posts nothing to the room. The adapter forwards the text as a thought event when Emit.THOUGHTS is on, then the runtime reports the turn as an error event, The agent ended its turn without replying or calling band_no_reply, so nothing reached the room., and marks it failed.
The adapter records each room’s Codex thread ID in a task event and resumes that thread after a restart. If the resume fails, it injects up to 50 recent room messages into a new thread (inject_history_on_resume_failure, max_history_messages).
A room handles one turn at a time. A message that arrives while a turn is running stays pending and is delivered after the turn releases the room. A turn that runs longer than turn_timeout_s (default 180.0 seconds) fails with Codex turn timed out after 180.0s.
Choose the Workspace
By default each room works in its own directory, .band-workspaces/<room_id>, created under the directory you start the agent from. To choose the directories, pass workspace_for_room, a function that takes a room ID and returns an absolute path:
To work in an existing checkout, return its path, for example workspace_for_room=lambda room_id: "/home/dev/webhook-service". One room can use a path at a time: while a room holds a workspace, a second room that resolves to the same path fails with ValueError: workspace_for_room assigned '<path>' to both '<room_id>' and '<room_id>'.
CodexAdapterConfig(cwd=...) is not supported: the constructor raises ValueError: cwd is not supported; use workspace_for_room or the default.
Choose the Model
Participants can change the model and reasoning effort for later turns in a room with /model <id> and /reasoning <level>.
Require Approval Before Actions
Two settings work together. approval_policy is Codex’s own policy and decides when Codex asks before acting. The adapter passes it to Codex unchanged; its default, "never", means Codex never asks. approval_mode decides what Band does with each request, and defaults to "manual", which posts the request in the room.
With "on-request", Codex works inside its sandbox and asks when it needs to go beyond it; see Codex sandbox and approvals for the values. "on-request" does not guarantee a request: Codex can attempt a command inside the sandbox and get a denial without asking, and only the model decides to request escalation. A participant replies /approve, /decline, or /approve-session. For the other replies, see Answer Requests in the Room. For what happens when nobody answers, see Approval Timeouts.
Set the Sandbox
sandbox sets Codex’s sandbox mode for new threads and turns:
Unset (None), Codex uses its own default. sandbox_policy takes a full Codex sandbox policy dictionary instead and overrides sandbox.
A participant can change the sandbox for one room with /sandbox <mode>. Switching to danger-full-access needs /sandbox danger-full-access --confirm. When sandbox_policy is set, /sandbox changes are refused.
Room Commands
The adapter handles these commands itself instead of sending them to Codex. Address them to the agent, for example @<agent-handle> /status. While a turn runs, including one waiting on an approval, the adapter answers only the approval commands and /status; any other message stays pending until the turn ends.
The approval commands are described in Answer Requests in the Room.
Report Activity to the Room
By default the adapter sends everything it supports: Emit.TOOL_CALLS (commands, file changes, and tool calls), Emit.THOUGHTS (Codex reasoning and plans as thought events), Emit.TASK_EVENTS, and Emit.USAGE. Pass emit to narrow the set:
The startup log’s token_usage field shows a separate setting, emit_token_usage_events (default False), which also posts a task event each time Codex reports updated token usage. Emit.USAGE reports usage once per turn.
An emit set without Emit.TASK_EVENTS stops the adapter from recording thread IDs, so every restart starts a new Codex thread in each room instead of resuming it.
Configure with Environment Variables
Every CodexAdapterConfig field can come from a CODEX_-prefixed environment variable, such as CODEX_MODEL, CODEX_APPROVAL_MODE, or CODEX_SANDBOX. The Codex launch command comes from CODEX_COMMAND, a space-separated command line. A value passed to the constructor overrides the environment. For Band’s own variables, see Environment Variables.
Adapter Options
The model parameters are listed in Choose the Model. Pass emit, capabilities, and additional_tools to CodexAdapter itself, not to CodexAdapterConfig. transport accepts only "stdio": any other value raises ValueError: only stdio Codex transport guarantees room process isolation. For the full signature, see CodexAdapter in the SDK reference.
Connect from TypeScript
@band-ai/sdk 0.6.0 also ships CodexAdapter. It starts codex app-server from the Codex CLI itself, so it needs no npm package beyond @band-ai/sdk. Create the agent credentials as above, then set up the project:
Run it with npx tsx agent.ts. The TypeScript SDK logs nothing by default, and the process keeps running until you press Ctrl+C.
The TypeScript adapter differs from the Python one:
- Like the Python adapter, it starts one
codex app-serverprocess per room, on the room’s first message.config.cwd, which defaults to the directory you start the agent in, is the root of the room workspaces: each room works in<cwd>/.band-workspaces/<roomId>. To choose the directories yourself, passconfig.workspaceForRoom, a function from room ID to an absolute path. It cannot be combined withconfig.cwd. - It declines Codex’s approval requests instead of posting them to the room.
approvalPolicydefaults to"never"andsandboxModeto"workspace-write". turnTimeoutMsdefaults to180000.- Tool and thought events are off by default. Set
enableExecutionReportingandemitThoughtEventsto post them. - The room commands are
/help,/status,/model,/models, and/reasoning.
If config.cwd contains agent_config.yaml, Codex can read the agent’s API key, and its tool results post the key to the room. config.cwd defaults to the directory you start the agent in, so set it to a separate directory.