Skip to content

Codex Remote surface (codex.justinsforge.com)

URL: https://mkdocs.justinsforge.com/memory/general/reference_codex_chat_surface/

A mobile-first web client for OpenAI Codex, running live on Console. It drives one long-lived codex app-server process using the ChatGPT login stored in CODEX_HOME. It does not use an OpenAI API key or proxy requests through a third party. Pick a repo, configure model and effort, start a thread, send text and images, steer or stop an active turn, answer native requests, and watch plans, commands, file changes, reasoning summaries, diffs, usage, and final responses stream into the browser.

Each local thread is bound to a repo and runs in its own throwaway git worktree, so Codex never dirties main. The service preserves its own searchable thread and message index while the native Codex thread remains the execution authority. Originally built 2026-07-08 and migrated from one-shot codex exec processes to the native app-server protocol on 2026-07-13.

Pieces

Piece Where
Production https://codex.justinsforge.com (Cloudflare Access, email allowlist [email protected], app uid 3432a3ef-8182-4f40-b1bd-9d8a05f5ed07, AUD fce9858c...5584b0; VR Alliance tunnel fb20b500-0119-4c84-9536-fa85751987c3 ingress -> http://127.0.0.1:7366)
Service scripts/forge_codex_chat_api.py, FastAPI, port 7366, bind 0.0.0.0
App-server client scripts/forge_codex_app_server.py, restartable async JSON-RPC over stdio
Unit systemctl --user status forge-codex-chat (user unit, linger)
Venv infra/codex-chat/.venv (fastapi, uvicorn, pyjwt)
UI sites/justinsforge.com/codex/{index.html,app.js,app.css} (served at /)
DB data/codex_chat.db (sqlite: threads, messages, thread_events)
Uploads data/codex_uploads/<thread>/
Worktrees ~/codex-work/<repo>/<thread> on branch codex/<thread>
Repo registry scripts/forge_codex_repos.py (forge, creatortrack, new-app; edit to add)
AGENTS.md writer scripts/forge_codex_agents_md.py + templates/codex_AGENTS.md.tmpl
Log journalctl --user -u forge-codex-chat

Codex install (Console)

  • Binary: ~/.local/bin/codex (codex-cli 0.144.2 when this page was updated).
  • Sandbox helper: ~/.local/bin/bwrap (Codex-bundled bubblewrap).
  • CODEX_HOME ~/.codex: config.toml (approval_policy=never, sandbox_mode=workspace-write, network_access=true) + auth.json (ChatGPT login, codex login --device-auth). No OpenAI API key is involved. Separate from Anthropic credentials. Pinned in ~/.forge-secrets/codex.env (CODEX_HOME, PATH).
  • Userns gotcha (load-bearing): Ubuntu 24.04 ships kernel.apparmor_restrict_unprivileged_userns=1, which blocks bwrap with setting up uid map: Permission denied. Fixed by kernel.apparmor_restrict_unprivileged_userns=0 persisted at /etc/sysctl.d/60-codex-userns.conf. Without it, Codex's shell/file tools fail before any write. This keeps the real workspace-write sandbox (writes confined to the worktree) instead of bypassing it.

Auth

CF Access JWT (Cf-Access-Jwt-Assertion, validated PyJWT vs CF_ACCESS_TEAM_DOMAIN / comma-separated CF_ACCESS_AUD in forge/.env) OR bearer CODEX_CHAT_TOKEN (forge/.env) for LAN/tailnet. Same pattern as [[reference_session_launcher]]. The UI stores an optional bearer token in localStorage (Settings gear) for direct LAN use; behind Access it rides the login cookie, no token needed.

Native architecture

The FastAPI process owns one restartable codex app-server --listen stdio:// child. The browser never talks directly to the experimental app-server websocket. The service initializes the experimental protocol locally, correlates JSON-RPC requests, fans notifications out by native thread id, holds server-initiated approval and input requests until the browser responds, and records active turn ids. Browser SSE streams are reconnectable: the native turn keeps running after a tab disconnects, with a bounded event replay buffer when the client returns.

The native protocol supplies:

  • Thread start, resume, rename, archive, unarchive, delete, and context compaction.
  • Turn start, live steering, interruption, diff and token-usage updates.
  • Inline review turns for uncommitted changes.
  • Command, file, permission, and request_user_input responses.
  • Background terminal listing and termination.
  • Account, model catalog, rate-limit, and native remote-control status.
  • Native remote-control enablement, manual pairing codes, and paired-client list.

Web capabilities

  • Searchable active and archived thread lists with persistent history.
  • Model, effort, build or plan mode, and approval-policy controls per new thread.
  • Coding scenarios: feature, bug fix, review, integrate, and explore only.
  • Optional launch modifiers for plan-first, dev preview, frequent commits, push, notification, tool registration, and bounded parallel-agent instructions.
  • Up to six pasted, dropped, or selected images per turn.
  • Streaming messages, reasoning summaries, plans, command and file activity, diffs, warnings, usage, and reconnectable completion state.
  • Send while running to steer; explicit stop to interrupt.
  • Rename, archive or unarchive, review changes, compact context, and delete.
  • Stable per-thread dev-server port and preview link detection.
  • Responsive drawer and bottom-sheet layout with reduced-motion support.

Endpoints

All /api/* endpoints require Cloudflare Access or the bearer token. /healthz is open at the origin but still Access-gated at the public edge.

  • GET /api/runtime: ChatGPT account type, model catalog, rate limits, app-server, and native remote-control status. Account email is never returned.
  • GET /api/repos: allowlisted repo picker rows.
  • POST /api/threads: creates worktree and AGENTS.md, starts a native thread, and applies model, effort, mode, approval policy, scenario, and modifiers.
  • GET /api/threads?archived=&search= and GET /api/threads/{id}: list and read local metadata, messages, usage, native pending requests, and preview details.
  • Thread controls: rename, archive, unarchive, compact, review, and DELETE /api/threads/{id}.
  • Turn controls: POST .../turn for SSE, GET .../events to reconnect, POST .../steer, and POST .../stop.
  • Images and preview: POST .../images, GET .../img/{fid}, and GET .../preview.
  • Native requests: GET .../pending and POST /api/approvals/{request_id}.
  • Background terminals: GET .../terminals and DELETE .../terminals/{process_id}.
  • Remote control: POST /api/remote-control/enable, disable, pair, and GET /api/remote-control/clients.

Ops

systemctl --user restart forge-codex-chat     # edits to the API/UI go live on restart
journalctl --user -u forge-codex-chat -n 50
curl http://127.0.0.1:7366/healthz
python3 scripts/forge_codex_repos.py --list    # repos in the picker
python3 scripts/forge_codex_repos.py --self-test
  • Add a repo: edit REPOS in scripts/forge_codex_repos.py, restart.
  • Worktrees are disposable; deleting a thread removes its worktree + codex/<thread> branch.
  • Remote-control pairing is opt-in. Keep Cloudflare Access in front of the web UI and do not expose the app-server websocket through the tunnel.
  • [[reference_session_launcher]] (the Claude equivalent, chat.justinsforge.com)
  • [[reference_code_server]] | [[reference_cloudflare]] | [[feedback_no_threads_with_subprocess_run]]