Skip to main content
T3 Code runs as a Node.js WebSocket server that wraps codex app-server (JSON-RPC over stdio) and serves a React web application.

System Overview

The application follows a three-tier architecture:
┌─────────────────────────────────┐
│  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               │
└─────────────────────────────────┘
T3 Code is currently Codex-first. Support for additional providers like Claude Code is reserved in the contracts and UI layer.

Core Components

Browser Layer (React + Vite)

The web application manages:
  • Session UX and conversation rendering
  • Client-side state management
  • Real-time event streaming from server
  • WebSocket connection lifecycle
Location: apps/web

Server Layer (Node.js)

The Node.js server orchestrates:

WebSocket Server

Routes RPC methods and pushes domain events to connected clients

Provider Management

Manages provider sessions and dispatches commands through adapters

Event Store

Persists orchestration events and maintains read-model projections

Static Assets

Serves the compiled React application
Location: apps/server

Provider Layer (Codex App Server)

The provider layer handles:
  • Agent execution and tool calls
  • File system operations
  • Command execution approvals
  • Thread state management

Package Structure

T3 Code uses a monorepo structure with clear separation of concerns:
Wraps Codex app-server via JSON-RPC over stdio, serves the React web app, and manages provider sessions.Key Responsibilities:
  • WebSocket protocol handling
  • Provider session lifecycle
  • Event store and projections
  • Checkpoint management
Owns session UX, conversation/event rendering, and client-side state. Connects to server via WebSocket.Key Responsibilities:
  • Conversation UI rendering
  • Real-time event display
  • User input handling
  • Session state management
Effect/Schema contracts for provider events, WebSocket protocol, and model/session types. Schema-only — no runtime logic.Key Exports:
  • orchestration.ts - Event sourcing schemas
  • provider.ts - Provider session contracts
  • model.ts - Model configuration types
Shared runtime utilities consumed by both server and web. Uses explicit subpath exports (e.g., @t3tools/shared/git) — no barrel index.Key Utilities:
  • Git operations
  • Model normalization
  • Validation helpers

Communication Protocol

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

Request/Response Pattern

// Request
{ id: "123", method: "providers.startSession", params: {...} }

// Response
{ id: "123", result: {...} }

// Error
{ id: "123", error: {...} }

Push Events

{
  type: "push",
  channel: "orchestration.domainEvent",
  data: {...}
}
Provider runtime activity is projected into orchestration events server-side, then pushed to clients via orchestration.domainEvent channel.

Key Interfaces

The NativeApi interface defines available WebSocket methods:
// Provider Operations
providers.startSession
providers.sendTurn
providers.interruptTurn
providers.respondToRequest
providers.stopSession

// Shell Integration
shell.openInEditor

// Server Configuration
server.getConfig

Event Sourcing Architecture

T3 Code uses event sourcing for state management:
1

Command Dispatch

Client sends commands via orchestration.dispatchCommand
2

Event Generation

Commands generate immutable domain events stored in the event store
3

Projection Updates

Events update read-model projections (threads, messages, activities)
4

Client Notification

Events are pushed to clients via WebSocket on orchestration.domainEvent

Orchestration Methods

const ORCHESTRATION_WS_METHODS = {
  getSnapshot: "orchestration.getSnapshot",
  dispatchCommand: "orchestration.dispatchCommand",
  getTurnDiff: "orchestration.getTurnDiff",
  getFullThreadDiff: "orchestration.getFullThreadDiff",
  replayEvents: "orchestration.replayEvents",
};

Provider Architecture

The provider layer uses an adapter pattern for extensibility:
ProviderService

ProviderAdapterRegistry

CodexAdapterimplements ProviderAdapterShape

Provider Session Lifecycle

export class CodexAppServerManager extends EventEmitter {
  async startSession(input: CodexAppServerStartSessionInput) {
    // 1. Spawn codex app-server process
    const child = spawn(codexBinaryPath, ["app-server"], {...});
    
    // 2. Initialize JSON-RPC connection
    await this.sendRequest(context, "initialize", {...});
    
    // 3. Start or resume thread
    const response = await this.sendRequest(
      context,
      resumeThreadId ? "thread/resume" : "thread/start",
      {...}
    );
    
    // 4. Emit session ready event
    this.emitLifecycleEvent(context, "session/ready", ...);
    
    return session;
  }
}

Design Principles

Performance First

Optimized for low latency and high throughput

Reliability First

Predictable behavior under load and failures

Maintainability

Extract shared logic, avoid duplication

Correctness

Choose robustness over short-term convenience
Core Priority: When tradeoffs are required, always choose correctness and robustness over convenience. Keep behavior predictable during session restarts, reconnects, and partial streams.

Data Flow

The complete data flow through the system:

Next Steps

Sessions

Learn about session lifecycle and management

Runtime Modes

Understand approval policies and sandbox modes

Providers

Explore provider adapter architecture

Getting Started

Set up your development environment

Build docs developers (and LLMs) love