page:docs-specs-platform-gaps-research-t3code-architecture
Research dossier: t3code architecture and migratable surface reference
Date: 2026-09-27 · Author: research agent for the platform-gaps spec effort · Status: input to 10-t3code-migration.md
Research dossier: t3code architecture and migratable surface
Date: 2026-09-27 · Author: research agent for the platform-gaps spec effort · Status: input to 10-t3code-migration.md Snapshot investigated: C:/Users/tmusk/AppData/Local/Temp/claude/C--work-company/368e0399-fd11-4960-8b4d-b4dcf1d79c43/scratchpad/t3code (MIT, T3 Tools Inc., shallow clone 2026-09-27). All path:line citations below are relative to that snapshot root unless prefixed fabric:.
Method: direct reading of source, manifests, and docs/internals/; file/LOC counts via find+wc -l over *.ts,*.tsx,*.rs,*.js,*.mjs,*.swift,*.kt,*.c,*.h,*.zig excluding node_modules/dist/target. LOC figures include co-located *.test.ts files unless a "non-test" figure is given. Effect-TS depth = share of non-test source files importing from effect/*.
---
1. What t3code is
T3 Code self-describes as an "agent harness control surface" (README.md:3): a single Node WebSocket server that wraps provider CLIs/agents — Codex, Claude Code, Cursor, Grok, OpenCode, Antigravity — and serves web, desktop, and mobile clients (AGENTS.md:3). It is a bring-your-own-subscription product with ~200,000 users (AGENTS.md:9), MIT licensed, pnpm@11 monorepo, Node ^24.13.1, Effect-TS 4.0.0-rc.115 throughout (package.json, pnpm-workspace.yaml catalog).
Core execution model (AGENTS.md:145): clients send typed WebSocket requests → server turns them into **commands** → a pure **decider** produces persisted **events** → a **projector** derives the read model → provider CLIs run as subprocesses with per-provider **adapters** translating native protocols into orchestration events → side effects run in queue-backed **reactors** emitting **receipts** → every turn ends with a **checkpoint** (hidden git ref) for diff/restore. Events, projections, and command receipts commit in one SQLite transaction (docs/internals/overview.md:56-60).
The architectural boundary rule that matters most for fabric adoption: *"Complexity belongs at the adapter boundary. Orchestration stays pure, UI stays dumb"* (AGENTS.md, Taste section), and *"Anything crossing the wire is typed in packages/contracts"* (AGENTS.md, Hit-every-surface section).
2. Monorepo topology and size
| Unit | Files (src) | LOC (incl. tests) | Language | Effect depth (non-test files importing effect) |
|---|---|---|---|---|
apps/server | 863 | 398,627 | TS | 431/491 = 88% |
apps/web | 1,258 | 318,401 | TS/TSX (React 19) | 139/841 = 17% |
apps/desktop | 258 | 81,239 | TS (Electron 44) | 89/134 = 66% |
apps/mobile | 868 | 154,001 | TS/TSX + Swift/Kotlin (Expo 57/RN) | 125/602 = 21% |
apps/marketing | 10 | 514 | TS | n/a |
packages/contracts | 74 | 26,979 | TS (Effect Schema) | 47/48 = 98% |
packages/effect-acp | 18 | 15,546 (10,375 generated) | TS | 100% |
packages/effect-codex-app-server | 18 | 61,816 (58,004 generated) | TS | 100% |
packages/client-runtime | 256 | 65,846 | TS | 85/157 = 54% |
packages/shared | 154 | 29,241 | TS | 36/86 = 42% |
packages/ssh | 10 | 4,143 | TS | 5/5 = 100% |
packages/tailscale | 3 | 763 | TS | 1/2 |
infra/relay | 78 | 27,381 | TS (Cloudflare Worker) | 40/44 = 91% |
native/browser-secret | 2 | 105 | C (libsecret) | — |
native/hyprland-snap-shot | 6 | 1,823 | Rust | — |
native/kde-snap-shot | 7 | 1,251 | Rust | — |
native/libghostty-vt | 30 | 8,915 | C headers (vendored, pinned by native/libghostty-vt/VERSION) | — |
native/resource-monitor | 1 | 1,334 | Rust (sysinfo) | — |
packaging/ (aur) | 0 TS | shell/PKGBUILD | — | — |
scripts/ | 60 | 23,121 | TS | heavy (build scripts written in Effect) |
oxlint-plugin-t3code | 17 | 1,771 | JS | — |
Workspace globs: apps/*, infra/*, packages/*, scripts, oxlint-plugin-t3code (pnpm-workspace.yaml:1-6). Vendored read-only reference repos live under .repos/ (effect-smol, alchemy-effect) and are never imported (AGENTS.md, Where-code-lives section).
**Tooling stack (CONFIRMED):** pnpm 11 catalogs + overrides + 23 patched dependencies (pnpm-workspace.yaml, patchedDependencies), vite-plus ("vp") as the build/test/lint runner, TypeScript 7.0.2, @effect/tsgo compiler patching (package.json:6 "prepare"), knip for dead-code, oxlint with a custom plugin. Effect is a release candidate (effect@4.0.0-rc.115) *and locally patched* (patches/effect@4.0.0-rc.115.patch) — a fork-tracking liability the spec must own.
3. apps/server — the environment
Entry: apps/server/src/bin.ts — an effect/unstable/cli Command tree (bin.ts:1-30) with subcommands: auth, app, connect, pair, project, serve/start/run-server, service (+ launcher, preflight), uninstall, update, claude-history, ssh-helper, theme, trace, triage (bin.ts:10-29). The server is simultaneously the product CLI (t3).
Subsystem sizes (non-test files / non-test LOC, from apps/server/src/*/):
| Subsystem | Files | LOC | Role |
|---|---|---|---|
provider/ | 109 | 49,072 | drivers, adapters, ACP runtimes, installers, auth flows, model catalogs |
orchestration/ | 38 | 20,360 | engine, decider, projector, reactors |
pullRequest/ | 26 | 19,751 | PR providers: GitHub, Bitbucket, Azure DevOps, Forgejo (pullRequest/ listing) |
sourceControl/ | 25 | 7,954 | repo/branch discovery, git actions |
persistence/ | 84 | 7,602 | SQLite event store, projections, receipts, migrations |
vcs/ | 8 | 6,540 | VCS driver registry (checkpoint capability lives here) |
cloud/ | 18 | 5,764 | T3 Connect client side: relay auth, managed cloudflared tunnels, self-update |
cli/ | 20 | 5,681 | the t3 CLI commands |
auth/ | 11 | 4,258 | environment auth: DPoP, pairing grants, sessions, scopes |
device/ | 12 | 4,150 | iOS simulator / Android emulator control |
usage/ | 11 | 3,894 | provider usage/quota ingestion |
project/ | 10 | 3,939 | project registry |
resourceTelemetry/ | 8 | 3,628 | host/process resource history (feeds from native resource-monitor) |
terminal/ | 4 | 3,453 | thread terminals over node-pty |
git/ | 4 | 3,417 | git command execution |
textGeneration/ | 13 | 3,090 | provider-backed helper generations (titles etc.) |
mcp/ | 11 | 3,057 | T3's own MCP server injected into provider sessions |
| others | — | — | workspace search (@ff-labs/fff-node native finder, workspace/WorkspaceSearchIndex.ts:13), preview, assets, checkpointing (620 LOC), diagnostics, observability, keybindings, desktopUpdate, relay glue |
External runtime deps (apps/server/package.json): @anthropic-ai/claude-agent-sdk ^0.3.276, @opencode-ai/sdk ^1.3.15, @effect/platform-node, @ff-labs/fff-node (native file finder), @napi-rs/keyring (OS credential store), node-pty, stream-json, yauzl, diff, yaml. No web framework — HTTP + WS are Effect platform (src/http.ts, src/ws.ts).
3.1 Orchestration (event-sourced core)
- Engine serializes commands; decider is pure; events+projections+command-receipt commit in one DB transaction; reactors do side effects afterwards and feed results back as commands (
docs/internals/overview.md:56-72,orchestration/Layers/OrchestrationEngine.ts,orchestration/decider.ts,orchestration/projector.ts). - Reactors present:
PullRequestSyncReactor.ts,ThreadPullRequestReactor.ts,ThreadSettlementReactor.ts, plusThreadLiveEventCoalescer.ts,LiveStreamBudget.ts(bandwidth discipline for WS),Normalizer.ts(provider event normalization into canonical activities). - Test-only
RuntimeReceiptBus(production layer is a no-op) lets tests wait on async milestones instead of sleeping (docs/internals/overview.md:100-104);packages/shared/src/DrainableWorker.tsis the drain-wait primitive. - Replay constraint: persisted events must remain decodable forever; schema changes affect replay at startup, not just live traffic (
docs/internals/overview.md:70-72).
3.2 Persistence
SQLite via a **port of @effect/sql-sqlite-node onto the built-in node:sqlite** (no better-sqlite3, no native addon) — packages/shared/src/nodeSqliteClient.ts:1-7, used by apps/server/src/persistence/Layers/Sqlite.ts:6,37. Layers: OrchestrationEventStore, OrchestrationCommandReceipts, per-view Projection* tables (threads, messages, activities, turns, sessions, projects, repositories, pending approvals, proposed plans), Migrations/ with a migration runner. State lives under T3 home (~/.t3/userdata/state.sqlite, AGENTS.md, Test-data section).
3.3 Auth (environment side)
auth/ implements token+session auth for a personally-owned server: DPoP proofs (auth/dpop.ts), pairing grants/one-time tokens (auth/PairingGrantStore.ts), auth sessions persisted in SQLite (persistence/AuthSessions.ts:1-30, record includes scopes, proof-key thumbprint, expiry/consumed/revoked timestamps; persistence/AuthPairingLinks.ts:19-31), per-method scopes (startup URL carries admin scopes, pair tokens standard scopes — AGENTS.md, Dev-servers section), RPC-level authorization separate from socket authentication (auth/RpcAuthorization.ts; "Authentication of a socket does not authorize every method on it", docs/internals/overview.md:20-22). Secrets in auth/ServerSecretStore.ts + @napi-rs/keyring.
3.4 Checkpointing
checkpointing/CheckpointStore.ts:1-15: repository interface for filesystem-backed workspace checkpoints as **hidden Git refs**; capture/restore/diff delegate to the active VCS driver's optional checkpoint capability (vcs/VcsDriver.ts via VcsDriverRegistry). Checkpoints never add commits to the user's branch (docs/internals/overview.md:79-83). Revert must coordinate workspace state with provider conversation rollback; providers that cannot roll back conversation (Antigravity) reject revert before touching files (docs/internals/providers.md, Protocol-traps section).
3.5 Claude history workers
Claude session history/fork runs in a **separate child process** so the Claude Agent SDK sees the provider's environment without mutating the server's: claudeHistoryWorker.ts:1-11 (calls getSessionMessages/forkSession from @anthropic-ai/claude-agent-sdk), standalone npm entry claude-history-worker.ts:1-4, and a __claude-history subcommand inside the single-executable (cli/claudeHistory.ts).
3.6 Cloud (T3 Connect client side)
cloud/ holds the environment's side of the hosted-relay story: relay-signed bootstrap credential exchange handlers (cloud/http.ts; trust analysis in docs/internals/t3-connect.md:11-33), managed tunnel runtime spawning **cloudflared** (cloud/ManagedEndpointRuntime.ts:77 parses cloudflared zerolog output), tunnel startup reconciliation (cloud/managedTunnelStartup.ts), CLI token management (cloud/CliTokenManager.ts), and server self-update (cloud/selfUpdate.ts). Tunnel lifetime rules (release-on-shutdown vs retain across update handoffs) are documented at docs/internals/t3-connect.md:41-56.
3.7 Terminal
terminal/Manager.ts:1-8 owns terminal lifecycle/fanout per thread; terminal/NodePtyAdapter.ts is the PTY boundary (node-pty is one of only three allowed native build scripts, pnpm-workspace.yaml allowBuilds). Client rendering is **libghostty-vt compiled to wasm32** driven from the web app (apps/web/src/terminal/ghostty/core.ts:13-15 "wasm32 C ABI layout … at the libghostty-vt revision pinned alongside this module"; header pin native/libghostty-vt/VERSION).
4. Harness integration matrix (the part D6 cares about)
Registry: provider/builtInDrivers.ts:49-56 — BUILT_IN_DRIVERS = [Codex, Claude, Cursor, Grok, OpenCode, Antigravity]. Driver = integration kind; instance = one configured account; adapters are per-driver Layers/*Adapter.ts implementing the shared Services/ProviderAdapter.ts contract and emitting canonical ProviderRuntimeEvents from @t3tools/contracts.
| Harness | Mechanism | Transport | Key files | Notes |
|---|---|---|---|---|
| **Claude Code** | **Bespoke: @anthropic-ai/claude-agent-sdk** in-process query() sessions | SDK (spawns the user's own claude executable; bundled SDK binaries are stripped via pnpm overrides, pnpm-workspace.yaml overrides block) | provider/Layers/ClaudeAdapter.ts:5,14-27; Drivers/ClaudeDriver.ts, ClaudeExecutable.ts, ClaudeHome.ts, ClaudeSkills.ts; history in child worker (claudeHistoryWorker.ts:1-11) | Permission callbacks via SDK CanUseTool; usage limits from SDKRateLimitInfo (Layers/claudeUsageLimits.ts) |
| **Codex** | **Bespoke: Codex "app server" JSON-RPC** over child-process stdio, typed by the in-repo effect-codex-app-server package | codex app-server subprocess (provider/Layers/codexLaunchArgs.ts:13) | provider/Layers/CodexAdapter.ts:45-46, CodexSessionRuntime.ts; schema packages/effect-codex-app-server/src/_generated/schema.gen.ts (56,820 LOC generated) | Async questions arrive as notifications answered by a new user message; blocking ones use request/response (docs/internals/providers.md, Protocol-traps) |
| **Cursor** | **ACP** | cursor-agent [permission args] acp subprocess (provider/acp/CursorAcpSupport.ts:56-60) | provider/Layers/CursorAdapter.ts:2 ("Cursor CLI (agent acp) via ACP"); ACP extensions provider/acp/CursorAcpExtension.ts | Cursor updates only via its own CLI updater (docs/internals/providers.md, updates section) |
| **Grok Build** | **ACP** | grok --permission-mode <mode> agent stdio subprocess (provider/acp/GrokAcpSupport.ts:33-41,55-56) | provider/Layers/GrokAdapter.ts:38-39; xAI extensions provider/acp/XAiAcpExtension.ts, XAiBackgroundTasks.ts | Probes avoid auth/session side effects (docs/internals/providers.md, setup section) |
| **OpenCode** | **Bespoke: OpenCode HTTP server** via @opencode-ai/sdk/v2 client | one T3-managed opencode server **per thread** (or an external server) | provider/Layers/OpenCodeAdapter.ts:32; provider/OpenCodeServerOwner.ts (shared instance-owned helper for catalog/text-gen); provider/opencodeRuntime.ts | Per-directory MCP registration vs thread-scoped connection forces server-per-thread (docs/internals/providers.md:14-22) |
| **Antigravity** | **ACP** against a T3-downloaded Google Antigravity release (no user-installed CLI) | downloaded executable+harness spawned as ACP agent; identity verified as agentInfo.name === "antigravity-acp", protocolVersion === 1 (provider/AntigravityInstallation.ts:484-502) | spawn builder provider/antigravityAuthSupport.ts:434; installer with immutable releases + version leases (provider/AntigravityInstallation.ts); OAuth loopback-callback forwarding (provider/AntigravityAuth.ts); per-instance profile isolation (provider/antigravityAuthSupport.ts) | Can checkpoint workspace but cannot roll back conversation → revert rejected (docs/internals/providers.md, capabilities) |
Shared ACP machinery on the server side: provider/acp/AcpSessionRuntime.ts, AcpAdapterSupport.ts, AcpCoreRuntimeEvents.ts, AcpRuntimeModel.ts, AcpStderr.ts — one generic ACP runtime with per-provider support modules (Cursor/Grok/Antigravity) layered on. This is the concrete precedent for D6 ("ACP becomes fabric's canonical harness protocol with per-harness extension modules").
Cross-cutting provider services: ProviderService (turn dispatch, attachment paths in turn input — docs/internals/providers.md, Attachments), ProviderInstanceRegistry (multi-account), ProviderSessionDirectory/ProviderSessionReaper, ProviderAuthService + per-provider auth flows, providerMaintenance.ts (updater-ownership proofs for one-click provider updates), ModelManifest.ts + model-manifest.json (model classification), RuntimeInstructions.ts (per-provider runtime prompt injection), mcp/McpProviderSession.ts (T3 injects its own MCP endpoint+bearer into each provider session for preview/device toolkits — mcp/McpProviderSession.ts:1-12).
5. packages/contracts — full module inventory (48 non-test modules, 26,979 LOC incl. tests)
Everything crossing the wire. 47/48 modules import Effect Schema; index at src/index.ts re-exports the core. Inventory (module — LOC — interface it defines):
| Module | LOC | Defines |
|---|---|---|
rpc.ts | 1,539 | **The client↔server WS RPC contract**: WS_METHODS map (rpc.ts:277), 144 Rpc.make definitions, aggregated WsRpcGroup (rpc.ts:1394). Groups: projects, shell, filesystem, agent-session import, assets/attachments, provider auth/install/update, server settings/config/probe, diagnostics, resource telemetry, usage, cloud relay client, background policy, pull requests (list/stats/routing/stack/detail/activity/comments/diff-contents/files-viewed) |
orchestration.ts | 2,441 | Orchestration domain: ORCHESTRATION_WS_METHODS (dispatchCommand, getWorkflowScript, getTurnDiff, getFullThreadDiff, searchThreads, getArchivedShellSnapshot, subscribeShell, subscribeThread — orchestration.ts:35-44), OrchestrationCommand/events, ModelSelection (+ legacy wire transform, orchestration.ts:60-74), approval policies, sandbox modes |
providerRuntime.ts | 1,234 | Canonical provider runtime event surface: ProviderRuntimeEvent, turn token usage, canonical item/request types, task/tool activity models |
provider.ts / providerInstance.ts / providerSetup.ts / providerUsageLimits.ts | 162/149/180/167 | Driver kinds, per-instance settings (ClaudeSettings, CodexSettings, …), auth/install state machines (ProviderAuthState, ProviderInstallState), rolling quota windows |
ipc.ts | 1,388 | Desktop renderer↔main Electron IPC surface |
settings.ts | 1,658 | Server/client settings schema (fonts, themes, providers, usage-limit sources) |
pullRequest.ts | 1,409 | PR domain: states, snapshots, stacks, multi-link protocol + linkedPullRequest legacy field |
relay.ts / relayClient.ts / remoteAccess.ts | 1,194/63/68 | T3 Connect relay protocol (managed endpoint runtime config, signing), relay client status, remote access modes |
environment.ts / environmentHttp.ts | 232/623 | Environment descriptor + capability flags (ORCHESTRATION_PROTOCOL_VERSION, environment.ts:1-3); HttpApi groups for the environment's HTTP endpoints (environmentHttp.ts:1-5) |
auth.ts / baseSchemas.ts | 355/195 | Auth posture labels, scopes, DPoP failure categories, shared branded primitives |
server.ts | 891 | Server config/probe/update surface, skills dispatch |
terminal.ts | 381 | Terminal open/attach/restart events, term-N ids |
composerContext.ts / composerContextClipboard.ts | 281/27 | Typed composer chips: context records keyed by contextId, reference links t3-context://v1/<kind>/<id>, attachment bindings |
git.ts / vcs.ts / sourceControl.ts / worktreeSetup.ts / projectClone.ts | 464/287/188/125/122 | Git action progress, VCS errors incl. checkpoint refs, branch/PR discovery, worktree/clone live progress |
project.ts / t3ProjectFile.ts | 307/143 | Project records; t3.json project file (schema URL t3ProjectFile.ts:1-2) |
device.ts | 583 | First-class iOS Simulator / Android Emulator control schemas |
preview.ts / previewAutomation.ts / browserProfile.ts / browserImport.ts | 354/953/99/165 | In-app browser preview surface, automation ops, named browser identities, cookie import from installed browsers |
assets.ts / filesystem.ts | 320/67 | Signed asset URLs, filesystem browse |
keybindings.ts / editor.ts / desktopAppActivation.ts / desktopBootstrap.ts | 211/232/53/31 | Keybinding rules (forward-compatible with unknown commands), editor deep links incl. VS Code remote, desktop activation/update handoff markers |
model.ts | 225 | Model/provider option selections (+ legacy on-disk decoding) |
usage.ts / usageLimitSourceId.ts | 223/9 | Usage reporting contract |
resourceTelemetry.ts | 522 | Host/process resource snapshots and history |
agentSessions.ts | 116 | Import of external sessions (claudeAgent, codex sources — agentSessions.ts:1-2) |
review.ts / assistantCitations.ts / background.ts | 70/31/110 | Review diff stats, quoted assistant citations (UTF-16 offsets), background/power policy |
rpc transport note | — | Runtime is effect/unstable/rpc (Rpc/RpcGroup, rpc.ts:1-3); serialization/session handled by client-runtime + server ws.ts |
Versioning/compat doctrine baked into contracts: clients and environments upgrade independently; capability flags on the environment descriptor (e.g. threadPullRequests vs threadPullRequestLinking) gate client behavior; legacy wire fields are kept and absorbed by schema transforms, never by runtime compat code (docs/internals/overview.md:24-44, orchestration.ts:66-74).
**Fabric equivalent replaced:** the wire types implicit in kradle core/sdk and the adapters event model; this package is the single strongest candidate for tracked-fork adoption per D9.
6. packages/effect-acp — ACP protocol implementation
Structure (packages/effect-acp/src/): _generated/schema.gen.ts (10,375 LOC, generated from the ACP schema via @effect/openapi-generator; regenerate with scripts/generate.ts — package.json "generate"), meta.gen.ts (method-name constants), rpc.ts (22 Rpc.make definitions over AGENT_METHODS/CLIENT_METHODS: initialize, authenticate, logout, session/new, session/load, session/list… — rpc.ts:8-40), protocol.ts (632 LOC; the JSON-RPC stdio protocol layer producing both an RpcClient protocol and an RpcServer protocol from one child stdio, with typed incoming notifications, ext-method escape hatches, session-update transforms — protocol.ts:23-80), client.ts (614 LOC; AcpClient Context.Service spawning agent childs — client.ts:49), agent.ts (538 LOC; AcpAgent service for *being* an ACP agent — agent.ts:31, used by apps/server/scripts/acp-mock-agent.ts for tests), errors.ts, terminal.ts (ACP terminal handle: output/waitForExit/kill/release with spec links — terminal.ts:6-25), exports as five subpaths (client/agent/schema/protocol/errors — package.json exports).
Sole runtime dependency: effect (packages/effect-acp/package.json). Highly portable; the Effect-4 unstable/rpc runtime is the only coupling.
**Fabric equivalent replaced:** the protocol layer that D6 mandates as canonical for adapters. Includes both directions (client for driving harnesses, agent for exposing fabric itself as an ACP agent).
7. packages/effect-codex-app-server — Codex protocol twin
Same generator pattern as effect-acp: _generated/schema.gen.ts 56,820 LOC + meta.gen.ts 889 + namespaces.gen.ts 295; handwritten client.ts (262 LOC, spawns codex app-server childs), protocol.ts (485 LOC), rpc.ts is purely re-exported generated meta (rpc.ts:1). Probe example at test/examples/codex-app-server-probe.ts. Only dep: effect.
**Fabric equivalent replaced:** fabric's Codex adapter transport (currently hooks/CLI-based in fabric:packages/adapters/hooks/adapter-codex).
8. packages/client-runtime — shared client brain (web+desktop+mobile)
256 files / 65,846 LOC; 54% Effect. Subpath-exported modules (no barrel): connection/ (supervisor = single transport-retry owner with backoff/wakeups, connection/supervisor.ts; registry scoping connections per environment, connection/registry.ts; catalog, credential store, compatibility negotiation, onboarding), rpc/ (client, session — session waits for initial server config before ready, rpc/session.ts; http auth), authorization/ (HTTP credential refresh decoupled from socket lifetime, authorization/service.ts), state/ (~30 shared state services: threads, orchestration, entities, git, models, filesystem, attachments, checkpointDiff, connections, device …, built on @effect/atom-react atoms), relay/, device/, environment/, operations/, platform/ (platform service interfaces the shells implement), voice-input/, work-log/, plus provider-flavored helpers (codexArtifactTemplates, codexFileCitations, providerSkills). Design rationale: one connection owner prevents divergent reconnect loops across surfaces (docs/internals/connection-runtime.md:1-27).
**Fabric equivalent replaced:** the client/data layer of kradle/web and the retired genty UI runtime (per D2c).
9. packages/shared — cross-runtime utilities
154 files / 29,241 LOC, subpath exports, no barrel (AGENTS.md, Where-code-lives). Notable: nodeSqliteClient.ts (the node:sqlite Effect SQL client, §3.2), DrainableWorker.ts, relaySigning/relayClient (T3 Connect crypto), hostProcess, cliRelease (release download URLs shared by installer/ssh bootstrap), legacyCliLauncher, model/usage-limit helpers, composer-context reference machinery shared by clients and server.
10. packages/ssh and packages/tailscale — remote access primitives
ssh(10 files / 4,143 LOC, 100% Effect): auth, command execution, config, tunnels. Can bootstrap a T3 server on a remote host (downloads viacliReleasebase URL —ssh/src/tunnel.ts:9) and port-forward to it; desktop main owns the lifecycle, renderer consumes the forwarded endpoint (docs/internals/remote.md:47-50). Cleanup stops a remote server only if it started it (ssh/src/tunnel.tsdoc,remote.md:50).tailscale(763 LOC): wraps the user'stailscaleexecutable (status,serve) with schema-validated, secret-scrubbing error taxonomy (tailscale/src/tailscale.ts:10-31). Tailscale is "an endpoint for ordinary pairing", not a separate environment type (docs/internals/remote.md:43-45).
**Fabric equivalent replaced:** the remote-access stack demanded by D2d/D12; fabric currently has no equivalent.
11. apps/web, apps/desktop — the control surfaces
**apps/web** (1,258 files / 318,401 LOC): React 19 + Vite(-plus) + TanStack Router (file routes at apps/web/src/routes/, e.g. routes/projects.$projectKey.tsx, routes/connect.tsx, routes/pair.tsx), Tailwind 4, tiptap composer, zustand for local UI state, @effect/atom-react bridging client-runtime atoms, @pierre/diffs for diff rendering, react-markdown pipeline, Clerk only for the hosted/cloud tier. ~135 top-level components + feature dirs (chat, settings ~140 files, terminal, cloud, device, onboarding). Terminal emulation via libghostty-vt wasm (src/terminal/ghostty/{core,renderer,runtime,surface}.ts). Two deployments: hosted app.t3.codes and the server-served local client; dev is single-origin with Vite proxying /api, /ws, /oauth (AGENTS.md, Three-ways-to-hurt-yourself #3). Hosted web stores the connection catalog in the browser and connects directly to each environment — it is a pure client, no server-side proxy (docs/internals/remote.md:28-38; pairing-URL secret-in-fragment design apps/web/src/hostedPairing.ts, remote.md:33-38).
**apps/desktop** (258 files / 81,239 LOC): Electron 44 wrapping the web renderer, plus: src/backend/ — a **DesktopBackendManager/Pool** that spawns/bundles the server so the desktop app is also a host environment (src/backend/DesktopBackendManager.ts, DesktopBackendPool.ts, DesktopServerExposure.ts, tailscaleEndpointProvider.ts); src/electron/ service wrappers (window, updater via electron-updater, safe storage, protocol, power monitor, Win32 foreground via lazily-loaded ffi-rs — docs/internals/overview.md:118-124); src/snapShot/ screen-capture across OSes (macOS via osascript, Linux via the native hyprland/kde helpers + GNOME extension apps/desktop/gnome-extension, a11y via @crowecawcaw/xa11y in forked children only); src/ssh/, src/wsl/, src/preview/ (playwright-core-driven in-app browser), IPC typed by contracts/ipc.ts (1,388 LOC). Linux desktop-identity/portal ordering constraints documented at docs/internals/overview.md:106-116.
**apps/mobile** (structural notes only, deferred per D13): Expo 57 / React Native (apps/mobile/package.json:7 expo start), EAS build profiles (eas.json), native modules under apps/mobile/modules incl. Swift/Kotlin (868 files, 154,001 LOC incl. native), src/{components,connection,features,lib}, uniwind theming, Clerk Expo for T3 Connect, patched RN ecosystem (19 of the 23 pnpm patches are mobile-related — pnpm-workspace.yaml patchedDependencies). It consumes the same contracts + client-runtime connection stack.
12. infra/relay — T3 Connect (hosted remote access)
78 files / 27,381 LOC, 91% Effect. A **Cloudflare Worker** (src/worker.ts, @cloudflare/workers-types) deployed with **alchemy** (infra/relay/package.json "deploy": alchemy deploy), Postgres via @effect/sql-pg + drizzle, Clerk backend for cloud identity, @noble/curves/@noble/hashes for the signing protocol. Modules: environments/ (EnvironmentConnector, EnvironmentLinker/Links, EnvironmentCredentials, EnvironmentPublishSignatures, ManagedEndpointAllocations/Provider/Reaper, ManagedTunnelLimits), auth/, http/Api.ts, agentActivity/, persistence/, queues.ts, push-notification smoke scripts for mobile.
Trust model (CONFIRMED, docs/internals/t3-connect.md:11-33): the relay is a broker that asks the environment to mint a one-time bootstrap credential bound to the client's DPoP key; the client redeems it directly with the environment; the relay never sees session tokens; both directions verify signatures; managed tunnels (cloudflared) expose only a validated loopback origin; after bootstrap the relay does not proxy application traffic (t3-connect.md:3-6).
**Fabric equivalent replaced:** the hosted-remote-access story D12 mandates; fabric has none today.
13. native/*
| Component | What | Used by |
|---|---|---|
browser-secret (105 LOC C) | reads Chromium's libsecret cookie key for browser cookie import; exit codes consumed by ChromiumKeys.ts (native/browser-secret/main.c:1-12) | desktop preview/browser-import |
hyprland-snap-shot (1,823 LOC Rust) | Wayland/Hyprland screen capture helper (wlr protocols in protocols/) | desktop snapshot |
kde-snap-shot (1,251 LOC Rust) | KDE screen capture helper (dbus) | desktop snapshot |
libghostty-vt (8,915 LOC C headers, revision-pinned) | vendored ghostty VT API headers; wasm build renders terminals in web | web terminal (apps/web/src/terminal/ghostty/core.ts:13-15) |
resource-monitor (1,334 LOC Rust, sysinfo, stdin/stdout protocol v3 — native/resource-monitor/src/main.rs:11) | host/process CPU/memory sampling with 1h history | server resourceTelemetry/, shipped in every CLI archive (scripts/build-cli-archive.ts:2-15) |
Portability note (CONFIRMED): the Electron main startup path loads **no** native modules; native capability runs in deadline-bounded children (docs/internals/overview.md:118-124). The server's own native surface is limited to node-pty, @napi-rs/keyring, fff-node (dlopen'd, kept external to the bundle — workspace/WorkspaceSearchIndex.ts:30), and msgpackr-extract.
14. Packaging, install, and release machinery
- **Single executable**:
apps/server/scripts/cli.ts build-exebuilds the server as a **Node single-executable application** (needs Node 25.7+--build-sea; native packages still resolved from a siblingnode_modulestree —apps/server/scripts/cli.ts:160). Bundle viavp pack(apps/server/package.json"build:bundle"). - **CLI archive**:
scripts/build-cli-archive.ts:2-15— per-platform archive =t3binary + web client + resource-monitor + production node_modules of the externals (node-pty, msgpackr-extract, fff); "nothing in it may require Node, npm, or a compiler". - **npm distribution**:
scripts/build-npm-platform-packages.ts:3-9—@t3code/t3-<platformKey>per-platform packages holding archive bytes verbatim + at3launcher package with optionalDependencies →npx t3/npm i -g t3. - **Shell installers**:
scripts/install.sh:2-24(POSIX sh, sha256-verified GitHub release download into$T3CODE_HOME/runtime/versions/<version>, channels stable/nightly/preview, same layout the background service uses) andscripts/install.ps1. - **Service + self-update**:
t3 service install,t3 update(README.md:40-41); server-side update logic incloud/selfUpdate.ts,desktopUpdate/,serviceLauncher.ts; update manifests merged byscripts/merge-update-manifests.ts, mock update server for dev (scripts/mock-update-server.ts). - **Desktop artifacts**:
scripts/build-desktop-artifact.ts→ electron-builder dmg/NSIS/AppImage per arch (rootpackage.jsondist:desktop:* scripts); macOS signingscripts/sign-macos.ts; winget (winget install T3Tools.T3Code) and Homebrew cask (README.md:52-62); AURt3code-bin/t3code-nightly-binrepackage the AppImage, published by.github/workflows/publish-aur.yml(packaging/aur/README.md:1-12). - **CI/CD**: 18 workflows (
.github/workflows/);release.ymljobs preflight → quality → test → release → finalize (release.yml:98,230,264,753,1121) with scheduled nightlies;release-desktop.yml,deploy-relay.yml, mobile EAS preview/production,windows-tests.yml,web-preview.yml; release smoke testscripts/release-smoke.ts; Discord release notifier. - **Licensing hygiene**:
third-party-licenses.config.json+scripts/sync-third-party-license-notices.ts— directly reusable for D15's attribution work items.
15. Effect-TS depth and portability assessment
- **Deep-Effect zones** (adopting means adopting Effect 4 rc): server (88%), contracts (98%, Effect Schema is the contract language), effect-acp/effect-codex-app-server (100%, built on
effect/unstable/rpc), ssh (100%), relay (91%). These use unstable namespaces heavily:effect/unstable/rpc,effect/unstable/sql,effect/unstable/process(ChildProcessSpawner),effect/unstable/cli,effect/unstable/http— pinned to4.0.0-rc.115**with a local patch** (patches/effect@4.0.0-rc.115.patch) and a patched@effect/vitest. - **Shallow-Effect zones** (Effect quarantined behind services): web UI (17% — Effect lives in the atom/data layer, components are plain React), mobile (21%), shared (42% — many pure-TS utility modules), client-runtime (54%).
- **Effect-free zones**: native/* (C/Rust), oxlint plugin, AUR packaging, install.sh/ps1.
- Portability risks (CONFIRMED): Node
^24.13.1engine (server accepts^22.16 || ^23.11 || >=24.10,apps/server/package.jsonengines);node:sqlitedependency (Node 22.5+); SEA build requires Node 25.7+ host; TypeScript 7 + tsgo patching; vite-plus (vp) is a Voidzero-private toolchain (vite: npm:@voidzero-dev/vite-plus-core) — fabric would either adopt vite-plus or re-platform builds; pnpm-only workspace mechanics (catalogs, patchedDependencies) vs fabric's npm workspaces (fabric:package.jsonuses npm + package-lock.json).
16. Mapping to fabric equivalents (per D2)
| t3code unit | Replaces in fabric | Notes |
|---|---|---|
packages/effect-acp (+ server provider/acp/*) | fabric:packages/adapters transport core | D6: ACP canonical; per-harness ext modules mirror t3code's Cursor/XAi/Antigravity support files |
apps/server/src/provider/* (drivers/adapters/instances/installers/auth) | fabric:packages/adapters/hooks/adapter-{claude,codex,cursor,opencode,antigravity,…} | fabric's hook adapters observe harnesses; t3code's adapters *drive* them — a strictly larger capability |
packages/contracts | the implicit interfaces of fabric:packages/kradle/{core,sdk} and adapters event types | tracked fork per D9; contracts' capability-flag versioning doctrine should come with it |
apps/server orchestration/persistence/auth/checkpointing/terminal | fabric:packages/kradle/core + parts of babysitter run-state handling | event-sourced core with SQLite receipts is the piece fabric's control surface lacks |
packages/client-runtime + apps/web | fabric:packages/kradle/web, fabric:packages/observer-dashboard, retired genty UI shells (D2c) | |
apps/desktop | no fabric equivalent (new surface) | bundles a host server — relevant to single-node packaging (D3) |
packages/ssh, packages/tailscale, apps/server/src/cloud, infra/relay | no fabric equivalent — fills D12 hosted remote access | relay requires Cloudflare+Postgres+Clerk operational stack |
| install/release machinery (§14) | fabric packaging gap (D3 all three forms) | curl\ |
apps/mobile | deferred (D13) | consumes same contracts/client-runtime; no fabric work implied now |
17. CONFIRMED vs INFERRED
**CONFIRMED** (read directly in source/docs, cited above): the six-harness set and each integration mechanism (§4); the event-sourced command/decider/projector/reactor model and its single-transaction commit; SQLite over node:sqlite; hidden-git-ref checkpoints; DPoP/pairing environment auth; relay-as-broker trust model with cloudflared managed tunnels; contracts as the sole wire boundary with 144+8 WS RPC methods; generated ACP (10.4k LOC) and Codex app-server (56.8k LOC) schemas; all size/LOC/Effect-depth figures (measured); packaging pipeline end to end; Effect 4.0.0-rc.115 pinned and locally patched; MIT license (LICENSE).
**INFERRED** (reasonable but not verified end-to-end in this pass):
- The libghostty-vt **wasm artifact build/packaging step** was not located in this pass; only the vendored headers, the pinned revision, and the web consumer were read. (The renderer's existence is confirmed; the build provenance of the
.wasmis not.) - Effect-depth percentages use "imports
effect" as a proxy; a file can import one Effect utility yet be architecturally plain TS. Treat the zone classification (§15) as directional. - The claim that the desktop renderer reuses the web app wholesale is based on
AGENTS.md:3/dependency wiring (@t3tools/webnot a desktop dep; desktop wraps built web assets); the exact asset-embedding path was not traced. - Mobile figures include generated/native scaffolding; the hand-written TS share is smaller than 154k LOC suggests.
packages/effect-codex-app-servergeneration source is presumed to be the Codex app-server JSON schema via@effect/openapi-generator(devDep +scripts/generate.tsnaming); the upstream schema URL was not read.
18. Spec inputs
Concrete facts the spec author must use verbatim:
1. **Harness matrix**: Cursor (cursor-agent … acp, provider/acp/CursorAcpSupport.ts:56-60), Grok (grok --permission-mode <m> agent stdio, provider/acp/GrokAcpSupport.ts:33-41), Antigravity (downloaded release verified as antigravity-acp protocolVersion 1, provider/AntigravityInstallation.ts:484-502) are **ACP**; Claude is **@anthropic-ai/claude-agent-sdk in-process** (provider/Layers/ClaudeAdapter.ts:5-27); Codex is **codex app-server JSON-RPC stdio** (provider/Layers/codexLaunchArgs.ts:13, typed by effect-codex-app-server); OpenCode is **HTTP via @opencode-ai/sdk/v2, one server per thread** (provider/Layers/OpenCodeAdapter.ts:32, docs/internals/providers.md:14-22). An ACP-canonical fabric adapters layer therefore still needs three non-ACP lanes (Claude SDK, Codex app-server, OpenCode HTTP) behind the same ProviderAdapter contract — exactly t3code's shape (provider/Services/ProviderAdapter.ts, registry provider/builtInDrivers.ts:49-56). 2. **Adoption units and coupling**: effect-acp and effect-codex-app-server depend only on effect and are extractable as-is; contracts depends only on effect; client-runtime depends on contracts+shared+@effect/atom-react; apps/server depends on all of the above plus platform-node. Dependency direction is clean (contracts ← everything; no cycles observed). 3. **Effect stance data (D5)**: adopting server/contracts/effect-acp means adopting effect@4.0.0-rc.115 + local patch + effect/unstable/{rpc,sql,process,cli,http}; web/mobile UI layers prove Effect can be quarantined to a data layer (17-21% file penetration). 4. **RPC surface size**: 144 Rpc.make in contracts/src/rpc.ts + 8 orchestration methods (contracts/src/orchestration.ts:35-44) + HttpApi groups in environmentHttp.ts + Electron IPC (ipc.ts, 1,388 LOC) — this is the interface fabric's kradle must match or subset. 5. **Compat doctrine to preserve**: environment capability flags negotiate features; persisted events must replay forever; schema transforms (not runtime branches) absorb legacy wire shapes (docs/internals/overview.md:24-44,70-72). 6. **Remote-access stack (D12)**: four routes — direct/LAN pairing (DPoP + pairing grants, apps/server/src/auth/), Tailscale endpoint (packages/tailscale), SSH launch+forward (packages/ssh, desktop-owned lifecycle), and T3 Connect (relay = Cloudflare Worker + Postgres + Clerk + cloudflared, broker-not-proxy, docs/internals/t3-connect.md). Hosted web is a pure client with browser-held connection catalog (docs/internals/remote.md:28-38). 7. **Packaging blueprint (D3 single-node form)**: SEA binary (Node 25.7+ build host, apps/server/scripts/cli.ts:160) → per-platform archive with web client + resource-monitor + 3 native externals (scripts/build-cli-archive.ts:2-15) → npm platform packages + launcher (scripts/build-npm-platform-packages.ts:3-9) → install.sh/ps1 with channels + service layout (scripts/install.sh:2-24) → winget/brew/AUR/deb. Release CI: preflight/quality/test/release/finalize (.github/workflows/release.yml:98-1121). 8. **License/attribution (D15)**: MIT (T3 Tools Inc.); reuse third-party-licenses.config.json + scripts/sync-third-party-license-notices.ts as the attribution mechanism. 9. **Size planning figures**: server 398.6k LOC / web 318.4k / client-runtime 65.8k / contracts 27.0k / effect-acp 15.5k (5.2k handwritten) / effect-codex-app-server 61.8k (3.8k handwritten) / relay 27.4k / ssh 4.1k / tailscale 0.8k. Handwritten-vs-generated distinction matters: both protocol packages are mostly regenerable. 10. **Native/portability constraints**: server native surface = node-pty + @napi-rs/keyring + fff-node (+ optional resource-monitor Rust binary shipped beside it); node:sqlite requires Node ≥22.5; desktop keeps native modules out of Electron main (docs/internals/overview.md:118-124); terminal rendering needs the libghostty-vt wasm story resolved (see INFERRED). 11. **Testing patterns worth importing into D7**: typed runtime receipts + drainable workers instead of sleeps (docs/internals/overview.md:96-104, packages/shared/src/DrainableWorker.ts); ACP mock agent for protocol tests (apps/server/scripts/acp-mock-agent.ts); release smoke (scripts/release-smoke.ts); per-provider adapter test suites co-located with every adapter. 12. **Toolchain divergence to resolve in the spec**: pnpm 11 catalogs/patches + vite-plus + TS7/tsgo (t3code) vs npm workspaces + plain tsc/vitest (fabric). Vendoring any t3code app wholesale imports this toolchain; extracting packages (contracts, effect-acp, ssh, tailscale) does not — they build with plain tsc --noEmit and have no bundler coupling.