t3code

README.md

T3 Code

T3 Code 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. Run bun run dev:desktop to launch the Electron desktop app in this monorepo.

Architecture

T3 Code 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               │
└─────────────────────────────────┘

Workspace layout

  • /apps/server: Node.js WebSocket server. Wraps Codex app-server, serves the built web app, and opens the browser on start.
  • /apps/web: React + Vite UI. Session control, conversation, and provider event rendering. Connects to the server via WebSocket.
  • /apps/desktop: Electron shell. Spawns a desktop-scoped t3 backend process and loads the shared web app.
  • /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 T3 Code (for example via API key or ChatGPT auth supported by Codex).
  • T3 Code starts the server via codex app-server per session.

Quick start

# Development (with hot reload)
bun run dev

# Desktop development
bun run dev:desktop

# Desktop development on an isolated port set
T3CODE_DEV_INSTANCE=feature-xyz bun run dev:desktop

# Production
bun run build
bun run start

# Build a shareable macOS .dmg (arm64 by default)
bun run dist:desktop:dmg

# Or from any project directory after publishing:
npx t3

Scripts

  • bun run dev — Starts contracts, server, and web in turbo watch mode.
  • bun run dev:server — Starts just the WebSocket server (uses Bun TypeScript execution).
  • bun run dev:web — Starts just the Vite dev server for the web app.
  • bun run start — Runs the production server (serves built web app as static files).
  • bun run build — Builds contracts, web app, and server through Turbo.
  • bun run typecheck — Strict TypeScript checks for all packages.
  • bun run test — Runs workspace tests.
  • bun run dist:desktop:dmg — Builds a shareable macOS .dmg into ./release.
  • bun run dist:desktop:dmg:x64 — Builds an Intel macOS .dmg.

Desktop .dmg packaging notes

  • Default build is unsigned/not notarized for local sharing.
  • The DMG build uses assets/macos-icon-1024.png as the production app icon source.
  • Desktop production windows load the bundled UI from t3://app/index.html (not a 127.0.0.1 document URL).
  • Desktop packaging includes apps/server/dist (the t3 backend) and starts it on loopback with an auth token for WebSocket/API traffic.
  • Your tester can still open it on macOS by right-clicking the app and choosing Open on first launch.
  • To keep staging files for debugging package contents, run: bun run dist:desktop:dmg -- --keep-stage

Running multiple dev instances

Set T3CODE_DEV_INSTANCE to any value to deterministically shift all dev ports together.

  • Default ports: server 3773, web 5173
  • Shifted ports: base + offset (offset is hashed from T3CODE_DEV_INSTANCE)
  • Example: T3CODE_DEV_INSTANCE=branch-a bun run dev:desktop

If you want full control instead of hashing, set T3CODE_PORT_OFFSET to a numeric offset.

Runtime modes

T3 Code has a global runtime mode switch in the chat toolbar:

  • 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.

Sync engine migration modes

The server supports feature-flagged sync-engine modes while migrating from the legacy in-house state sync pipeline to LiveStore.

  • T3CODE_SYNC_ENGINE_MODE=livestore (default)

    • Uses the LiveStore-backed read path and disables delegate fallback (strict mirror-read mode).
    • Mirror state is pre-bootstrapped from persisted catch-up history during server startup.
  • T3CODE_SYNC_ENGINE_MODE=livestore-read-pilot

    • Uses the LiveStore mirror for state.bootstrap, state.catchUp, and state.listMessages reads when available.
    • Automatically falls back to legacy reads if the mirror is unavailable or errors.
  • T3CODE_SYNC_ENGINE_MODE=legacy

    • Uses the existing PersistenceService-backed state sync engine for reads and writes.
  • T3CODE_SYNC_ENGINE_MODE=shadow

    • Keeps legacy state as canonical, but mirrors committed state.event traffic into a LiveStore shadow store for parity validation.
  • T3CODE_LIVESTORE_ENFORCE_MODE=1

    • Disallows legacy and shadow sync modes at startup.
    • Intended for post-cutover environments to prevent accidental rollback to pre-LiveStore modes.

Optional diagnostics:

  • T3CODE_LIVESTORE_BOOTSTRAP_PARITY_CHECK=1
    • In livestore-read-pilot mode, compares LiveStore vs legacy state.bootstrap snapshots and logs drift diagnostics.
  • T3CODE_LIVESTORE_CATCHUP_PARITY_CHECK=1
    • In livestore-read-pilot mode, compares LiveStore vs legacy state.catchUp responses and logs drift diagnostics.
  • T3CODE_LIVESTORE_LIST_MESSAGES_PARITY_CHECK=1
    • In livestore-read-pilot mode, compares LiveStore vs legacy state.listMessages responses and logs drift diagnostics.
  • T3CODE_LIVESTORE_SHADOW_BOOTSTRAP_PARITY_CHECK=1
    • In shadow mode, compares mirror vs delegate state.bootstrap snapshots and logs drift diagnostics.
  • T3CODE_LIVESTORE_SHADOW_CATCHUP_PARITY_CHECK=1
    • In shadow mode, compares mirror vs delegate state.catchUp responses and logs drift diagnostics.
  • T3CODE_LIVESTORE_SHADOW_LIST_MESSAGES_PARITY_CHECK=1
    • In shadow mode, compares mirror vs delegate state.listMessages responses and logs drift diagnostics.
  • T3CODE_LIVESTORE_DISABLE_READ_FALLBACK=1
    • In livestore-read-pilot mode, disables delegate read fallback and fails requests when mirror reads fail (strict canary mode).
    • Read-source/fallback counters are emitted on shutdown via livestore read pilot metrics logs.

Web clients now always consume the server-authoritative api.state.* stream, and the server mode fully controls LiveStore vs fallback behavior.

Provider architecture

The web app communicates with the server via WebSocket using a simple JSON-RPC-style protocol:

  • Request/Response: { id, method, params } → { id, result } or { id, error }
  • Push events: { type: "push", channel, data } for streaming provider events

Methods mirror the NativeApi interface defined in @t3tools/contracts:

  • providers.startSession, providers.sendTurn, providers.interruptTurn
  • providers.respondToRequest, providers.stopSession, providers.listSessions
  • shell.openInEditor, server.getConfig

Codex is the only implemented provider. claudeCode is reserved in contracts/UI.

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.