|
| 1 | +# CoahCode — Codex Handoff Document |
| 2 | + |
| 3 | +## What This Is |
| 4 | + |
| 5 | +CoahCode is a fork of [T3 Code](https://github.com/pingdotgg/t3code) (Theo's open-source AI coding agent) with a Cursor-grade agent harness bolted on. The harness adds parallel tool execution, MCP server support, LSP integration, skills/rules discovery, scheduled tasks, model switching mid-chat, steering (steer vs queue follow-ups), physics-based thread drag-and-drop, checkpoint snapshots, tool result spilling, skill auto-creation nudges, and mixture-of-agents mode. |
| 6 | + |
| 7 | +**Repo:** https://github.com/coah80/coahcode |
| 8 | +**Local path:** `~/Projects/cursor-harness/coahcode-build` |
| 9 | +**Status:** Builds clean, dev server runs, 0 type errors. The harness engine is fully built but not yet wired into T3 Code's orchestration layer — it exists as a parallel system that needs integration. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## Tech Stack |
| 14 | + |
| 15 | +| Layer | Technology | |
| 16 | +|-------|-----------| |
| 17 | +| Monorepo | Turborepo | |
| 18 | +| Runtime | Bun | |
| 19 | +| Server | Effect-TS, SQLite (via `@effect/sql-sqlite-bun`), WebSocket RPC | |
| 20 | +| Web | React 19, TanStack Router + Query, Tailwind CSS 4, Vite | |
| 21 | +| Desktop | Electron (via `apps/desktop`) | |
| 22 | +| AI Providers | Claude Agent SDK (`@anthropic-ai/claude-agent-sdk` v0.2.77), OpenAI Codex CLI | |
| 23 | +| Auth | Claude: OAuth via `claude login`. Codex: API key via `codex login` | |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Monorepo Structure |
| 28 | + |
| 29 | +``` |
| 30 | +coahcode-build/ |
| 31 | + apps/ |
| 32 | + server/ — Backend (Effect-TS services, SQLite, WebSocket RPC) |
| 33 | + src/ |
| 34 | + provider/ — AI provider adapters (ClaudeAdapter, CodexAdapter) |
| 35 | + orchestration/ — Agent state machine (CQRS/event-sourced) |
| 36 | + terminal/ — PTY terminal management |
| 37 | + git/ — Git operations |
| 38 | + persistence/ — SQLite migrations + queries |
| 39 | + harness/ — *** OUR CODE *** (agent harness engine) |
| 40 | + web/ — Frontend (React, TanStack, Tailwind) |
| 41 | + src/ |
| 42 | + components/ — UI components (chat/, settings/, ui/) |
| 43 | + hooks/ — Custom React hooks |
| 44 | + lib/ — React Query options, utilities |
| 45 | + rpc/ — WebSocket RPC client |
| 46 | + routes/ — TanStack Router file-based routes |
| 47 | + desktop/ — Electron shell |
| 48 | + marketing/ — Marketing site |
| 49 | + packages/ |
| 50 | + contracts/ — Shared TypeScript types, RPC definitions, schemas |
| 51 | + shared/ — Shared utilities |
| 52 | +``` |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## The Harness (`apps/server/src/harness/`) |
| 57 | + |
| 58 | +This is all our custom code. 18 files, ~2,500 lines. |
| 59 | + |
| 60 | +### File Map |
| 61 | + |
| 62 | +``` |
| 63 | +harness/ |
| 64 | + types.ts — All type definitions (ToolName, AgentConfig, AgentEvent, etc.) |
| 65 | + index.ts — Barrel exports for everything |
| 66 | +
|
| 67 | + engine/ |
| 68 | + loop.ts — Core agent loop: stream model → collect tool calls → execute in parallel → loop |
| 69 | + prompt.ts — System prompt builder (Cursor-style sections) |
| 70 | + home.ts — Home workspace: discover projects in ~/Projects, ~/Developer, etc. |
| 71 | + scheduler.ts — Cron-based scheduled agent tasks (in-memory, needs persistence) |
| 72 | + steering.ts — Steer vs queue follow-up behavior |
| 73 | + modelSwitch.ts — Mid-chat model switching (pending switch applied after turn) |
| 74 | + skillNudge.ts — Periodic nudges to save reusable skills (every N turns) |
| 75 | + resultSpill.ts — Large tool outputs → temp file + preview (50K per-result, 200K per-turn) |
| 76 | + checkpoint.ts — Shadow git snapshots before file mutations (~/.coahcode/checkpoints/) |
| 77 | + mixtureOfAgents.ts — Fan hard problems to N models in parallel, synthesize answer |
| 78 | +
|
| 79 | + providers/ |
| 80 | + anthropic.ts — Anthropic Messages API streaming with tool use |
| 81 | + openai.ts — OpenAI/OpenRouter Chat Completions streaming with tool use |
| 82 | +
|
| 83 | + tools/ |
| 84 | + index.ts — 11 tool implementations + tool definitions |
| 85 | + Shell, Read, Write, StrReplace, Delete, Glob, Grep, |
| 86 | + ReadLints, TodoWrite, WebSearch, WebFetch |
| 87 | +
|
| 88 | + mcp/ |
| 89 | + client.ts — MCP client: local (stdio) + remote (HTTP) servers |
| 90 | + McpManager class with connectAll, getAllTools, callTool |
| 91 | +
|
| 92 | + lsp/ |
| 93 | + client.ts — LSP client: lazy spawn, JSON-RPC over stdio |
| 94 | + Built-in: TypeScript, Python, Go, Rust, CSS |
| 95 | + getDiagnostics, goToDefinition, hover |
| 96 | +
|
| 97 | + skills/ |
| 98 | + loader.ts — SKILL.md discovery from ~/.claude/skills, ~/.cursor/skills, project dirs |
| 99 | + AGENTS.md/CLAUDE.md instruction loading |
| 100 | + Exposed as "Skill" tool for the model to call |
| 101 | +``` |
| 102 | + |
| 103 | +### How the Agent Loop Works (`engine/loop.ts`) |
| 104 | + |
| 105 | +``` |
| 106 | +1. Discover skills + load instructions from workspace |
| 107 | +2. Connect MCP servers (if configured) |
| 108 | +3. Build tool list: built-in + MCP + LSP + skills |
| 109 | +4. Build system prompt with instructions |
| 110 | +5. LOOP: |
| 111 | + a. Stream model response (Anthropic or OpenAI) |
| 112 | + b. Accumulate text + tool calls |
| 113 | + c. If no tool calls → done |
| 114 | + d. Checkpoint files about to be mutated (shadow git) |
| 115 | + e. Execute ALL tool calls in PARALLEL (Promise.all) |
| 116 | + - Route by prefix: mcp_* → MCP, LSP → LSP, Skill → skills, else → built-in |
| 117 | + f. Spill oversized results to temp files |
| 118 | + g. Append to conversation history |
| 119 | + h. Nudge skill/memory creation if enough turns passed |
| 120 | + i. Back to (a) |
| 121 | +6. Cleanup MCP connections |
| 122 | +``` |
| 123 | + |
| 124 | +### Key Design Decisions |
| 125 | + |
| 126 | +- **Parallel execution** is the speed secret. All tool calls in a single model turn execute concurrently via `Promise.all`. This matches Cursor's architecture. |
| 127 | +- **MCP tools are namespaced** as `mcp_{serverName}_{toolName}` to avoid collisions. |
| 128 | +- **Skills are tools, not system prompt** — the model calls `Skill({name: "foo"})` and gets the skill content as tool output. This preserves prompt caching. |
| 129 | +- **Checkpoints are invisible** to the model. Shadow git repos in `~/.coahcode/checkpoints/` snapshot files before every Write/StrReplace/Delete. |
| 130 | +- **Result spilling** uses a 3-layer budget: per-result 50K chars, per-turn aggregate 200K chars. Oversized outputs get a head/tail preview + file path the model can `Read` later. |
| 131 | + |
| 132 | +--- |
| 133 | + |
| 134 | +## Frontend Components We Added |
| 135 | + |
| 136 | +### In `apps/web/src/components/` |
| 137 | + |
| 138 | +| File | What It Does | |
| 139 | +|------|-------------| |
| 140 | +| `ScheduledTasks.tsx` | CRUD UI for cron-scheduled agent runs. Create/toggle/delete tasks with preset schedules and model picker. Wired to React Query → LocalApi stubs. | |
| 141 | +| `WorkspacePicker.tsx` | Search + select project workspaces. Shows git remote info. Create new projects. Wired to React Query → LocalApi stubs. | |
| 142 | +| `chat/ModelSwitcher.tsx` | Dropdown to switch models mid-chat. Groups by provider (Anthropic/OpenAI/OpenRouter). Shows tier badges (fast/standard/premium/reasoning). | |
| 143 | +| `chat/SteeringIndicator.tsx` | Shows "Steer" or "Queue" mode during active runs. Toggle between modes. | |
| 144 | + |
| 145 | +### In `apps/web/src/hooks/` |
| 146 | + |
| 147 | +| File | What It Does | |
| 148 | +|------|-------------| |
| 149 | +| `usePhysicsDrag.tsx` | Spring pendulum physics for dragging threads between folders. `DragGhost` component renders SVG string from cursor to dangling card. Uses `requestAnimationFrame` simulation loop. | |
| 150 | + |
| 151 | +### In `apps/web/src/lib/` |
| 152 | + |
| 153 | +| File | What It Does | |
| 154 | +|------|-------------| |
| 155 | +| `scheduledTasksReactQuery.ts` | TanStack Query options for scheduled tasks CRUD. Uses `ensureLocalApi()`. | |
| 156 | +| `workspaceReactQuery.ts` | TanStack Query options for workspace discovery + creation. | |
| 157 | + |
| 158 | +### Branding Changes |
| 159 | + |
| 160 | +- `apps/web/src/index.css` — Primary color changed from blue (hue 264) to purple (hue 303) in both light and dark mode |
| 161 | +- `apps/web/src/branding.ts` — `APP_BASE_NAME` changed to `"CoahCode"` |
| 162 | +- `apps/web/index.html` — Title changed to `"CoahCode"` |
| 163 | +- `apps/web/src/components/Sidebar.tsx` — Wordmark changed from T3 SVG logo to `<span className="text-primary font-bold">Coah</span>Code` |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +## Contracts Changes (`packages/contracts/src/`) |
| 168 | + |
| 169 | +### `ipc.ts` |
| 170 | +- Added `scheduledTasks` and `workspace` namespaces to `LocalApi` interface |
| 171 | +- Added `ScheduledTaskInfo`, `ScheduledTaskCreateInput`, `WorkspaceProject` types |
| 172 | + |
| 173 | +### `rpc.ts` |
| 174 | +- Added `WS_METHODS` entries: `scheduledTasks.list`, `.create`, `.delete`, `.toggle`, `workspace.discover`, `.create`, `.switch` |
| 175 | +- Added `Rpc.make()` definitions for all new methods |
| 176 | +- Added all new RPCs to `WsRpcGroup` |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## What Works Right Now |
| 181 | + |
| 182 | +1. **Build** — `bun run build` passes clean (5/5 tasks, 0 errors) |
| 183 | +2. **Dev server** — `bun run dev` starts web on :5733 and server on :13773 |
| 184 | +3. **Auth** — Claude via `claude login` OAuth, Codex via API key |
| 185 | +4. **Chat** — Full T3 Code chat experience with Claude/Codex |
| 186 | +5. **Diffs** — File diff visualization |
| 187 | +6. **Terminals** — Integrated terminal sessions |
| 188 | +7. **Plan mode** — Plan sidebar with implementation flow |
| 189 | +8. **Purple accent** — Throughout light and dark themes |
| 190 | +9. **CoahCode branding** — Sidebar, title, settings |
| 191 | +10. **Steering indicator** — Shows in composer footer during active runs |
| 192 | +11. **ScheduledTasks UI** — Renders in settings page (data is in-memory stubs) |
| 193 | + |
| 194 | +--- |
| 195 | + |
| 196 | +## What Needs Wiring (Priority Order) |
| 197 | + |
| 198 | +### 1. Integrate Harness with Orchestration Engine (HIGH) |
| 199 | + |
| 200 | +The harness in `apps/server/src/harness/` is a standalone agent loop. T3 Code has its own orchestration system in `apps/server/src/orchestration/` that manages threads, turns, events, and checkpoints via CQRS/event-sourcing with Effect-TS. |
| 201 | + |
| 202 | +**What needs to happen:** |
| 203 | +- Create a `HarnessAdapter` that implements `ProviderAdapterShape` (see `apps/server/src/provider/Services/ProviderAdapter.ts`) |
| 204 | +- Register it in `ProviderAdapterRegistry` alongside `ClaudeAdapter` and `CodexAdapter` |
| 205 | +- The adapter should use `runAgentLoop()` from our harness engine |
| 206 | +- Map harness `AgentEvent` types to T3 Code's `ProviderRuntimeEvent` types |
| 207 | +- This lets users choose "CoahCode Harness" as a provider alongside Claude/Codex |
| 208 | + |
| 209 | +**Key files to study:** |
| 210 | +- `apps/server/src/provider/Layers/ClaudeAdapter.ts` — Reference implementation |
| 211 | +- `apps/server/src/provider/Services/ProviderAdapter.ts` — Interface to implement |
| 212 | +- `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts` — Registration |
| 213 | +- `apps/server/src/orchestration/Services/OrchestrationEngine.ts` — State machine |
| 214 | + |
| 215 | +### 2. Wire Scheduled Tasks to Persistence (MEDIUM) |
| 216 | + |
| 217 | +Currently `scheduledTasks` in `LocalApi` returns empty stubs. Needs: |
| 218 | +- SQLite migration for `scheduled_tasks` table |
| 219 | +- Effect service layer for CRUD |
| 220 | +- RPC handler in the server's WS handler (`apps/server/src/ws.ts`) |
| 221 | +- Wire the `scheduledTasksReactQuery` to use real RPC calls instead of stubs |
| 222 | +- Implement the actual scheduler that invokes `runAgentLoop()` on cron triggers |
| 223 | + |
| 224 | +### 3. Wire Workspace Discovery to Real File System (MEDIUM) |
| 225 | + |
| 226 | +Currently `workspace` in `LocalApi` returns empty stubs. Needs: |
| 227 | +- RPC handler that calls `discoverProjects()` from `harness/engine/home.ts` |
| 228 | +- Wire `workspaceReactQuery` to real RPC calls |
| 229 | +- Add workspace switcher to the sidebar (T3 Code already has project add/remove) |
| 230 | + |
| 231 | +### 4. Wire Physics Drag into Sidebar Thread List (LOW) |
| 232 | + |
| 233 | +`usePhysicsDrag.tsx` is built but not connected to the sidebar. Needs: |
| 234 | +- Import `usePhysicsDrag` and `DragGhost` in `Sidebar.tsx` |
| 235 | +- Add `onMouseDown={startDrag}` to thread items |
| 236 | +- Render `DragGhost` at the root level |
| 237 | +- Handle `onDrop` to move threads between projects |
| 238 | +- `data-drop-zone` attributes are already on project `<Collapsible>` elements |
| 239 | + |
| 240 | +### 5. Wire ModelSwitcher into Composer (LOW) |
| 241 | + |
| 242 | +`ModelSwitcher.tsx` is built but not rendered. T3 Code already has a `ProviderModelPicker` component in the composer footer. Options: |
| 243 | +- Replace `ProviderModelPicker` with our `ModelSwitcher` (more models, tier badges) |
| 244 | +- Or add `ModelSwitcher` as a secondary picker for mid-chat switching |
| 245 | +- Wire the `onSwitch` callback to `requestModelSwitch()` from `harness/engine/modelSwitch.ts` |
| 246 | + |
| 247 | +### 6. Connect MCP Config to UI (LOW) |
| 248 | + |
| 249 | +The harness `McpManager` accepts `McpServerConfig[]`. Needs: |
| 250 | +- Settings UI for adding/removing MCP servers (command + args for local, URL for remote) |
| 251 | +- Persist config to SQLite or JSON file |
| 252 | +- Pass configs to `runAgentLoop()` via `mcpConfigs` option |
| 253 | + |
| 254 | +### 7. Connect LSP Manager Lifecycle (LOW) |
| 255 | + |
| 256 | +The harness `LspManager` spawns LSP servers lazily. Needs: |
| 257 | +- Initialize `LspManager` at server startup |
| 258 | +- Pass it to `runAgentLoop()` via `lspManager` option |
| 259 | +- Clean up on server shutdown |
| 260 | +- Optional: settings UI for custom LSP server configs |
| 261 | + |
| 262 | +--- |
| 263 | + |
| 264 | +## How to Run |
| 265 | + |
| 266 | +```bash |
| 267 | +# Prerequisites: bun, claude login (for Claude), codex login (for Codex) |
| 268 | +cd ~/Projects/cursor-harness/coahcode-build |
| 269 | +bun install |
| 270 | +bun run dev |
| 271 | +# Open the pairing URL printed in the terminal |
| 272 | +``` |
| 273 | + |
| 274 | +## How to Build |
| 275 | + |
| 276 | +```bash |
| 277 | +bun run build # Full production build |
| 278 | +bun run typecheck # Type checking only |
| 279 | +bun run test # Run tests |
| 280 | +bun run lint # Lint with oxlint |
| 281 | +``` |
| 282 | + |
| 283 | +## How to Update from Upstream T3 Code |
| 284 | + |
| 285 | +```bash |
| 286 | +git fetch upstream main |
| 287 | +git merge upstream/main |
| 288 | +# Resolve conflicts (our files are in harness/ and won't conflict with upstream) |
| 289 | +# Re-check branding (Sidebar wordmark, index.css colors, branding.ts) |
| 290 | +bun run build # Verify |
| 291 | +``` |
| 292 | + |
| 293 | +--- |
| 294 | + |
| 295 | +## Architecture Diagram |
| 296 | + |
| 297 | +``` |
| 298 | +┌─────────────────────────────────────────────────────┐ |
| 299 | +│ React Frontend (apps/web) │ |
| 300 | +│ ├── ChatView + ChatComposer (existing T3 Code) │ |
| 301 | +│ ├── ModelSwitcher (our addition) │ |
| 302 | +│ ├── SteeringIndicator (our addition) │ |
| 303 | +│ ├── ScheduledTasks (our addition) │ |
| 304 | +│ ├── WorkspacePicker (our addition) │ |
| 305 | +│ └── usePhysicsDrag (our addition) │ |
| 306 | +├─────────────────────────────────────────────────────┤ |
| 307 | +│ WebSocket RPC (packages/contracts/src/rpc.ts) │ |
| 308 | +├─────────────────────────────────────────────────────┤ |
| 309 | +│ Server (apps/server) │ |
| 310 | +│ ├── OrchestrationEngine (existing — CQRS/ES) │ |
| 311 | +│ ├── ProviderService (existing — routes to adapters) │ |
| 312 | +│ │ ├── ClaudeAdapter (existing — Claude Agent SDK) │ |
| 313 | +│ │ ├── CodexAdapter (existing — OpenAI Codex CLI) │ |
| 314 | +│ │ └── HarnessAdapter (TODO — our harness) │ |
| 315 | +│ ├── TerminalManager (existing) │ |
| 316 | +│ ├── GitManager (existing) │ |
| 317 | +│ └── Harness Engine (our addition) │ |
| 318 | +│ ├── Agent Loop (parallel tool execution) │ |
| 319 | +│ ├── Tools (Shell, Read, Write, Grep, etc.) │ |
| 320 | +│ ├── MCP Client (local + remote servers) │ |
| 321 | +│ ├── LSP Client (TS, Python, Go, Rust, CSS) │ |
| 322 | +│ ├── Skills Loader (SKILL.md, AGENTS.md) │ |
| 323 | +│ ├── Scheduler (cron tasks) │ |
| 324 | +│ ├── Checkpoints (shadow git snapshots) │ |
| 325 | +│ ├── Result Spilling (context budget) │ |
| 326 | +│ ├── Skill Nudges (auto-capture knowledge) │ |
| 327 | +│ └── Mixture of Agents (multi-model synthesis) │ |
| 328 | +└─────────────────────────────────────────────────────┘ |
| 329 | +``` |
| 330 | + |
| 331 | +--- |
| 332 | + |
| 333 | +## Reference: Cursor Decompilation |
| 334 | + |
| 335 | +All extracted Cursor data is in `~/cursor-decompiled/` (17 files, 176KB). Key files: |
| 336 | +- `server-prompts.md` — 7 server-side system prompt variants |
| 337 | +- `server-tool-definitions.json` — 19 tool definitions captured from the model |
| 338 | +- `harness-architecture.md` — How Cursor's harness achieves its speed |
| 339 | +- `EXTRACTION-PLAYBOOK.md` — 14-step guide to re-extract after Cursor updates |
| 340 | + |
| 341 | +The harness architecture in this codebase is modeled after Cursor's BiDi streaming tool loop with parallel execution, as documented in those files. |
| 342 | + |
| 343 | +--- |
| 344 | + |
| 345 | +## Key Contacts |
| 346 | + |
| 347 | +- **Original T3 Code:** https://github.com/pingdotgg/t3code (Theo/ping.gg) |
| 348 | +- **Cursor decompilation data:** `~/cursor-decompiled/` |
| 349 | +- **Memory system:** All project context is logged in mcp-memory (search for "CoahCode" or "cursor-decompiled") |
0 commit comments