Codex Remote Collaboration VS Code Bridge
This extension connects local and Aether relay channels to one switchable Codex
control host. Synchronous mode follows the conversation currently shown by
the official Codex VS Code extension through its private IPC protocol and does
not spawn a codex process. Asynchronous mode starts an independent
app-server and lets the Web UI list, resume, create, and select conversations.
The attached conversation remains visible and usable in the official Codex panel. Remote operators can observe its output, submit a new turn or steer the active turn, interrupt it, and answer supported approval/input requests.
The mode can be changed from the Web UI without reconnecting either relay. Synchronous mode makes the official panel the only conversation-navigation owner; asynchronous mode restores the browser history and new-conversation actions. A running turn or pending request blocks mode changes.
Requirements
- The official
openai.chatgptVS Code extension is installed and signed in. - The target Codex conversation is open and owned by that extension.
- The bridge and official extension run as the same OS user. The default Unix
socket is
$CODEX_HOME/ipc/ipc.sock, normally~/.codex/ipc/ipc.sock. - For a loopback
ws://URL, the extension starts and owns its bundled relay automatically. Remote andwss://relay URLs remain externally hosted.
The IPC follower protocol is private and versioned, not a public OpenAI API. An official extension update can require a compatible bridge update. Strict stream-version checks are enabled by default so an unknown protocol fails closed instead of being interpreted optimistically.
Build and install
npm install
npm run check
npm run build
npx --yes @vscode/vsce package
code --install-extension codex-remote-collab-0.4.0.vsix --force
Run Developer: Reload Window after installing or replacing the VSIX.
Configure control modes
For the local default, no separate relay command is required. The extension
starts the bundled relay on the host and port from codexRemoteCollab.localRelayUrl.
To run the development relay manually, disable
codexRemoteCollab.autoStartLocalRelay and use:
HOST=127.0.0.1 PORT=8787 CODEX_REMOTE_MODE=host npm start
To opt into authentication later, set CODEX_REMOTE_AUTH=required and the three
token variables before starting the relay.
Set the extension configuration:
{
"codexRemoteCollab.localRelayUrl": "ws://127.0.0.1:8787/v1/connect",
"codexRemoteCollab.controlMode": "sync",
"codexRemoteCollab.autoDiscoverThread": true,
"codexRemoteCollab.autoStart": true
}
Then:
- Open the target conversation in the official Codex panel.
- Reload VS Code once after installing the companion extension. The local relay and bridge start automatically; no token is needed for loopback. The status item opens the Web console and is not a connect/disconnect toggle.
- Open the relay web console; it connects automatically on localhost. The web UI uses a Codex-style conversation stream with a bottom composer; Enter sends and Shift+Enter inserts a newline. There is no separate connect/disconnect step for the local relay.
If the browser says that it is waiting for the VS Code host or the recent-session list is
empty, verify that codexRemoteCollab.localRelayUrl uses the same port as the relay and run
Developer: Reload Window. Keep codexRemoteCollab.threadId empty unless a specific
conversation must be pinned; an old closed ID can prevent startup until it is cleared.
When authentication is enabled, run Codex Remote: Set Relay Token with the
host token. It is stored in vscode.SecretStorage, not in settings; the browser
uses the operator or viewer token separately.
With no configured thread ID, the bridge ranks recent VS Code rollout metadata and shows only candidates verified by live IPC owner discovery and a matching follower snapshot. Explicit Codex Desktop tasks, closed, stale, and other non-attachable history entries are omitted. In synchronous mode, switching the conversation in the official Codex panel also switches the Web projection after the new owner snapshot is ready. The Web UI cannot list, select, or create conversations in this mode. Switch to asynchronous mode when the browser should own conversation navigation. To avoid ambiguity when several Codex windows are open, run Codex Remote: Set Existing Thread ID. An empty value restores automatic discovery.
Useful commands:
- Codex Remote: Start Bridge / Stop Bridge
- Codex Remote: Set Existing Thread ID
- Codex Remote: Set Relay Token
- Codex Remote: Pair with Aether
- Codex Remote: Configure Aether Cloud Relay
- Codex Remote: Send Input
- Codex Remote: Show Snapshot
Settings
| Setting | Default | Meaning |
|---|---|---|
codexRemoteCollab.controlMode |
sync |
sync follows VS Code; async owns an independent app-server. |
codexRemoteCollab.localRelayUrl |
ws://127.0.0.1:8787/v1/connect |
Bundled loopback relay used by the local Web control. |
codexRemoteCollab.aetherUrl |
empty | Aether origin remembered by the pairing command. |
codexRemoteCollab.cloudRelayUrl |
empty | Aether WebSocket relay URL populated by pairing. |
codexRemoteCollab.threadId |
empty | Exact existing conversation ID; empty enables discovery. |
codexRemoteCollab.autoDiscoverThread |
true |
Discover and owner-check a local VS Code session. |
codexRemoteCollab.followVscodeSession |
true |
Legacy compatibility setting; synchronous mode always follows VS Code. |
codexRemoteCollab.ipcSocketPath |
empty | Override the local IPC socket path. |
codexRemoteCollab.hostId |
local |
Owner-discovery host identifier. |
codexRemoteCollab.ipcStrictVersions |
true |
Reject unsupported stream protocol versions. |
codexRemoteCollab.approvalTimeoutMs |
300000 |
Deny an unanswered request locally after this delay. |
codexRemoteCollab.allowHighRiskApprovals |
false |
Permit remote high-risk approvals when explicitly enabled. |
codexRemoteCollab.codexCommand, codexArgs, and defaultCwd apply only to
asynchronous mode. The deprecated mode=attach/spawn values map to
controlMode=sync/async when no explicit control mode exists.
Pair with Aether
The local relay stays enabled after cloud pairing. In Aether, open Codex remote control and generate a one-time code. Then run Codex Remote: Pair with Aether from the VS Code Command Palette, enter the Aether server URL and the code, and the bridge will connect to both relays. The long-lived device credential is stored only in VS Code SecretStorage. Revoke a lost or retired device from the Aether page.
Relay behavior
The bridge sends a hello and, when a relay token is configured, a separate
bearer-auth frame over an outbound WebSocket. It publishes normalized events including:
connection.opened/connection.closedsession.snapshotoutput.snapshot/output.chunktask.started/task.finished/task.cancelledapproval.requested/approval.resolved/approval.expiredinput.requested/input.resolved/input.expired
Remote commands are mapped to the existing conversation owner:
control/mode/setatomically switches betweensyncandasync.session/list,session/select, andsession/neware available only in asynchronous mode and map tothread/list,thread/resume, andthread/start.turn/startstarts a turn in the attached thread.turn/steeradds input to the active turn.turn/interruptinterrupts the expected active turn.approval.respond,input.respond, andserver.request.respondpreserve the original request ID and use method-specific follower responses.thread/startis deliberately rejected in synchronous mode because VS Code owns conversation navigation there.
The browser never connects directly to the IPC socket. Relay and host both enforce role/capability checks; high-risk command approval remains disabled unless the local VS Code setting opts in.
Supported follower requests
item/commandExecution/requestApprovalitem/fileChange/requestApprovalitem/permissions/requestApprovalitem/tool/requestUserInputmcpServer/elicitation/request- legacy
applyPatchApprovalandexecCommandApproval
Unanswered requests expire with a local deny. JSON-RPC numeric and string IDs remain distinct, and a response can be submitted only once.
Legacy mode migration
The old setting remains accepted:
{
"codexRemoteCollab.mode": "spawn",
"codexRemoteCollab.codexCommand": "/absolute/path/to/codex",
"codexRemoteCollab.codexArgs": ["app-server", "--stdio"]
}
It maps to controlMode=async. Prefer the new setting directly. A
spawn codex ENOENT error belongs only to asynchronous mode; it is not a
synchronous-mode prerequisite or a PATH problem that needs fixing for
existing-session control.
The standalone npm run start:stdio entry point and createBridge() helper
also retain the legacy app-server adapter for compatibility.
Embedding the attach adapter
The reusable exports are in src/index.ts:
import {
CodexIpcAgentAdapter,
RelayClient,
RelayHost,
} from "codex-remote-collab";
const adapter = new CodexIpcAgentAdapter({
threadId: process.env.CODEX_THREAD_ID,
autoDiscoverThread: true,
});
const relay = new RelayClient({
url: "wss://relay.example.test/v1/connect",
accessToken: process.env.CODEX_REMOTE_HOST_TOKEN,
});
const host = new RelayHost({ adapter, relay });
await host.start();
CodexIpcClient is exported separately for protocol fixtures and diagnostics.
Use followConversation() before follower mutations, and always target the
owner returned by findThreadOwner().
Troubleshooting
- No existing session found: open the target official Codex conversation, keep that VS Code window running, then retry or set its exact thread ID.
- Owner not found: the rollout exists on disk but no live official client currently owns it. Reopen the conversation in the Codex panel.
- IPC version mismatch: update this bridge for the installed official extension. Disabling strict versions is diagnostic only.
- Relay stays at waiting for host: confirm host mode, relay URL, and that no second host is already connected. If authentication is enabled, also check the host token.
- Old
spawn codex ENOENTmessage: install version0.4.0, reload VS Code, and verifycodexRemoteCollab.controlModeissyncunless independent conversations are intended.