Codex Remote is an MIT-licensed Web/PWA control plane for local Codex sessions on multiple macOS and Windows computers. A browser talks to one Registry/Hub; each user-level Agent keeps a single outbound WSS connection to that Hub and uses the official Codex App Server over stdio.
This repository is a clean-room public implementation. It contains only fictional fixtures and example domains. It does not depend on any private prototype, internal endpoint, local Codex file format, JSONL rollout, or Codex SQLite database.
- Login with scrypt password verification, 15-minute signed access credentials, and automatic renewal through an
HttpOnly/SameSite=Strictrefresh cookie. - One-time, five-minute device pairing codes and long-lived random device credentials.
- Pinned
registryUrl,trustDomain, anddeviceId; replacing them requires explicit unpair/removal. - Outbound-only Agent WSS with heartbeat, reconnect, backoff, timeout, and offline errors.
- Device list/presence, Codex history, streaming deltas, interruption, and approvals.
- Threads grouped into collapsible workspace folders derived from the official App Server
cwd; start a chat globally or directly inside a workspace. - Real
thread/start,thread/fork,turn/start, andturn/steeradapter operations against the installed Codex version. - In-memory per-conversation message queue with edit/remove controls, plus same-turn guidance through
turn/steer. - Image and file attachments with inline image previews and file cards. Files travel through the Hub only in volatile WSS frames and are stored on the paired Agent for Codex to access.
- React/Vite installable PWA with native-style desktop and mobile workspaces and no CDN/analytics/runtime scripts.
- SQLite metadata behind a storage interface. Hub memory routes message bodies but never persists them.
- Current-user LaunchAgent and Windows Scheduled Task installers.
- A fully fictional Mock Agent for development without Codex.
flowchart LR
PWA["PWA"] -->|"HTTPS / WSS"| HUB["Registry / Hub"]
AGENT["macOS / Windows Agent"] -->|"outbound WSS"| HUB
AGENT -->|"JSONL JSON-RPC over stdio"| CODEX["codex app-server"]
Deploy the same artifacts twice with independent configuration:
- Personal: public PWA + public Hub + personal Agents,
APP_MODE=personal. - Company: intranet PWA + intranet Hub + company Agents,
APP_MODE=company.
The two deployments must use different domains, databases, signing secrets, credentials, TLS certificates, and device identities. There is no discovery or fallback from one Registry to another.
More detail: architecture, security boundaries, deployment, Codex adapter.
- Node.js 22.5+ (tested with 24.15.0)
- pnpm 11+
- Codex CLI for real Agent use (tested with
codex-cli 0.145.0-alpha.18) - Docker only for the optional container deployment
git clone https://github.com/cpys/codex-remote.git
cd codex-remote
pnpm install
pnpm schema:codex
pnpm build
pnpm testTerminal 1:
$env:HUB_TOKEN_SECRET='development-only-secret-change-me-123456'
$env:HUB_ADMIN_PASSWORD='dev-only-change-me'
pnpm --filter @codex-remote/hub devTerminal 2:
pnpm --filter @codex-remote/web devOpen http://127.0.0.1:5173, sign in as admin, and use + to create a pairing code. The development password exists only when NODE_ENV is not production; production refuses missing/short secrets.
To use fictional data instead of Codex, start the Mock Agent after the Hub:
$env:HUB_ADMIN_PASSWORD='dev-only-change-me'
pnpm --filter @codex-remote/mock-agent devTo pair a real Agent:
pnpm --filter @codex-remote/agent build
node apps/agent/dist/cli.js pair --registry http://127.0.0.1:8787 --trust-domain personal --code 12345678 --name "My PC"
node apps/agent/dist/cli.js run
node apps/agent/dist/cli.js healthThe Agent permits plain HTTP only for localhost. All non-local deployments require HTTPS/WSS.
pnpm build production builds for all components
pnpm typecheck strict TypeScript check
pnpm test unit and integration tests
pnpm test:e2e real Hub + fictional Mock Agent + browser tests
pnpm test:real-e2e opt-in local Codex test; reads a thread and adds the exact acceptance turn
pnpm schema:codex regenerate current installed Codex App Server types/schema
If Playwright's bundled Chromium is unavailable, set PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH to a local Chrome/Chromium executable before pnpm test:e2e.
Copy .env.example to an external secret/config source and replace every secret. Never commit .env. TLS terminates at a reverse proxy; proxy /api, /ws, and /healthz to the Hub and all other paths to the PWA.
Copy-Item deploy/examples/personal.env.example deploy/docker/.env
docker compose -f deploy/docker/compose.yaml --env-file deploy/docker/.env build
docker compose -f deploy/docker/compose.yaml --env-file deploy/docker/.env up -dCompany deployments build the public source inside the company environment with company.env.example; they do not consume a personal build artifact and do not publish changes, configuration, telemetry, or data back to this repository or a public service.
macOS (current user LaunchAgent):
pnpm --filter @codex-remote/agent build
./installers/macos/install.shWindows (current user Scheduled Task, never LocalSystem):
pnpm --filter @codex-remote/agent build
powershell -ExecutionPolicy Bypass -File installers/windows/Install-CodexRemote.ps1Pair before starting the background process, or restart it after pairing. Identity is preserved by uninstall unless the explicit purge option is used.
- Hub logs are disabled by default; audit rows contain action/outcome identifiers only.
- Hub stores no prompt, response, code, tool output, token, or local session body.
- The Hub can observe message bodies in volatile process memory while routing; this MVP is transport-secure, not browser-to-Agent end-to-end encrypted.
- Device credentials and pairing codes are stored only as one-way digests.
- No third-party analytics, runtime scripts, public CDN, or automatic Registry discovery.
- Automatic Agent updates are disabled in the MVP. The optional update URL is configuration-only; company mode rejects an update origin different from its pinned Registry origin.
- Codex desktop and Codex Remote cannot safely write the same thread at the same time because each owns a separate App Server connection and the official API exposes no cross-process loaded-thread lock. Agent v0.2.1 therefore permits browsing while the desktop is open but rejects thread creation, turns, steering, interruption, and approval writes until the desktop app is closed. Before continuing an existing thread remotely, Agent restarts its App Server so it resumes from current persisted history. Do not override this single-writer boundary.
- Personal and single-user deployments intentionally use one environment-seeded administrator; SSO/OIDC is not required. Central identity is only a future option for deployments that need multi-user administration.
- The editable pending-message queue lives in the current PWA process and is lost on reload or device/thread switching. The Hub never persists it.
- Editing an already-sent historical message and automatically forking from that point is not in the Web UI yet. The v2 protocol and adapter already expose
thread.forkfor that next step. - Attachments are limited to four files, 8 MB each and 16 MB total. They are stored under the paired user's
~/.codex-remote/attachments; automatic retention cleanup and browser download are not implemented yet. - A global chat starts without a selected workspace; the App Server defaults it to the Agent user's home directory, so it appears under that folder after creation.
- No browser-direct Agent transport, push notifications, or audio.
- Browser access tokens expire after 15 minutes and renew automatically while the 30-day refresh cookie remains valid; an invalid or expired refresh credential returns the PWA to sign-in instead of showing an empty reconnecting state.
- Approval rendering supports the core allow/decline decisions; richer structured user-input prompts are a next phase.
- Thread rename/archive/search, model/effort/permission selectors, diff viewer, terminal UI, skills/apps surfaces, and sent-message fork editing remain future parity work.
- Docker Compose files are optional server-deployment helpers; Node.js/pnpm local and server deployments do not require Docker.
- Auto-update is deliberately not implemented; releases are installed explicitly.
The personal GitHub repository is the sole upstream and may remain private until the maintainer chooses to publish it. Contributions must use synthetic fixtures and must never include company domains, IPs, accounts, certificates, logs, session exports, patches, build artifacts, or derived private code. See CONTRIBUTING.md.