1# The Knife
2
3The Knife is Clover’s fork of T3 Code, focused on precise engineering across the backend and UI. Fork behavior and identity belong to this patch stack; the upstream architecture and service names below describe the foundation.
4
5T3 Code is a minimal GUI for coding agents. A Node WebSocket server wraps provider CLIs and agents (Codex, Claude Code, Cursor, Grok, OpenCode, Antigravity) and serves web, desktop, and mobile clients.
6
7You can think of T3 Code as an open source "bring-your-own-subscription" alternative to apps like Claude Desktop, Codex App, Cursor Glass and Conductor.
8
9## What makes T3 Code special?
10
11We have over 500,000 users who love T3 Code. It's important we maintain the things they love as we continue to iterate on the product. Here's a brief list of the things we can never compromise on.
12
13### 1. Open at the core
14
15T3 Code is truly open. We share our roadmap, we share how we think about things, and of course we share all our code. A large number of our users run forks. We work in the open, and should strive to stay that way.
16
17### 2. Performance without compromise
18
19Lots of apps have gotten bogged down with bad tech decisions and "slop". We have not, and we're proud of the performance of T3 Code. We regularly audit for performance regressions, often caused by sending too much data over websockets, css animations causing gpu spikes, lists being hard to render, and more. Make sure all changes are considerate of performance impact.
20
21### 3. Remote ready
22
23The architecture of T3 Code's websocket layer (npx t3) enables a lot of awesome remote features. These have become core to the product. Whether users are connecting directly over their local network, using Tailscale, or leaning in fully with T3 Connect (our tunnel solution, also in this repo), we need to make sure new features are properly supported.
24
25### 4. Multi-surface
26
27T3 Code has 3 key app surfaces: **web**, **desktop**, and **mobile**.
28
29**Web** is kind of two surfaces, as we have the public facing "app.t3.codes" as well as locally hosting the web app through the `npx t3` command. Both need to be supported by all new features where reasonable.
30
31**Desktop** is the main surface most users install first. It's a full Electron app that bundles the server runner as well. The desktop app can also be used as the host server, allowing remote connections from app.t3.codes or the mobile app.
32
33**Mobile** is a React Native app for both iOS and Android, available on the App Store and Google Play. The mobile app allows for connecting to any T3 Code server to control work remotely.
34
35## A note from Theo
36
37I like ambitious ideas, simple systems, and software that feels obvious. Do not preserve complexity just because it already exists. Do not introduce machinery because it looks architecturally impressive. Understand the real constraint, then fight for the smallest model that makes the correct behavior unsurprising.
38
39Channel both "measure twice, cut once" and "yagni". Fight scope creep. Try to honor the dev's intent in both a minimal and realistic fashion.
40
41The rest of this document is meant to help you navigate the codebase and make changes effectively. Think of these instructions less as "hard rules", more as "good defaults". The developer's preferences should be able to override anything here.
42
43Of note: Most T3 Code contributions will come from T3 Code itself, often controlled remotely. This means you should be careful about accessing data, killing dev servers, and other things that may damage the T3 Code instance that the contributor is using.
44
45## A small glossary
46
47We need to be on the same page with terminology. When communicating, use this language:
48
49- **you** means the agent reading this file and changing T3 Code.
50- **we, us, and maintainers** mean Theo, Julius and the people building T3 Code. These are who you are talking to now.
51- **user** means the person using T3 Code to direct coding agents.
52- **agent** means the coding agent a user runs inside T3 Code. Depending on context, that may also include you.
53- **provider** means the agent runtime or harness T3 Code talks to, such as Codex, Claude, Cursor, or OpenCode.
54- **client** means the web, desktop, or mobile UI.
55- **environment** means one running T3 server and the machine, filesystem, provider credentials, and state it owns.
56- **project** means an environment-local workspace record rooted at a directory.
57- **thread** means the durable conversation and work history for a project.
58- **turn** means one user-to-agent cycle, including follow-up work such as checkpointing.
59- **T3 home** means the base data directory. Runtime state normally lives below its userdata directory.
60
61## The three ways to hurt yourself
62
631. **Killing by pattern.** Never `pkill -f`, `pgrep | kill`, or `kill` a PID you found by matching a name, path, or worktree string. Your own agent process has this worktree's path in its argv, and this machine runs several other dev servers at once. Kill only a PID you captured at spawn, or the owner of your port from `ss -H -ltnp` after confirming `/proc/<pid>/cwd` is your worktree.
642. **Writing to the live install.** `~/.t3/userdata` is the developer's real T3 Code database, in use while you work. Reading it and copying from it are fine, and a good way to get real test data (see Test data). Never start a server against it, never open it read-write, never clean it up.
653. **Baking in origins.** Never set `VITE_HTTP_URL` or `VITE_WS_URL` for dev. Dev is single-origin and Vite proxies `/api`, `/ws`, `/oauth`, and `/.well-known`. Setting them bakes localhost into the bundle and silently breaks every remote browser.
66
67## Hit every surface
68
69The most common defect in this repo is a change that works on the path you tested and is missing everywhere else. Before calling frontend work done, walk this list and say which entries applied:
70
71- **Entry points.** A behavior reachable from the chat view is usually also reachable from Settings, the command palette, and a keybinding. Fixing one is not fixing the feature.
72- **Clients.** Web, desktop (wraps web, adds Electron shell/IPC), and mobile (React Native, separate navigation). Shared logic lives in `packages/client-runtime`
73- **Providers.** Codex, Claude, Cursor, Grok, OpenCode, and Antigravity each have an adapter. Provider-shaped features need a decision per adapter, even if the decision is "not supported here".
74- **Agents.** A capability a user can trigger is usually one an agent should reach through MCP tools, and scheduled tasks run the same paths. That only works when it is a service method, not handler code.
75- **Contracts.** Anything crossing the wire is typed in `packages/contracts`. Change the schema and the server, web, mobile, and desktop all follow.
76- **Reverse states.** If you added a way in, add the way out and the way to see it. Snooze needs unsnooze. Close needs reopen. A one-way door is a bug.
77- **Connection modes.** Local, remote/relay, and tunnel behave differently. Multi-device and multi-environment cases are real.
78- **Docs.** Check whether the change makes existing guidance inaccurate. Apply the [documentation rules](#documentation) before adding anything.
79
80## Dev servers
81
82- `vp i` installs. Worktrees get this from the t3.json setup script; if module resolution looks broken, it probably did not run.
83- `vp run dev` starts server and web. In a worktree, state defaults to that worktree's gitignored `.t3`, which deliberately outranks an ambient `T3CODE_HOME` so you cannot land on shared state by accident. An explicit `--home-dir` still wins.
84- Ports derive from the worktree path and are stable across restarts, but read the real ones from the `[dev-runner]` line since occupied ports shift.
85- Sharing over the tailnet is three steps: run `vp run dev --share` in the background, wait for the `pairingUrl:` line in its output, then give that full URL to an unpaired browser. Do not wire up `tailscale serve` by hand, open the URL yourself, or consume the user's pairing link. A browser with the reusable dev cookie can use the bare origin. If a normal one-time token was consumed, mint a fresh one with `node apps/server/src/bin.ts pair`. It carries standard scopes, while the startup URL carries admin scopes needed for Connections settings.
86- To reuse web dev auth across worktrees, configure one fixed `T3CODE_DEV_AUTH_TOKEN` in the main checkout's gitignored `.env`. The `t3.json` setup links that file into worktrees. Never commit or publish the token or a startup URL. See [Reusable dev credential](docs/operations/development.md#reusable-dev-credential).
87- Stop what you started, by the PID you tracked. See rule 1.
88
89## Test data
90
91An empty database is a bad test. Seed your worktree's `.t3` with a copy of real data instead of pointing at live state:
92
93- Run `vp run migrate-dev-db` with your dev server stopped. It rebuilds `<worktree>/.t3/userdata/statev2.sqlite` from a read-only snapshot of `~/.t3/userdata/statev2.sqlite`, the developer's real data. It keeps recent projects and their stopped threads, and drops scheduled tasks, pending work, and auth sessions, so your dev server never runs the developer's agents. Raise `--projects` and `--threads-per-project` for more data.
94- Refresh `statev2.sqlite`, not `state.sqlite`. The server copies the V1 `state.sqlite` only when `statev2.sqlite` is missing.
95- Bring `secrets` and `settings.json` only if the flow under test needs them.
96- Copy in, never symlink. Data flows one way: into your sandbox, never back out.
97
98## Verifying
99
100- Smallest proof that the change works. `vp test run <files>` for the tests you touched, targeted lint and typecheck for the scope you changed.
101- Test meaningful logic or observable behavior. Do not render components to static markup to assert props or attributes, or add tests that merely assert callback wiring or mirror the implementation.
102- **Do not run repo-wide checks.** No `vp check`, no `vp run -r test`, no `vp run -r typecheck` unless I ask. CI owns the full suite.
103- Backend behavior changes ship with focused tests for that behavior.
104- The server is event-sourced, and side effects run after the command commits. In tests, drain the effect worker (`OrchestrationEffectWorkerV2.drain`) or await the specific persisted event or `Deferred` that marks the milestone. Never wait on sleeps or polling. A test that needs a timeout to pass is wrong.
105- Upon request, user-visible frontend changes should get one integrated pass in a real client: `test-t3-app` for web, `test-t3-mobile` for mobile. The primary agent does this once after integrating. Subagents do not launch their own dev servers. Ask permission before doing computer use or spinning up browsers.
106
107For authorized mobile verification, a missing or outdated native client is a build step, not a blocker. Run `node scripts/mobile-native-client.ts ensure <ios|android> <device-id>` on the simulator host before starting Metro. It checks the local Expo fingerprint and builds/installs when needed. See `test-t3-mobile` for the full workflow.
108
109## Documentation
110
111Most code changes do not need an internal documentation change. Agents can read the code.
112
113- `docs/internals/` is for architectural decisions and their reasons, constraints that span components, and implementation traps that are hard to discover from the source. Before adding a paragraph, ask what a maintainer would get wrong without it. If reading the relevant code answers the question, leave it out.
114- Do not document every feature, enumerate fields or methods, narrate control flow, maintain file catalogs, or append PR summaries. Types, tests, and code already record the implementation. The glossary defines shared vocabulary; it is not a feature index.
115- Keep a local implementation explanation in a nearby code comment. Use an internal doc when the reasoning crosses boundaries or needs context the code cannot carry well. Link to the relevant source instead of copying it.
116- When a documented decision or constraint changes, rewrite or remove the affected text. Do not append another account of the new behavior. A new internal page needs a distinct, durable reason to exist.
117- `docs/user/` helps users accomplish tasks. Give each major feature a concise section explaining what it does, how to start, and anything unintuitive. A settings path is useful; descriptions of visible buttons, icons, layouts, animations, or every UI state are not. Before adding text, ask what task or decision it helps the user with.
118- Keep user docs in the shipped product's voice, without implementation details or contributor tooling. Update the relevant feature section when how to use it changes. A UI tweak does not need a documentation entry, and a new control does not need its own page.
119- `docs/operations/` holds maintainer setup, release, and debugging procedures. Keep instructions for operating an installed T3 Code server in the user guides.
120
121## Fork patch workflow
122
123This checkout is a fork of T3 code for Clover. All changes should be
124categorized into a set of well-maintained changes on top of the upstream. When
125a change to something you already patched is requested, the changes are
126squashed in. This allows rebasing without having hundreds of changes. The
127patches can also be cherry-picked for upstreaming if Theo or someone elses fork
128wants the change. Exact operating rules:
129
130- Fork-only work follows these rules instead of upstream contribution and PR
131 conventions. Apply the upstream process when Clover requests an upstream submission.
132- Keep one Jujutsu change per complete behavior above `main@upstream`, not per
133 iteration or touched file. Fold revisions into their owning patch with
134 `jj squash --from @ --into <patch-change-id> --use-destination-message`.
135- Order setup first, general UI patches next, and work integrations last. Within
136 each group, put dependencies before their consumers.
137- Use unscoped titles such as `feat: ...` and `fix: ...`. The only scope is
138 `at-work`, for work-specific patches.
139- Titles name the concrete change. For replacements, name the original T3
140 component and replacement package; explain behavior and retained features in
141 the description. Rewrite descriptions when a patch's scope changes.
142- Keep fork setup and agent guidance together in the setup patch.
143- After testing a change yourself, publish it with `vp run fork:release` before
144 handing it back. Follow the
145 [private release procedure](docs/operations/development.md#private-fork-releases-for-apple-silicon).
146 Publish every supported desktop platform affected by the change, using the
147 native build and ingestion steps in that procedure.
148 Reuse unchanged UI, static assets, application code, and shell artifacts; all machines consume
149 the same public feed. Keep the upload API key and signing credentials in
150 `~/.config/t3-fork-release.json`, outside the repository.
151- Downloads are automatic. Backend and shell restarts require confirmation.
152 Automatically refresh a pending UI after one minute unfocused or ten minutes
153 idle only when browser, terminal, draft, composer, and scroll state survive.
154 Defer the refresh when a live view or unsaved work cannot be restored.
155- Keep employer names, logos, repository identifiers, and service origins in
156 private host configuration, outside tracked files and change descriptions.
157- Describe the intended behavior and why Clover requested it in each change's description.
158- Use managed Jujutsu workspaces when they help parallel subagents; integrate their changes into the same stack.
159
160## Plans and work artifacts
161
162- Do not commit implementation plans, research notes, or agent scratch files. Keep temporary working material outside the worktree. `.plans/` is gitignored only as a safety net for legacy tooling.
163- Track active maintainer work in the GitHub issue or project item that owns it. External proposals follow `CONTRIBUTING.md` and belong in Ideas discussions.
164- A merged PR is the implementation record. Close or update its tracking item when the work lands; do not preserve a second checklist in the repository.
165
166## How it works
167
168Clients send typed WebSocket requests. The server turns them into _commands_. The _orchestrator_ (`apps/server/src/orchestration-v2/Orchestrator.ts`) serializes commands and decides _events_ without doing any I/O. The _event sink_ commits those events, the _projections_ the UI reads, the _command receipt_, and _outbox_ effects in one transaction. The _effect worker_ then runs the effects, such as starting a provider turn or capturing a checkpoint, and feeds results back as commands. Provider CLIs run as subprocesses; per-provider _adapters_ translate their native protocols into orchestration events. Each turn ends with a _checkpoint_, a hidden git ref, so the app can diff and restore.
169
170Architecture and its constraints: `docs/internals/overview.md`. Glossary: `docs/internals/glossary.md`
171
172## Where code lives
173
174- `apps/server` - WebSocket, orchestration, providers, checkpointing. Effect-heavy: read [Effect services](docs/internals/effect-services.md) before adding server code, and `.repos/effect-smol/LLMS.md` for the Effect library itself.
175- `apps/web` - React/Vite UI. `apps/desktop` wraps it, `apps/mobile` is React Native, `apps/marketing` is the site.
176- `packages/contracts` - Effect/Schema contracts plus small derived helpers. No heavy runtime logic.
177- `packages/shared` - shared runtime utils, subpath exports, no barrel.
178- `packages/client-runtime` - client code shared by web and mobile.
179- `.repos/` - vendored read-only references. Prefer their patterns over invented ones. Never edit or import from them. Sync with `vpr sync:repos` when bumping the matching dependency.
180
181## Taste
182
183- Complexity belongs at the adapter boundary. Orchestration stays pure, UI stays dumb.
184- Client mutations use `createEnvironmentRpcCommand`. Add protected methods to `CLIENT_GUARDED_RPC_SCOPES` in contracts and use the command's `permissionAtom` for UI availability. Grants are checked at execution against the destination environment; the server remains authoritative. Keep raw RPC clients inside `rpc/`, and extend the permission behavior tests when adding a protected method.
185- Server features are services; transports stay thin. A `ws.ts` RPC handler, HTTP route, or MCP tool decodes input, calls one service method, and maps errors. See [Effect services](docs/internals/effect-services.md).
186- `apps/web/src/components/ui` exports own their look. Pick a `variant` or `size`; do not restyle one with `className`. If none fits and the look is a generic concept, add a variant to the component; a look that belongs to one feature stays in that feature's own component, not in `components/ui`. Layout classes (width, flex, margin, position) belong on the parent. `shadcn/no-restyle` fails lint on violations. See [Web UI](docs/internals/web-ui.md).
187- Inferred types over annotations. `any` is the enemy.
188- Comments describe how a thing is used, and move when the code moves. To be used mostly to describe functions, not to annotate every line of behavior.
189- Our users drive agents all day and notice a dropped frame, a lying spinner, and a stale label. No continuously repainting animations; they peg the GPU on high-refresh displays.
190- If a rule here fights the task in front of you, say so loudly and get a human sign-off before breaking it.
191
192## Additional tips
193
194- Don't verify with browsers or computer use unless the user explicitly agrees or requests it.
195- Security is important, but should not be over-indexed on, especially for dev mode/maintainer-only features.