-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Codex web app architecture #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b674d43
275863c
f94bbc4
948947d
9b9f587
976c2ed
871fe5e
bb4f4d5
56349ee
84e3659
6238edb
1990db7
83ce5f4
f3d92c9
8cc7135
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,6 @@ node_modules | |
| *.log | ||
| *.tsbuildinfo | ||
| apps/*/dist | ||
| apps/*/dist-electron | ||
| packages/*/dist | ||
| .env | ||
| .env.local | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| # AGENTS.md | ||
| # CLAUDE.md | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filename and header mismatch. The file is named 🤖 Prompt for AI Agents |
||
|
|
||
| ## Project Snapshot | ||
| CodeThing is a minimal GUI for using code agents like Codex and Claude Code (coming soon). | ||
| CodeThing is a minimal web GUI for using code agents like Codex and Claude Code (coming soon). | ||
|
|
||
| This repository is a VERY EARLY WIP. Proposing sweeping changes that improve long-term maintainability is encouraged. | ||
|
|
||
|
|
@@ -13,17 +13,18 @@ This repository is a VERY EARLY WIP. Proposing sweeping changes that improve lon | |
| If a tradeoff is required, choose correctness and robustness over short-term convenience. | ||
|
|
||
| ## Package Roles | ||
| - `apps/desktop`: Electron main/preload runtime. Owns provider orchestration, process/session lifecycle, and native IPC boundaries. | ||
| - `apps/renderer`: React/Vite UI. Owns session UX, conversation/event rendering, and client-side state. | ||
| - `packages/contracts`: Shared Zod schemas and TypeScript contracts for provider events, IPC payloads, and model/session types. | ||
| - `apps/server`: Node.js WebSocket server. Wraps Codex app-server (JSON-RPC over stdio), serves the React web app, and manages provider sessions. | ||
| - `apps/renderer`: React/Vite UI. Owns session UX, conversation/event rendering, and client-side state. Connects to the server via WebSocket. | ||
| - `packages/contracts`: Shared Zod schemas and TypeScript contracts for provider events, WebSocket protocol, and model/session types. | ||
|
|
||
| ## Codex App Server (Important) | ||
| CodeThing is currently Codex-first. The desktop app starts `codex app-server` (JSON-RPC over stdio) per provider session, then streams structured events into the renderer through the provider APIs. | ||
| CodeThing is currently Codex-first. The server starts `codex app-server` (JSON-RPC over stdio) per provider session, then streams structured events to the browser through WebSocket push messages. | ||
|
|
||
| How we use it in this codebase: | ||
| - Session startup/resume and turn lifecycle are brokered in `apps/desktop/src/codexAppServerManager.ts`. | ||
| - Provider dispatch and thread event logging are coordinated in `apps/desktop/src/providerManager.ts`. | ||
| - Renderer consumes provider event streams via `nativeApi.providers.onEvent`. | ||
| - Session startup/resume and turn lifecycle are brokered in `apps/server/src/codexAppServerManager.ts`. | ||
| - Provider dispatch and thread event logging are coordinated in `apps/server/src/providerManager.ts`. | ||
| - WebSocket server routes NativeApi methods in `apps/server/src/wsServer.ts`. | ||
| - Renderer consumes provider event streams via WebSocket push on channel `providers.event`. | ||
|
|
||
| Docs: | ||
| - Codex App Server docs: https://developers.openai.com/codex/sdk/#app-server | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,67 +1,88 @@ | ||||||||||||||||||||||||||||||||||||
| # CodeThing (Electron + Vite + Bun) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| CodeThing is a desktop shell for coding agents. This first implementation is: | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| 1. Codex-first: connects to `codex app-server` and streams turn/item events. | ||||||||||||||||||||||||||||||||||||
| 2. Provider-ready: renderer speaks a provider abstraction so Claude Code can plug in later. | ||||||||||||||||||||||||||||||||||||
| 3. Typed end-to-end: contracts validate payloads at preload/main boundaries. | ||||||||||||||||||||||||||||||||||||
| # CodeThing | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| CodeThing is a minimal web GUI for coding agents. Currently Codex-first, with Claude Code support coming soon. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Run `npx t3` in any project directory to launch the web interface. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Architecture | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| CodeThing runs as a **Node.js WebSocket server** that wraps `codex app-server` (JSON-RPC over stdio) and serves a React web app. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||
| ┌─────────────────────────────────┐ | ||||||||||||||||||||||||||||||||||||
| │ Browser (React + Vite) │ | ||||||||||||||||||||||||||||||||||||
| │ Connected via WebSocket │ | ||||||||||||||||||||||||||||||||||||
| └──────────┬──────────────────────┘ | ||||||||||||||||||||||||||||||||||||
| │ ws://localhost:3773 | ||||||||||||||||||||||||||||||||||||
| ┌──────────▼──────────────────────┐ | ||||||||||||||||||||||||||||||||||||
| │ apps/server (Node.js) │ | ||||||||||||||||||||||||||||||||||||
| │ WebSocket + HTTP static server │ | ||||||||||||||||||||||||||||||||||||
| │ ProviderManager │ | ||||||||||||||||||||||||||||||||||||
| │ CodexAppServerManager │ | ||||||||||||||||||||||||||||||||||||
| └──────────┬──────────────────────┘ | ||||||||||||||||||||||||||||||||||||
| │ JSON-RPC over stdio | ||||||||||||||||||||||||||||||||||||
| ┌──────────▼──────────────────────┐ | ||||||||||||||||||||||||||||||||||||
| │ codex app-server │ | ||||||||||||||||||||||||||||||||||||
| └─────────────────────────────────┘ | ||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+11
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add language specifier to fenced code block. The ASCII architecture diagram lacks a language specifier, which triggers a markdownlint warning (MD040). While 📝 Suggested fix-```
+```text
┌─────────────────────────────────┐
│ Browser (React + Vite) │📝 Committable suggestion
Suggested change
🧰 Tools🪛 markdownlint-cli2 (0.20.0)[warning] 11-11: Fenced code blocks should have a language specified (MD040, fenced-code-language) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Workspace layout | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `/apps/desktop`: Electron main + preload process, includes provider and Codex session managers. | ||||||||||||||||||||||||||||||||||||
| - `/apps/renderer`: React + Vite UI for session control, conversation, and protocol event stream. | ||||||||||||||||||||||||||||||||||||
| - `/packages/contracts`: shared Zod schemas + TypeScript types for IPC and provider events. | ||||||||||||||||||||||||||||||||||||
| - `/apps/server`: Node.js WebSocket server. Wraps Codex app-server, serves the built renderer, and opens the browser on start. | ||||||||||||||||||||||||||||||||||||
| - `/apps/renderer`: React + Vite UI. Session control, conversation, and provider event rendering. Connects to the server via WebSocket. | ||||||||||||||||||||||||||||||||||||
| - `/packages/contracts`: Shared Zod schemas and TypeScript contracts for provider events, WebSocket protocol, and model/session types. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Codex prerequisites | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - Install Codex CLI so `codex` is on your PATH. | ||||||||||||||||||||||||||||||||||||
| - Authenticate Codex before running CodeThing (for example via API key or ChatGPT auth supported by Codex). | ||||||||||||||||||||||||||||||||||||
| - CodeThing starts the server via `codex app-server` per session. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Security and boundary model | ||||||||||||||||||||||||||||||||||||
| ## Quick start | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `nodeIntegration: false` | ||||||||||||||||||||||||||||||||||||
| - `contextIsolation: true` | ||||||||||||||||||||||||||||||||||||
| - `sandbox: true` | ||||||||||||||||||||||||||||||||||||
| - Renderer talks only to `window.nativeApi` exposed by preload. | ||||||||||||||||||||||||||||||||||||
| - Preload and main both validate inputs using shared Zod schemas. | ||||||||||||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||||||||||||
| # Development (with hot reload) | ||||||||||||||||||||||||||||||||||||
| bun run dev | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| `sandbox: true` above is Electron renderer sandboxing. It is separate from Codex execution sandbox policy (`read-only`, `workspace-write`, `danger-full-access`) used when starting provider sessions. | ||||||||||||||||||||||||||||||||||||
| # Production | ||||||||||||||||||||||||||||||||||||
| bun run build | ||||||||||||||||||||||||||||||||||||
| bun run start | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Runtime modes | ||||||||||||||||||||||||||||||||||||
| # Or from any project directory after publishing: | ||||||||||||||||||||||||||||||||||||
| npx t3 | ||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| CodeThing has a global runtime mode switch in the sidebar: | ||||||||||||||||||||||||||||||||||||
| ## Scripts | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `Full access` (default): starts new sessions with `approvalPolicy: never` and `sandboxMode: danger-full-access`. | ||||||||||||||||||||||||||||||||||||
| - `Approval required`: starts new sessions with `approvalPolicy: on-request` and `sandboxMode: workspace-write`, then prompts in-app for command/file approvals. | ||||||||||||||||||||||||||||||||||||
| - `bun run dev` — Starts contracts, server, and web dev tasks via Turborepo's parallel task runner. | ||||||||||||||||||||||||||||||||||||
| - `bun run dev:server` — Starts just the WebSocket server (uses tsx for TS execution). | ||||||||||||||||||||||||||||||||||||
| - `bun run dev:web` — Starts just the Vite dev server for the renderer. | ||||||||||||||||||||||||||||||||||||
| - `bun run start` — Runs the production server (serves built renderer as static files). | ||||||||||||||||||||||||||||||||||||
| - `bun run build` — Builds contracts, renderer, and server through Turbo. | ||||||||||||||||||||||||||||||||||||
| - `bun run typecheck` — Strict TypeScript checks for all packages. | ||||||||||||||||||||||||||||||||||||
| - `bun run test` — Runs workspace tests. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Mode changes apply across all threads. Existing live sessions are restarted so old and new threads use the selected mode. | ||||||||||||||||||||||||||||||||||||
| ## Runtime modes | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Scripts | ||||||||||||||||||||||||||||||||||||
| CodeThing has a global runtime mode switch in the chat toolbar: | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `bun run dev`: starts contract build/watch, renderer dev server, and Electron process. | ||||||||||||||||||||||||||||||||||||
| - `bun run build`: builds contracts, renderer, and desktop bundles through Turbo. | ||||||||||||||||||||||||||||||||||||
| - `bun run typecheck`: strict TypeScript checks for all packages. | ||||||||||||||||||||||||||||||||||||
| - `bun run test`: runs workspace tests. | ||||||||||||||||||||||||||||||||||||
| - **Full access** (default): starts sessions with `approvalPolicy: never` and `sandboxMode: danger-full-access`. | ||||||||||||||||||||||||||||||||||||
| - **Supervised**: starts sessions with `approvalPolicy: on-request` and `sandboxMode: workspace-write`, then prompts in-app for command/file approvals. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## CI quality gates | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `.github/workflows/ci.yml` runs `bun run lint`, `bun run typecheck`, and `bun run test` on pull requests and pushes to `main`. | ||||||||||||||||||||||||||||||||||||
| ## Provider architecture | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Optional: | ||||||||||||||||||||||||||||||||||||
| The renderer communicates with the server via WebSocket using a simple JSON-RPC-style protocol: | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| - `ELECTRON_RENDERER_PORT=5180 bun run dev` if `5173` is already in use. | ||||||||||||||||||||||||||||||||||||
| - **Request/Response**: `{ id, method, params }` → `{ id, result }` or `{ id, error }` | ||||||||||||||||||||||||||||||||||||
| - **Push events**: `{ type: "push", channel, data }` for streaming provider events | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| ## Provider architecture | ||||||||||||||||||||||||||||||||||||
| Methods mirror the `NativeApi` interface defined in `@acme/contracts`: | ||||||||||||||||||||||||||||||||||||
| - `providers.startSession`, `providers.sendTurn`, `providers.interruptTurn` | ||||||||||||||||||||||||||||||||||||
| - `providers.respondToRequest`, `providers.stopSession`, `providers.listSessions` | ||||||||||||||||||||||||||||||||||||
| - `shell.openInEditor`, `server.getConfig` | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| The renderer now depends on `nativeApi.providers.*`: | ||||||||||||||||||||||||||||||||||||
| Codex is the only implemented provider. `claudeCode` is reserved in contracts/UI. | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| 1. `startSession` | ||||||||||||||||||||||||||||||||||||
| 2. `sendTurn` | ||||||||||||||||||||||||||||||||||||
| 3. `interruptTurn` | ||||||||||||||||||||||||||||||||||||
| 4. `respondToRequest` | ||||||||||||||||||||||||||||||||||||
| 5. `stopSession` | ||||||||||||||||||||||||||||||||||||
| 6. `listSessions` | ||||||||||||||||||||||||||||||||||||
| 7. `onEvent` | ||||||||||||||||||||||||||||||||||||
| ## CI quality gates | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Codex is the only implemented provider right now. `claudeCode` is reserved in contracts/UI but returns a not-implemented error in main-process dispatch. | ||||||||||||||||||||||||||||||||||||
| - `.github/workflows/ci.yml` runs `bun run lint`, `bun run typecheck`, and `bun run test` on pull requests and pushes to `main`. | ||||||||||||||||||||||||||||||||||||
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Bun 1.3.9 release changelog breaking changes💡 Result:
Bun v1.3.9 (published Feb 8, 2026) does not call out any explicit “breaking changes” section in the official changelog. The release is mostly new features, fixes, and perf work. [1]
Possible breaking / behavior-changing items to watch:
NO_PROXYis now respected even when you pass an explicitproxyoption tofetch()/new WebSocket()—requests that previously went through the proxy may now bypass it (or vice‑versa, depending on your env). [1]Not breaking, but notable changelog items:
bun run --parallel/--sequentialfor running multiple scripts (with workspace/filter integration). [1]bun:testmock()/spyOn()implementSymbol.dispose(works withusingto auto-restore). [1]--compilenow supports ESM bytecode (--bytecode --format=esm). [1]Source
Citations:
🌐 Web query:
Bun version history 1.1.38 to 1.3.9 what changed💡 Result:
Between Bun v1.1.38 (Nov 29, 2024) and Bun v1.3.9 (Feb 8, 2026), the highlights were:
postgrescrash, TypeScript minification bug,fetch()rare crash,Bun.FileSystemRouter.reload()fix),reusePortforBun.listen/node:net, SQLite 3.45 → 3.47, plus other compatibility fixes. [1].htmldirectly as a dev server with hot reload/bundling; built-in routing forBun.serve()(routes);bun initReact template;bun install --analyze; plus Node.js compatibility and Bun.SQL improvements. [2]bun:test(and other fixes). [3]Bun.spawn({ terminal: ... })for truly interactive subprocesses. [4]Bun.markdown(CommonMark-compliant parser) +bun build --metafile-mdfor Markdown bundle analysis output. [6]bun run --parallel/--sequentialfor running multiple scripts;bun:testSymbol.disposesupport formock()/spyOn()(works withusing);NO_PROXYhonored even with explicit proxy options;--cpu-prof-interval; ESM bytecode support in--compile --bytecode; ARM crash fix on older ARMv8.0 CPUs; plus performance work (Markdown, AbortSignal) and a JavaScriptCore upgrade with multiple JIT/SIMD improvements. [7]Sources: Bun blog release notes for v1.1.38, v1.2.3, v1.3.4, v1.3.5, v1.3.6, v1.3.8, v1.3.9. [1][2][3][4][5][6][7]
Confirm Bun 1.3.9 is tested against behavior changes before merging.
Bun 1.3.9 was published Feb 8, 2026 and is stable. However, the jump from 1.1.38 introduces two behavior-changing items to watch:
NO_PROXYis now respected even with an explicitproxyoption tofetch()/new WebSocket()—requests may route differently than before.Ensure
bun run test && bun run checkexercise code paths affected by these changes.🤖 Prompt for AI Agents