Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 127 additions & 40 deletions AGENTS.md

Large diffs are not rendered by default.

22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
# T3 Code

T3 Code is a minimal web GUI for coding agents (currently Codex, Claude, Cursor, and OpenCode, more coming soon).
T3 Code is an "agent harness control surface". It enables control of the agents on your machine with a best-in-class mobile app, [web app](https://app.t3.codes) and [Electron-based desktop app](https://t3.codes).

Works with your subscriptions on Claude Code, Codex, Cursor, Grok Build, and OpenCode. If they're set up on your computer, T3 Code can control them.

## "Wait, what are you selling me?"

Nothing. We built T3 Code because we wanted the best possible development experience with agents. We were inspired by existing solutions like the Codex desktop app, Conductor, Claude Desktop and Cursor Glass, but none met our bar.

We wanted something performant, remote-ready, and truly open. If we ever go the wrong direction, we want you to have everything you need to fork and build the editor that you want.

## Installation

> [!WARNING]
> T3 Code currently supports Codex, Claude, Cursor, and OpenCode.
> Install and authenticate at least one provider before use:
> T3 Code currently supports Codex, Claude, Cursor, Grok Build and OpenCode. Install and authenticate at least one provider before use:
>
> - Codex: install [Codex CLI](https://developers.openai.com/codex/cli) and run `codex login`
> - Claude: install [Claude Code](https://claude.com/product/claude-code) and run `claude auth login`
> - Cursor: install [Cursor CLI](https://cursor.com/cli) and run `cursor-agent login`
> - Grok Build: install [Grok Build CLI](https://x.ai/cli) and run `grok login`
> - OpenCode: install [OpenCode](https://opencode.ai) and run `opencode auth login`

### Run without installing
### Try it out (install-free)

The easiest way to test T3 Code is to run the server in your terminal:

```bash
npx t3@latest
```

This will launch T3 Code's backend on your machine as well as the local web app to control your agents.

Tip: Use `npx t3@latest --help` for the full CLI reference.

### Desktop app
Expand Down Expand Up @@ -47,7 +59,7 @@ yay -S t3code-bin

We are very very early in this project. Expect bugs.

We are not accepting contributions yet.
We are (mostly) not accepting contributions yet. Small fixes may be considered. Big features will not be.

There's no public docs site yet, checkout the miscellaneous markdown files in [docs](./docs).

Expand Down
6 changes: 3 additions & 3 deletions apps/mobile/src/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import { SettingsAuthRouteScreen } from "./features/settings/SettingsAuthRouteSc
import { SettingsEnvironmentsRouteScreen } from "./features/settings/SettingsEnvironmentsRouteScreen";
import { SettingsLegalRouteScreen } from "./features/settings/SettingsLegalRouteScreen";
import { SettingsRouteScreen } from "./features/settings/SettingsRouteScreen";
import { SettingsWaitlistRouteScreen } from "./features/settings/SettingsWaitlistRouteScreen";
import { ShowcaseCaptureCoordinator } from "./features/showcase/ShowcaseCaptureCoordinator";
import {
SettingsLegalDocumentCloseHeaderButton,
Expand Down Expand Up @@ -190,10 +189,11 @@ const SettingsSheetStack = createNativeStackNavigator({
},
}),
SettingsWaitlist: createNativeStackScreen({
screen: SettingsWaitlistRouteScreen,
// Keep the old deep link working after the Connect GA launch.
screen: SettingsAuthRouteScreen,
linking: "waitlist",
options: {
title: "Join the waitlist",
title: "Sign in",
},
}),
},
Expand Down
36 changes: 36 additions & 0 deletions apps/mobile/src/connection/environment-cache-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ function makeDatabase() {
removed.push(id);
values.delete(id);
}),
clearCacheKind: (environmentId, kind) =>
Effect.sync(() => {
for (const key of values.keys()) {
if (key.startsWith(`${environmentId}:${kind}:`)) values.delete(key);
}
}),
clearEnvironmentCache: (environmentId) =>
Effect.sync(() => {
for (const key of values.keys()) {
Expand Down Expand Up @@ -80,6 +86,36 @@ describe("mobile SQLite environment cache store", () => {
}),
);

it.effect("removes one persisted VCS ref snapshot", () =>
Effect.gen(function* () {
const memory = makeDatabase();
const store = yield* make().pipe(Effect.provideService(MobileDatabase, memory.database));
yield* store.saveVcsRefs(ENVIRONMENT_ID, "/repo", REFS);

yield* store.removeVcsRefs(ENVIRONMENT_ID, "/repo");

expect(yield* store.loadVcsRefs(ENVIRONMENT_ID, "/repo")).toEqual(Option.none());
expect(memory.removed).toContain(cacheId(ENVIRONMENT_ID, "vcs-refs", "/repo"));
}),
);

it.effect("clears every persisted VCS ref snapshot in one environment", () =>
Effect.gen(function* () {
const memory = makeDatabase();
const store = yield* make().pipe(Effect.provideService(MobileDatabase, memory.database));
const otherEnvironmentId = EnvironmentId.make("environment-2");
yield* store.saveVcsRefs(ENVIRONMENT_ID, "/repo", REFS);
yield* store.saveVcsRefs(ENVIRONMENT_ID, "/repo-worktree", REFS);
yield* store.saveVcsRefs(otherEnvironmentId, "/repo", REFS);

yield* store.clearVcsRefs(ENVIRONMENT_ID);

expect(yield* store.loadVcsRefs(ENVIRONMENT_ID, "/repo")).toEqual(Option.none());
expect(yield* store.loadVcsRefs(ENVIRONMENT_ID, "/repo-worktree")).toEqual(Option.none());
expect(yield* store.loadVcsRefs(otherEnvironmentId, "/repo")).toEqual(Option.some(REFS));
}),
);

it.effect("clears one environment without touching another", () =>
Effect.gen(function* () {
const memory = makeDatabase();
Expand Down
10 changes: 10 additions & 0 deletions apps/mobile/src/connection/environment-cache-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ export const make = Effect.fn("MobileEnvironmentCacheStore.make")(function* () {
.pipe(Effect.mapError(mapDatabaseError("save-vcs-refs")));
},
),
removeVcsRefs: Effect.fn("MobileEnvironmentCache.removeVcsRefs")((environmentId, cwd) =>
database
.removeCache(environmentId, "vcs-refs", cwd)
.pipe(Effect.mapError(mapDatabaseError("remove-vcs-refs"))),
),
clearVcsRefs: Effect.fn("MobileEnvironmentCache.clearVcsRefs")((environmentId) =>
database
.clearCacheKind(environmentId, "vcs-refs")
.pipe(Effect.mapError(mapDatabaseError("clear-vcs-refs"))),
),
clear: Effect.fn("MobileEnvironmentCache.clear")((environmentId) =>
database
.clearEnvironmentCache(environmentId)
Expand Down
120 changes: 0 additions & 120 deletions apps/mobile/src/features/cloud/CloudWaitlistEnrollment.tsx

This file was deleted.

48 changes: 0 additions & 48 deletions apps/mobile/src/features/cloud/cloudWaitlistJoin.test.ts

This file was deleted.

46 changes: 0 additions & 46 deletions apps/mobile/src/features/cloud/cloudWaitlistJoin.ts

This file was deleted.

Loading
Loading