Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1b4830f
fix(desktop): restore T3 Connect sign-in (#4809)
PixPMusic Jul 29, 2026
08e4932
Simplify files panel header (#4828)
juliusmarminge Jul 29, 2026
72b960f
build(desktop): reduce installed app size by ~300MB (#4824)
wukko Jul 29, 2026
c3e8fb6
Update model version from claude-opus-4-8 to claude-opus-5 (#4832)
juliusmarminge Jul 29, 2026
3137c2b
Preserve the thread shell while detail loads (#4830)
juliusmarminge Jul 29, 2026
49c0d96
Reduce idle work and disk churn with native resource diagnostics (#2679)
juliusmarminge Jul 29, 2026
d19039a
fix(server): detect repositories after initialization (#4848)
StiensWout Jul 29, 2026
faea70a
perf(server): merge separate staged/unstaged numstat calls into singl…
UtkarshUsername Jul 29, 2026
85a8986
fix(git): disable external diff for review diff previews (#4854)
ohbentos Jul 29, 2026
fc28abf
Fix editable file focus and live syntax highlighting (#3979)
jakeleventhal Jul 29, 2026
e698796
fix(web): remember the rendered-markdown choice across threads (#4853)
Sy-D Jul 29, 2026
a8e05cb
chore(release): prepare v0.0.31
t3-code[bot] Jul 29, 2026
9e3e9bb
fix(mobile): reduce thread feed scroll jank (#4874)
gabrielelpidio Jul 30, 2026
35a6840
fix(web): restore sidebar v2 thread actions and terminal icon (#4712)
Noojuno Jul 30, 2026
2d9066e
fix(web): settle button now works on hover, not just right-click (#4905)
t3dotgg Jul 30, 2026
758deca
fix(clients): disable add project while disconnected (#4834)
StiensWout Jul 30, 2026
b125b76
fix(composer): hide default Codex service tier (#4784)
maxktz Jul 30, 2026
748203e
docs: link iOS and Android app store downloads (#4902)
t3dotgg Jul 30, 2026
6efcf3e
fix(web): align remote server update action (#4731)
StiensWout Jul 30, 2026
6ab2f16
fix(connect): suggest a serve command that matches how you ran connec…
t3dotgg Jul 30, 2026
00da6b5
fix(mobile): stop shared content errors in Personal Team builds (#4943)
t3dotgg Jul 30, 2026
f0f16e4
perf(mobile): sends respond instantly, thread opens stop freezing (#4…
t3dotgg Jul 30, 2026
9146ed2
fix(web): show Codex fast mode as a bolt (#4947)
t3dotgg Jul 30, 2026
2f466ff
docs: seed worktrees with a copy of real userdata instead of banning …
t3dotgg Jul 30, 2026
2652fee
fix(mobile): support dragged images in the composer (#4953)
t3dotgg Jul 30, 2026
90f3913
fix(mobile): stop long iOS threads from jumping while scrolling up (#…
t3dotgg Jul 30, 2026
f0c6ba9
fix(web): keep worktree default when switching a draft's machine (#4964)
t3dotgg Jul 30, 2026
69a18ce
perf(mobile): reconnect environments immediately on resume (#4878)
t3dotgg Jul 30, 2026
cbe8052
feat(web): pasting a huge screenshot now compresses it instead of err…
t3dotgg Jul 30, 2026
5c9358a
feat(web): regenerate thread titles from sidebar (#4810)
t3dotgg Jul 30, 2026
197d348
fix(web): show server update progress through reconnect (#4903)
t3dotgg Jul 30, 2026
4b71a2a
feat(search): find threads by conversation content (#4959)
t3dotgg Jul 30, 2026
50871eb
fix: marketing site Vercel builds no longer die after ~100 deploys (#…
t3dotgg Jul 30, 2026
9dd425b
docs: split user and maintainer docs, fix 100+ stale claims (#4807)
t3dotgg Jul 30, 2026
96ee60b
Merge remote-tracking branch 'origin/main' into claude/sync-2026-07-30
NoahHendrickson Jul 30, 2026
9ed9031
fix(fork): absorb the v0.0.31 sync's new icons and renamed test carrier
NoahHendrickson Jul 30, 2026
cb9c84d
fix(fork): protect the terminalSlot port and correct sync-review find…
NoahHendrickson Jul 31, 2026
ae92b55
docs(fork): fix T3 Connect reference
NoahHendrickson Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .fork/customizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@
a fenced per-test timeout raise rather than a product change, because the
underlying cost is upstream's to fix and diverging in hot upstream logic
buys a conflict on every sync. Current carrier:
stashImageCompression.test.ts's give-up path (~15 encodes of an 8 MB stub
imageCompression.test.ts's give-up path (~15 encodes of an 8 MB stub
through chunked base64 — deterministic work, not flake). No guard asserts
these hunks; losing one turns CI red by itself, which is the enforcement.
tier: 4
files: []
shadows: []
watch:
- .github/workflows/ci.yml
- apps/web/src/lib/stashImageCompression.test.ts
- apps/web/src/lib/imageCompression.test.ts
verify:
- apps/web/src/__fork_guards__/ciRunners.test.ts

Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ jobs:
cache: true
run-install: true

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt

- name: Ensure Electron runtime is installed
run: vp run --filter @t3tools/desktop ensure:electron

Expand All @@ -49,6 +54,9 @@ jobs:
- name: Typecheck
run: vpr typecheck

- name: Check resource monitor formatting
run: cargo fmt --manifest-path native/resource-monitor/Cargo.toml -- --check

- name: Build desktop pipeline
run: vp run build:desktop

Expand All @@ -75,12 +83,18 @@ jobs:
cache: true
run-install: true

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Ensure Electron runtime is installed
run: vp run --filter @t3tools/desktop ensure:electron

- name: Test
run: vp run test

- name: Test resource monitor
run: cargo test --locked --manifest-path native/resource-monitor/Cargo.toml

mobile_native_static_analysis:
name: Mobile Native Static Analysis
# fork:begin ci-runners — see .fork/customizations.yaml#ci-runners
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,21 +331,29 @@ jobs:
platform: mac
target: dmg
arch: arm64
rust_target: aarch64-apple-darwin
resource_key: darwin-arm64
- label: macOS x64
runner: blacksmith-12vcpu-macos-26
platform: mac
target: dmg
arch: x64
rust_target: x86_64-apple-darwin
resource_key: darwin-x64
- label: Linux x64
runner: blacksmith-32vcpu-ubuntu-2404
platform: linux
target: AppImage
arch: x64
rust_target: x86_64-unknown-linux-gnu
resource_key: linux-x64
- label: Windows x64
runner: blacksmith-32vcpu-windows-2025
platform: win
target: nsis
arch: x64
rust_target: x86_64-pc-windows-msvc
resource_key: win32-x64
# - label: Windows arm64
# runner: windows-11-arm
# platform: win
Expand All @@ -365,6 +373,11 @@ jobs:
cache: true
run-install: true

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust_target }}

- name: Download relay client tracing config
uses: actions/download-artifact@v8
with:
Expand Down Expand Up @@ -603,13 +616,33 @@ jobs:
# done
# fi

- name: Collect resource monitor
shell: bash
run: |
set -euo pipefail
binary_name="t3-resource-monitor"
if [[ "${{ matrix.platform }}" == "win" ]]; then
binary_name="${binary_name}.exe"
fi
source_path="native/resource-monitor/target/${{ matrix.rust_target }}/release/${binary_name}"
target_dir="resource-monitor-publish/${{ matrix.resource_key }}"
mkdir -p "$target_dir"
cp "$source_path" "$target_dir/$binary_name"

- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: desktop-${{ matrix.platform }}-${{ matrix.arch }}
path: release-publish/*
if-no-files-found: error

- name: Upload resource monitor
uses: actions/upload-artifact@v7
with:
name: resource-monitor-${{ matrix.resource_key }}
path: resource-monitor-publish/${{ matrix.resource_key }}/*
if-no-files-found: error

publish_cli:
name: Publish CLI to npm
needs: [preflight, relay_public_config, build]
Expand Down Expand Up @@ -664,6 +697,24 @@ jobs:
- name: Build CLI package
run: vp run --filter t3 build

- name: Download resource monitors
uses: actions/download-artifact@v8
with:
pattern: resource-monitor-*
path: ${{ runner.temp }}/resource-monitors

- name: Bundle resource monitors into CLI package
shell: bash
run: |
set -euo pipefail
for artifact_dir in "$RUNNER_TEMP"/resource-monitors/resource-monitor-*; do
resource_key="${artifact_dir##*/resource-monitor-}"
target_dir="apps/server/dist/resource-monitor/${resource_key}"
mkdir -p "$target_dir"
cp "$artifact_dir"/t3-resource-monitor* "$target_dir/"
chmod +x "$target_dir"/t3-resource-monitor 2>/dev/null || true
done

- name: Publish CLI package
run: node apps/server/scripts/cli.ts publish --tag "${{ needs.preflight.outputs.cli_dist_tag }}" --app-version "${{ needs.preflight.outputs.version }}" --verbose

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dist-electron/
.showcase/
apps/mobile/.showcase/
artifacts/app-store/screenshots/
native/**/target/
node_modules/
.alchemy/
*.log
Expand Down
2 changes: 1 addition & 1 deletion .macroscope/check-run-agents/effect-service-conventions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Effect Service Conventions
model: claude-opus-4-8
model: claude-opus-5
effort: high
input: full_diff
tools:
Expand Down
27 changes: 18 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ T3 Code has 3 key app surfaces: **web**, **desktop**, and **mobile**.

**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.

**Mobile** is a React native app for both iOS and Android. The mobile app allows for connecting to any T3 Code server to control work remotely. It is still in early access (Testflight), but it is pretty close to shipping globally.
**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.

## A note from Theo

Expand Down Expand Up @@ -72,7 +72,7 @@ We need to be on the same page with terminology. When communicating, use this la
## The three ways to hurt yourself

1. **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.
2. **Touching the live install.** `~/.t3/userdata` is the developer's real T3 Code database, in use while you work. Read-only inspection is fine. Never start a server against it, never open it read-write, never clean it up.
2. **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.
3. **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.

## Hit every surface
Expand All @@ -85,7 +85,7 @@ The most common defect in this repo is a change that works on the path you teste
- **Contracts.** Anything crossing the wire is typed in `packages/contracts`. Change the schema and the server, web, mobile, and desktop all follow.
- **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.
- **Connection modes.** Local, remote/relay, and tunnel behave differently. Multi-device and multi-environment cases are real.
- **Docs.** `docs/` mirrors this structure. Behavior changes that a user would notice belong in `docs/user/`; architecture changes in `docs/architecture/`; new vocabulary in `docs/reference/encyclopedia.md`.
- **Docs.** `docs/` splits by audience. Behavior changes that a user would notice belong in `docs/user/` (shipped-product voice, no repo tooling or source paths); architecture and contributor changes in `docs/internals/`; runbooks in `docs/operations/`; new vocabulary in `docs/internals/glossary.md`.

## Dev servers

Expand All @@ -98,10 +98,19 @@ The most common defect in this repo is a change that works on the path you teste

## Test data

An empty database is a bad test. Seed your worktree's `.t3` instead of pointing at live state:
An empty database is a bad test. Seed your worktree's `.t3` with a copy of real data instead of pointing at live state:

- Copy from `~/.t3/userdata` (the developer's real data, the most realistic test set) or `~/.t3/dev`. Worktree state lives at `<worktree>/.t3/userdata`.
- Snapshot the database with `VACUUM INTO`, which is safe even while a server has the source open and yields one consistent file:

```bash
mkdir -p .t3/userdata
rm -f .t3/userdata/state.sqlite* # VACUUM INTO refuses to overwrite
bun -e "new (require('bun:sqlite').Database)(process.env.HOME + '/.t3/userdata/state.sqlite', { readonly: true }).run(\"VACUUM INTO '.t3/userdata/state.sqlite'\")"
```

A plain `cp` is only safe when no server has the source open, and must bring the `-wal` and `-shm` siblings along. A live file copy is a corrupt copy.

- Copy from `~/.t3/dev`, never from `~/.t3/userdata`.
- Copy `state.sqlite` together with its `-wal` and `-shm` siblings, and only while no server has the source open. A live copy is a corrupt copy.
- Bring `secrets` and `settings.json` only if the flow under test needs them.
- Copy in, never symlink. Data flows one way: into your sandbox, never back out.

Expand All @@ -127,13 +136,13 @@ An empty database is a bad test. Seed your worktree's `.t3` instead of pointing

Clients send typed WebSocket requests. The server turns them into _commands_, a pure _decider_ turns commands into persisted _events_, and a _projector_ derives the read model the UI renders. Provider CLIs run as subprocesses; per-provider _adapters_ translate their native protocols into orchestration events. Side effects run in queue-backed _reactors_ that emit _receipts_ when milestones land. Each turn ends with a _checkpoint_, a hidden git ref, so the app can diff and restore.

Full glossary with file links: `docs/reference/encyclopedia.md`
Full glossary with file links: `docs/internals/glossary.md`

## Where code lives

- `apps/server` - WebSocket, orchestration, providers, checkpointing. Effect-heavy: read `.repos/effect-smol/LLMS.md` and `docs/operations/effect-fn-checklist.md` before writing Effect code.
- `apps/server` - WebSocket, orchestration, providers, checkpointing. Effect-heavy: read `.repos/effect-smol/LLMS.md` before writing Effect code.
- `apps/web` - React/Vite UI. `apps/desktop` wraps it, `apps/mobile` is React Native, `apps/marketing` is the site.
- `packages/contracts` - Effect/Schema contracts. Schema only, no runtime logic.
- `packages/contracts` - Effect/Schema contracts plus small derived helpers. No heavy runtime logic.
- `packages/shared` - shared runtime utils, subpath exports, no barrel.
- `packages/client-runtime` - client code shared by web and mobile.
- `.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.
Expand Down
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# T3 Code

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).
T3 Code is an "agent harness control surface". It enables control of the agents on your machine with a best-in-class mobile app ([iOS](https://apps.apple.com/us/app/t3-code-remote-claude-more/id6787819824), [Android](https://play.google.com/store/apps/details?id=com.t3tools.t3code)), [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.

Expand All @@ -17,13 +17,13 @@ We wanted something performant, remote-ready, and truly open. If we ever go the
>
> - 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`
> - Cursor: install [Cursor CLI](https://cursor.com/cli) and run `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`

### Try it out (install-free)

The easiest way to test T3 Code is to run the server in your terminal:
The easiest way to test T3 Code is to run the server in your terminal (requires Node.js 22.16+, 23.11+, or 24.10+):

```bash
npx t3@latest
Expand Down Expand Up @@ -61,17 +61,20 @@ We are very very early in this project. Expect bugs.

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).

## Documentation

- [Getting started](./docs/getting-started/quick-start.md)
- [Remote access](./docs/user/remote-access.md)
- [Keeping T3 Code in sync](./docs/user/server-updates.md)
- [Architecture overview](./docs/architecture/overview.md)
- [Provider guides](./docs/providers/codex.md)
- [Operations](./docs/operations/ci.md)
- [Reference](./docs/reference/encyclopedia.md)
Full docs live in [docs/](./docs). There's no docs site yet.

- [Install and first run](./docs/user/install.md)
- [Permission modes](./docs/user/permission-modes.md)
- [Keyboard shortcuts](./docs/user/keybindings.md)
- [Remote access from a phone or another machine](./docs/user/remote-access.md)
- [Keeping app and server in sync](./docs/user/updating.md)
- [Source control integrations](./docs/user/source-control.md)
- Multiple accounts: [Codex](./docs/user/providers-codex.md) · [Claude](./docs/user/providers-claude.md)
- Linux: [run T3 Code as a background service](./docs/user/background-service.md)

Building from source? Start at [docs/internals/overview.md](./docs/internals/overview.md).

## If you REALLY want to contribute still.... read this first

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@t3tools/desktop",
"version": "0.0.30",
"version": "0.0.31",
"private": true,
"type": "module",
"main": "dist-electron/main.cjs",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/app/DesktopAppIdentity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const makeElectronAppLayer = (calls: ElectronAppCalls) =>
}),
setAppUserModelId: () => Effect.void,
requestSingleInstanceLock: Effect.succeed(true),
getAppMetrics: Effect.succeed([]),
isDefaultProtocolClient: () => Effect.succeed(false),
setAsDefaultProtocolClient: () => Effect.succeed(true),
setDesktopName: () => Effect.void,
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/app/DesktopLifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe("DesktopLifecycle", () => {
setAboutPanelOptions: () => Effect.void,
setAppUserModelId: () => Effect.void,
requestSingleInstanceLock: Effect.succeed(true),
getAppMetrics: Effect.succeed([]),
isDefaultProtocolClient: () => Effect.succeed(false),
setAsDefaultProtocolClient: () => Effect.succeed(true),
setDesktopName: () => Effect.void,
Expand Down
Loading
Loading