codex-webstrap is a macOS wrapper that lets you run the Codex desktop client UI in a browser while keeping backend execution local.
This started as a personal project to remotely access the Codex desktop experience; it is open sourced so others can use and improve it.
Screen.Recording.-.Frosted.Sidebar.mov
Codex desktop is not a pure web app. The renderer expects Electron preload APIs, IPC, local process control, worker threads, and desktop-only integrations.
codex-webstrap makes browser access possible by:
- Serving Codex's bundled web assets.
- Injecting a browser shim that emulates key
electronBridgepreload methods. - Bridging renderer messages over WebSocket to local backend handlers.
- Forwarding app protocol traffic to local
codex app-serverand UDS IPC where available.
Default endpoint: http://127.0.0.1:8080
bin/codex-webstrap.sh- CLI entrypoint and env/arg normalization.
src/server.mjs- HTTP + WS host, auth gating, startup orchestration.
src/auth.mjs- Persistent token bootstrap +
cw_sessioncookie sessions.
- Persistent token bootstrap +
src/assets.mjs- Discovers Codex app bundle, extracts/caches
app.asarassets, patchesindex.html.
- Discovers Codex app bundle, extracts/caches
src/bridge-shim.js- Browser-side Electron preload compatibility layer (
window.electronBridge).
- Browser-side Electron preload compatibility layer (
src/ipc-uds.mjs- Framed UDS client (
length-prefix + JSON) forcodex-ipc.
- Framed UDS client (
src/app-server.mjs- Local
codex app-serverprocess manager over stdio JSON-RPC.
- Local
src/message-router.mjs- Message dispatch, terminal lifecycle, worker bridge, unsupported fallbacks.
- Wrapper starts Node server and loads config.
- Auth token is created/read from token file.
- Codex app assets are extracted to a versioned cache directory.
- Patched
index.htmlis served with shim injection. - Browser opens
/, shim connects tows://<host>/__webstrapper/bridge. - Renderer messages are routed to:
- app-server JSON-RPC (
thread/*, turns, config, etc.) - UDS broadcast forwarding where relevant
- terminal sessions (
spawn,write,close) - git worker bridge path
- app-server JSON-RPC (
- Results are sent back as bridge envelopes and posted to the renderer via
window.postMessage.
Codex desktop behavior depends on Electron/main-process features unavailable to normal browser JavaScript, including:
- preload-only bridge APIs
- local privileged process orchestration
- desktop IPC channels
- local worker/protocol assumptions
This project provides near-parity by emulation/bridging, not by removing those dependencies.
codex-webstrap [--port <n>] [--bind <ip>] [--open] [--token-file <path>] [--codex-app <path>]
codex-webstrapper [--port <n>] [--bind <ip>] [--open] [--token-file <path>] [--codex-app <path>]
codex-webstrapper open [--port <n>] [--bind <ip>] [--token-file <path>] [--copy]CODEX_WEBSTRAP_PORTCODEX_WEBSTRAP_BINDCODEX_WEBSTRAP_TOKEN_FILECODEX_WEBSTRAP_CODEX_APPCODEX_WEBSTRAP_INTERNAL_WS_PORT
GET /GET /__webstrapper/shim.jsGET /__webstrapper/healthzGET /__webstrapper/auth?token=...
GET /__webstrapper/bridge
view-messagemain-messageworker-messageworker-eventbridge-errorbridge-ready
- macOS
- Node.js 20+
- Installed Codex app bundle at
/Applications/Codex.app(or pass--codex-app)
By default, webstrapper runs the app-server via the bundled desktop CLI at:
/Applications/Codex.app/Contents/Resources/codex
Optional override:
CODEX_CLI_PATH=/custom/codex
npm installGlobal CLI install:
npm install -g codex-webstrapperWith global install:
codex-webstrapper --port 8080 --bind 127.0.0.1From local checkout:
./bin/codex-webstrap.sh --port 8080 --bind 127.0.0.1Optional auto-open:
codex-webstrapper --openGenerate/open the full auth URL from your persisted token:
codex-webstrapper openCopy the full auth URL (including token) to macOS clipboard:
codex-webstrapper open --copy- On first run, a random token is persisted at
~/.codex-webstrap/token(default path). - You authenticate once via:
open "http://127.0.0.1:8080/__webstrapper/auth?token=$(cat ~/.codex-webstrap/token)"Or use the helper command:
codex-webstrapper open- Server sets
cw_sessioncookie (HttpOnly,SameSite=Lax, scoped to/). - UI and bridge endpoints require a valid session cookie.
This project can expose powerful local capabilities if misconfigured. Treat it as sensitive software.
- Remote users with valid session can operate Codex UI features and local workflows.
- Token bootstrap URL can be leaked via shell history, logs, screenshots, or shared links.
- Binding to non-local interfaces increases attack surface.
- No built-in TLS termination. Plain HTTP should not be exposed directly to the public internet.
- Keep default bind:
127.0.0.1unless remote access is required. - If remote access is needed, use a private overlay network (for example Tailscale/WireGuard) and not public port-forwarding.
- Do not share token values in chat, screenshots, logs, issue reports, or commit history.
- Rotate token file if exposure is suspected:
rm -f ~/.codex-webstrap/tokenThen restart wrapper to generate a new token.
- Consider external TLS/auth proxy if you must serve beyond localhost.
Implemented coverage includes:
- core message routing (
ready,fetch,mcp-*,terminal-*,persisted-atom-*,shared-object-*) - thread lifecycle actions including archive/unarchive pathing
- worker message support (including git worker bridge)
- browser equivalents for desktop-only UX events (open links, diff/plan summaries)
- graceful unsupported handling for non-web-native desktop actions
Unknown message types produce structured bridge-error responses and do not crash the session.
npm testBootstrap env/secrets from another worktree checkout:
./scripts/worktree-bootstrap.sh --dry-run
./scripts/worktree-bootstrap.sh --mode symlinkCore paths are configured via:
scripts/worktree-secrets.manifest
Codex setup-script compatible command:
./scripts/worktree-bootstrap.sh --mode symlink --overwrite backup --extras on --install on --checks on401 unauthorized- Authenticate first via
/__webstrapper/auth?token=....
- Authenticate first via
- UI loads but actions fail
- Check
GET /__webstrapper/healthzfor app-server/UDS readiness.
- Check
- Codex app not found
- Pass
--codex-app /path/to/Codex.app.
- Pass
codexCLI spawn failures- Ensure the bundled CLI exists in your Codex app install, or set
CODEX_CLI_PATH.
- Ensure the bundled CLI exists in your Codex app install, or set
MIT. See LICENSE.md.
