# How to Contribute to pingdotgg/t3code: A Complete Developer Guide

> Learn how to contribute to pingdotgg/t3code. Set up your dev environment with Bun, fix bugs, improve performance, and submit PRs to this powerful codebase.

- Repository: [Ping.gg/t3code](https://github.com/pingdotgg/t3code)
- Tags: how-to-guide
- Published: 2026-04-18

---

**Contribute to pingdotgg/t3code by setting up a local development environment with Bun, making small focused bug fixes or performance improvements, and submitting PRs that pass the quality gates defined in [`AGENTS.md`](https://github.com/pingdotgg/t3code/blob/main/AGENTS.md).**

The **t3code** repository is a minimal web GUI that wraps a Codex/Claude app-server (JSON-RPC over stdio) in a Node.js WebSocket server and serves a React + Vite front-end. If you want to contribute to pingdotgg/t3code, you must understand its monorepo structure, runtime architecture, and strict contribution policy that only accepts small, focused improvements.

---

## Understanding the Repository Structure

The codebase is organized as a monorepo with distinct applications and shared packages. Knowing these paths is essential when navigating the source code to contribute to pingdotgg/t3code.

| Directory / File | Purpose |
|------------------|---------|
| `apps/server` | Node.js WebSocket server, provider orchestration, and background workers |
| `apps/web` | React + Vite UI and WebSocket client (`WsTransport`) |
| `packages/contracts` | Shared TypeScript contracts and schema definitions with no runtime logic |
| `packages/shared` | Runtime utilities including `DrainableWorker` and logging |
| [`.docs/architecture.md`](https://github.com/pingdotgg/t3code/blob/main/.docs/architecture.md) | Narrative documentation of end-to-end data flow |
| [`CONTRIBUTING.md`](https://github.com/pingdotgg/t3code/blob/main/CONTRIBUTING.md) | Official contribution policy limiting scope to small fixes |
| [`AGENTS.md`](https://github.com/pingdotgg/t3code/blob/main/AGENTS.md) | Quality gate requirements (`bun fmt`, `bun lint`, `bun typecheck`) |

---

## Core Architecture and Runtime Flow

To contribute to pingdotgg/t3code effectively, you must understand the runtime flow from browser to provider and back.

### Data Flow Sequence

1. **Browser → WebSocket** – The UI opens a WebSocket to `ws://localhost:3773` using `WsTransport` in [`apps/web/src/wsTransport.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/web/src/wsTransport.ts). Typed push events are decoded using contracts from [`packages/contracts/src/ws.ts`](https://github.com/pingdotgg/t3code/blob/main/packages/contracts/src/ws.ts).

2. **Server Acceptance** – The server accepts the socket, runs **startup barriers** (`ServerReadiness`), then publishes a `server.welcome` push via `ServerPushBus`.

3. **Provider Orchestration** – `ProviderServiceLive` in [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts) coordinates provider adapters (Codex, Claude) and persists session bindings. It publishes runtime events through a `PubSub` consumed by workers such as `ProviderRuntimeIngestion` and `CheckpointReactor`.

4. **Provider Runtime** – The system communicates with the `codex app-server` over JSON-RPC on stdio. The server converts provider events into **orchestration domain events** via `OrchestrationEngine` and pushes them back to the client.

### Key Module: ProviderServiceLive

Located in [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts), this is the core orchestrator for all provider actions.

| Feature | Implementation Details |
|---------|------------------------|
| **Session Startup** | `startSession` (lines 36-78) validates input, checks settings, starts a provider session, and persists the binding. |
| **Turn Handling** | `sendTurn` (lines 19-91) resolves the routable session, forwards the turn to the provider adapter, and records analytics. |
| **Event Streaming** | `streamEvents` getter (lines 93-95) creates a fresh `PubSub` subscription for each consumer. |
| **Graceful Shutdown** | `runStopAll` and finalizer (lines 40-78) stop all sessions on application teardown. |

---

## Development Workflow to Contribute to pingdotgg/t3code

Follow these steps to set up your environment and submit a contribution.

### 1. Fork and Clone

Fork the repository on GitHub, then clone your fork locally.

### 2. Install Development Tools

The project uses **mise** to manage Node ≥ 20, Bun, and other tools. If you have mise installed, run:

```bash
mise install

```

Otherwise, ensure you have **Bun** installed directly.

### 3. Install Dependencies

```bash
bun install .

```

### 4. Run the Application Locally

**Hot-reload (web + server):**

```bash
bun run dev

```

**Desktop-only development:**

```bash
bun run dev:desktop

```

### 5. Make Focused Changes

Contribute only small, focused bug fixes, reliability improvements, or performance tweaks. Examples include tightening a validation schema, improving a log message, or fixing a TypeScript type.

### 6. Run Quality Gates

All CI jobs require these commands to pass:

```bash
bun fmt
bun lint
bun typecheck

```

Run the test suite with Vitest:

```bash
bun run test

```

Tests live under `apps/**/__tests__`.

### 7. Submit a Pull Request

The repository automatically labels PRs with `vouch:*` and `size:*`. External contributors start with `vouch:unvouched` until a maintainer adds them to `.github/VOUCHED.td`.

Include a clear description of the fix, and add before/after screenshots for any UI changes as required by [`CONTRIBUTING.md`](https://github.com/pingdotgg/t3code/blob/main/CONTRIBUTING.md).

---

## Practical Code Examples for Contributors

These snippets demonstrate how to interact with the core modules when contributing to pingdotgg/t3code.

### Starting a Provider Session (Server-Side)

```ts
import { ProviderService } from "@t3tools/server";

// `threadId` is a UUID generated by the client.
// `rawInput` follows the `ProviderSessionStartInput` schema.
const session = await ProviderService.startSession(threadId, rawInput);
console.log("Provider session started:", session.provider, session.threadId);

```

*Reference*: `startSession` implementation (lines 35-78) in [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts).

### Sending a Turn from the UI (Client-Side)

```ts
import { wsTransport } from "./wsTransport";

await wsTransport.send({
  type: "provider.sendTurn",
  threadId: "c1a9…",
  input: "Explain the observer pattern",
  interactionMode: "text",
  // optional modelSelection, attachments, etc.
});

```

The transport serializes the request, and the server resolves the routable session and forwards it to the appropriate adapter via `ProviderService.sendTurn`. See the flow diagram in [`.docs/architecture.md`](https://github.com/pingdotgg/t3code/blob/main/.docs/architecture.md).

### Subscribing to Runtime Events (Any Component)

```ts
import { ProviderService } from "@t3tools/server";

const subscription = ProviderService.streamEvents.subscribe({
  next: (event) => console.log("Runtime event:", event.type, event.threadId),
  error: (err) => console.error(err),
});

```

Each call to `streamEvents` creates a fresh `PubSub` subscription, allowing independent consumers such as `ProviderRuntimeIngestion` and `CheckpointReactor`. See the getter at lines 93-95 in [`ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/ProviderService.ts).

---

## Key Files Every Contributor Should Know

| File | Purpose | Path |
|------|---------|------|
| **ProviderService.ts** | Core orchestrator for provider actions (start, turn, stop, list) | [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts) |
| **wsTransport.ts** | Client-side WebSocket abstraction; entry point for UI → server messages | [`apps/web/src/wsTransport.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/web/src/wsTransport.ts) |
| **ws.ts** | Typed contract definitions shared between server and client | [`packages/contracts/src/ws.ts`](https://github.com/pingdotgg/t3code/blob/main/packages/contracts/src/ws.ts) |
| **architecture.md** | End-to-end data flow documentation | [`.docs/architecture.md`](https://github.com/pingdotgg/t3code/blob/main/.docs/architecture.md) |
| **CONTRIBUTING.md** | Official contribution policy and guidelines | [`CONTRIBUTING.md`](https://github.com/pingdotgg/t3code/blob/main/CONTRIBUTING.md) |
| **AGENTS.md** | Quality gate requirements and automation rules | [`AGENTS.md`](https://github.com/pingdotgg/t3code/blob/main/AGENTS.md) |

---

## Summary

- **pingdotgg/t3code** is a minimal web GUI wrapping a Codex/Claude app-server in a Node.js WebSocket server with a React + Vite frontend.
- Contributions are limited to **small, focused bug fixes, reliability improvements, and performance tweaks** only.
- The core orchestration logic lives in [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts), specifically the `startSession`, `sendTurn`, and `streamEvents` methods.
- All contributions must pass quality gates defined in [`AGENTS.md`](https://github.com/pingdotgg/t3code/blob/main/AGENTS.md): `bun fmt`, `bun lint`, and `bun typecheck`.
- External contributors start with `vouch:unvouched` status until added to `.github/VOUCHED.td` by a maintainer.

---

## Frequently Asked Questions

### What types of contributions does pingdotgg/t3code accept?

The project only accepts small, focused bug fixes, reliability improvements, and performance optimizations. Large feature work or major architectural changes are unlikely to be merged. According to [`CONTRIBUTING.md`](https://github.com/pingdotgg/t3code/blob/main/CONTRIBUTING.md), you should keep changes under 200 lines and focused on a single logical fix.

### How do I set up the development environment for t3code?

First, fork and clone the repository. Install dependencies using `bun install .` (the project uses Bun as its package manager). You can optionally use **mise** to manage Node.js ≥ 20 and Bun versions via `mise install`. Run `bun run dev` to start both the WebSocket server and Vite UI with hot-reload.

### What are the quality gates I need to pass before submitting a PR?

All pull requests must pass the quality gates defined in [`AGENTS.md`](https://github.com/pingdotgg/t3code/blob/main/AGENTS.md). You must run `bun fmt` (formatting), `bun lint` (linting), and `bun typecheck` (TypeScript validation) locally before submitting. Additionally, run `bun run test` to execute the Vitest test suite. CI will block merges if any of these steps fail.

### Where is the main orchestration logic located in the codebase?

The core orchestration logic resides in [`apps/server/src/provider/Layers/ProviderService.ts`](https://github.com/pingdotgg/t3code/blob/main/apps/server/src/provider/Layers/ProviderService.ts). This file contains the `ProviderServiceLive` class with critical methods including `startSession` (lines 36-78), `sendTurn` (lines 19-91), and the `streamEvents` getter (lines 93-95). This service coordinates provider adapters, manages session lifecycle, and publishes runtime events to workers like `ProviderRuntimeIngestion` and `CheckpointReactor`.