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