Skip to content

Commit 883489c

Browse files
juliusmarmingecodex
andcommitted
Merge origin/main into t3code/turn-completion-invalidation
Co-authored-by: codex <codex@users.noreply.github.com>
2 parents 85ed747 + 5b3b31b commit 883489c

248 files changed

Lines changed: 30024 additions & 7288 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/devcontainer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "T3 Code Dev",
3+
"image": "debian:bookworm",
4+
"features": {
5+
"ghcr.io/devcontainers-extra/features/bun:1": {},
6+
"ghcr.io/devcontainers/features/node:1": {
7+
"version": "24",
8+
"nodeGypDependencies": true
9+
},
10+
"ghcr.io/devcontainers/features/python:1": {
11+
"version": "3.12"
12+
}
13+
},
14+
"postCreateCommand": {
15+
"bun-install": "bun install --backend=copyfile --frozen-lockfile"
16+
},
17+
"customizations": {
18+
"vscode": {
19+
"extensions": ["oxc.oxc-vscode"]
20+
}
21+
}
22+
}

.docs/remote-architecture.md

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
# Remote Architecture
2+
3+
This document describes the target architecture for first-class remote environments in T3 Code.
4+
5+
It is intentionally architecture-first. It does not define a complete implementation plan or user-facing rollout checklist. The goal is to establish the core model so remote support can be added without another broad rewrite.
6+
7+
## Goals
8+
9+
- Treat remote environments as first-class product primitives, not special cases.
10+
- Support multiple ways to reach the same environment.
11+
- Keep the T3 server as the execution boundary.
12+
- Let desktop, mobile, and web all share the same conceptual model.
13+
- Avoid introducing a local control plane unless product pressure proves it is necessary.
14+
15+
## Non-goals
16+
17+
- Replacing the existing WebSocket server boundary with a custom transport protocol.
18+
- Making SSH the only remote story.
19+
- Syncing provider auth across machines.
20+
- Shipping every access method in the first iteration.
21+
22+
## High-level architecture
23+
24+
T3 already has a clean runtime boundary: the client talks to a T3 server over HTTP/WebSocket, and the server owns orchestration, providers, terminals, git, and filesystem operations.
25+
26+
Remote support should preserve that boundary.
27+
28+
```text
29+
┌──────────────────────────────────────────────┐
30+
│ Client (desktop / mobile / web) │
31+
│ │
32+
│ - known environments │
33+
│ - connection manager │
34+
│ - environment-aware routing │
35+
└───────────────┬──────────────────────────────┘
36+
37+
│ resolves one access endpoint
38+
39+
┌───────────────▼──────────────────────────────┐
40+
│ Access method │
41+
│ │
42+
│ - direct ws / wss │
43+
│ - tunneled ws / wss │
44+
│ - desktop-managed ssh bootstrap + forward │
45+
└───────────────┬──────────────────────────────┘
46+
47+
│ connects to one T3 server
48+
49+
┌───────────────▼──────────────────────────────┐
50+
│ Execution environment = one T3 server │
51+
│ │
52+
│ - environment identity │
53+
│ - provider state │
54+
│ - projects / threads / terminals │
55+
│ - git / filesystem / process runtime │
56+
└──────────────────────────────────────────────┘
57+
```
58+
59+
The important decision is that remoteness is expressed at the environment connection layer, not by splitting the T3 runtime itself.
60+
61+
## Domain model
62+
63+
### ExecutionEnvironment
64+
65+
An `ExecutionEnvironment` is one running T3 server instance.
66+
67+
It is the unit that owns:
68+
69+
- provider availability and auth state
70+
- model availability
71+
- projects and threads
72+
- terminal processes
73+
- filesystem access
74+
- git operations
75+
- server settings
76+
77+
It is identified by a stable `environmentId`.
78+
79+
This is the shared cross-client primitive. Desktop, mobile, and web should all reason about the same concept here.
80+
81+
### KnownEnvironment
82+
83+
A `KnownEnvironment` is a client-side saved entry for an environment the client knows how to reach.
84+
85+
It is not server-authored. It is local to a device or client profile.
86+
87+
Examples:
88+
89+
- a saved LAN URL
90+
- a saved public `wss://` endpoint
91+
- a desktop-managed SSH host entry
92+
- a saved tunneled environment
93+
94+
A known environment may or may not know the target `environmentId` before first successful connect.
95+
96+
### AccessEndpoint
97+
98+
An `AccessEndpoint` is one concrete way to reach a known environment.
99+
100+
This is the key abstraction that keeps SSH from taking over the model.
101+
102+
A single environment may have many endpoints:
103+
104+
- `wss://t3.example.com`
105+
- `ws://10.0.0.25:3773`
106+
- a tunneled relay URL
107+
- a desktop-managed SSH tunnel that resolves to a local forwarded WebSocket URL
108+
109+
The environment stays the same. Only the access path changes.
110+
111+
### RepositoryIdentity
112+
113+
`RepositoryIdentity` remains a best-effort logical repo grouping mechanism across environments.
114+
115+
It is not used for routing. It is only used for UI grouping and correlation between local and remote clones of the same repository.
116+
117+
### Workspace / Project
118+
119+
The current `Project` model remains environment-local.
120+
121+
That means:
122+
123+
- a local clone and a remote clone are different projects
124+
- they may share a `RepositoryIdentity`
125+
- threads still bind to one project in one environment
126+
127+
## Access methods
128+
129+
Access methods answer one question:
130+
131+
How does the client speak WebSocket to a T3 server?
132+
133+
They do not answer:
134+
135+
- how the server got started
136+
- who manages the server process
137+
- whether the environment is local or remote
138+
139+
### 1. Direct WebSocket access
140+
141+
Examples:
142+
143+
- `ws://10.0.0.15:3773`
144+
- `wss://t3.example.com`
145+
146+
This is the base model and should be the first-class default.
147+
148+
Benefits:
149+
150+
- works for desktop, mobile, and web
151+
- no client-specific process management required
152+
- best fit for hosted or self-managed remote T3 deployments
153+
154+
### 2. Tunneled WebSocket access
155+
156+
Examples:
157+
158+
- public relay URLs
159+
- private network relay URLs
160+
- local tunnel products such as pipenet
161+
162+
This is still direct WebSocket access from the client's perspective. The difference is that the route is mediated by a tunnel or relay.
163+
164+
For T3, tunnels are best modeled as another `AccessEndpoint`, not as a different kind of environment.
165+
166+
This is especially useful when:
167+
168+
- the host is behind NAT
169+
- inbound ports are unavailable
170+
- mobile must reach a desktop-hosted environment
171+
- a machine should be reachable without exposing raw LAN or public ports
172+
173+
### 3. Desktop-managed SSH access
174+
175+
SSH is an access and launch helper, not a separate environment type.
176+
177+
The desktop main process can use SSH to:
178+
179+
- reach a machine
180+
- probe it
181+
- launch or reuse a remote T3 server
182+
- establish a local port forward
183+
184+
After that, the renderer should still connect using an ordinary WebSocket URL against the forwarded local port.
185+
186+
This keeps the renderer transport model consistent with every other access method.
187+
188+
## Launch methods
189+
190+
Launch methods answer a different question:
191+
192+
How does a T3 server come to exist on the target machine?
193+
194+
Launch and access should stay separate in the design.
195+
196+
### 1. Pre-existing server
197+
198+
The simplest launch method is no launch at all.
199+
200+
The user or operator already runs T3 on the target machine, and the client connects through a direct or tunneled WebSocket endpoint.
201+
202+
This should be the first remote mode shipped because it validates the environment model with minimal extra machinery.
203+
204+
### 2. Desktop-managed remote launch over SSH
205+
206+
This is the main place where Zed is a useful reference.
207+
208+
Useful ideas to borrow from Zed:
209+
210+
- remote probing
211+
- platform detection
212+
- session directories with pid/log metadata
213+
- reconnect-friendly launcher behavior
214+
- desktop-owned connection UX
215+
216+
What should be different in T3:
217+
218+
- no custom stdio/socket proxy protocol between renderer and remote runtime
219+
- no attempt to make the remote runtime look like an editor transport
220+
- keep the final client-to-server connection as WebSocket
221+
222+
The recommended T3 flow is:
223+
224+
1. Desktop connects over SSH.
225+
2. Desktop probes the remote machine and verifies T3 availability.
226+
3. Desktop launches or reuses a remote T3 server.
227+
4. Desktop establishes local port forwarding.
228+
5. Renderer connects to the forwarded WebSocket endpoint as a normal environment.
229+
230+
### 3. Client-managed local publish
231+
232+
This is the inverse of remote launch: a local T3 server is already running, and the client publishes it through a tunnel.
233+
234+
This is useful for:
235+
236+
- exposing a desktop-hosted environment to mobile
237+
- temporary remote access without changing router or firewall settings
238+
239+
This is still a launch concern, not a new environment kind.
240+
241+
## Why access and launch must stay separate
242+
243+
These concerns are easy to conflate, but separating them prevents architectural drift.
244+
245+
Examples:
246+
247+
- A manually hosted T3 server might be reached through direct `wss`.
248+
- The same server might also be reachable through a tunnel.
249+
- An SSH-managed server might be launched over SSH but then reached through forwarded WebSocket.
250+
- A local desktop server might be published through a tunnel for mobile.
251+
252+
In all of those cases, the `ExecutionEnvironment` is the same kind of thing.
253+
254+
Only the launch and access paths differ.
255+
256+
## Security model
257+
258+
Remote support must assume that some environments will be reachable over untrusted networks.
259+
260+
That means:
261+
262+
- remote-capable environments should require explicit authentication
263+
- tunnel exposure should not rely on obscurity
264+
- client-saved endpoints should carry enough auth metadata to reconnect safely
265+
266+
T3 already supports a WebSocket auth token on the server. That should become a first-class part of environment access rather than remaining an incidental query parameter convention.
267+
268+
For publicly reachable environments, authenticated access should be treated as required.
269+
270+
## Relationship to Zed
271+
272+
Zed is a useful reference implementation for managed remote launch and reconnect behavior.
273+
274+
The relevant lessons are:
275+
276+
- remote bootstrap should be explicit
277+
- reconnect should be first-class
278+
- connection UX belongs in the client shell
279+
- runtime ownership should stay clearly on the remote host
280+
281+
The important mismatch is transport shape.
282+
283+
Zed needs a custom proxy/server protocol because its remote boundary sits below the editor and project runtime.
284+
285+
T3 should not copy that part.
286+
287+
T3 already has the right runtime boundary:
288+
289+
- one T3 server per environment
290+
- ordinary HTTP/WebSocket between client and environment
291+
292+
So T3 should borrow Zed's launch discipline, not its transport protocol.
293+
294+
## Recommended rollout
295+
296+
1. First-class known environments and access endpoints.
297+
2. Direct `ws` / `wss` remote environments.
298+
3. Authenticated tunnel-backed environments.
299+
4. Desktop-managed SSH launch and forwarding.
300+
5. Multi-environment UI improvements after the base runtime path is proven.
301+
302+
This ordering keeps the architecture network-first and transport-agnostic while still leaving room for richer managed remote flows.

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
quality:
1111
name: Format, Lint, Typecheck, Test, Browser Test, Build
1212
runs-on: blacksmith-4vcpu-ubuntu-2404
13+
timeout-minutes: 10
1314
steps:
1415
- name: Checkout
1516
uses: actions/checkout@v6
@@ -71,11 +72,12 @@ jobs:
7172
- name: Verify preload bundle output
7273
run: |
7374
test -f apps/desktop/dist-electron/preload.js
74-
grep -nE "desktopBridge|getWsUrl|PICK_FOLDER_CHANNEL|wsUrl" apps/desktop/dist-electron/preload.js
75+
grep -nE "desktopBridge|getLocalEnvironmentBootstrap|PICK_FOLDER_CHANNEL|wsUrl" apps/desktop/dist-electron/preload.js
7576
7677
release_smoke:
7778
name: Release Smoke
7879
runs-on: ubuntu-24.04
80+
timeout-minutes: 10
7981
steps:
8082
- name: Checkout
8183
uses: actions/checkout@v6

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
preflight:
2020
name: Preflight
2121
runs-on: ubuntu-24.04
22+
timeout-minutes: 10
2223
outputs:
2324
version: ${{ steps.release_meta.outputs.version }}
2425
tag: ${{ steps.release_meta.outputs.tag }}
@@ -81,6 +82,7 @@ jobs:
8182
name: Build ${{ matrix.label }}
8283
needs: preflight
8384
runs-on: ${{ matrix.runner }}
85+
timeout-minutes: 30
8486
strategy:
8587
fail-fast: false
8688
matrix:
@@ -227,6 +229,7 @@ jobs:
227229
name: Publish CLI to npm
228230
needs: [preflight, build]
229231
runs-on: ubuntu-24.04
232+
timeout-minutes: 10
230233
steps:
231234
- name: Checkout
232235
uses: actions/checkout@v6
@@ -260,6 +263,7 @@ jobs:
260263
name: Publish GitHub Release
261264
needs: [preflight, build, publish_cli]
262265
runs-on: ubuntu-24.04
266+
timeout-minutes: 10
263267
steps:
264268
- name: Checkout
265269
uses: actions/checkout@v6
@@ -307,6 +311,7 @@ jobs:
307311
name: Finalize release
308312
needs: [preflight, release]
309313
runs-on: ubuntu-24.04
314+
timeout-minutes: 10
310315
steps:
311316
- id: app_token
312317
name: Mint release app token

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ apps/web/src/components/__screenshots__
2121
.vitest-*
2222
__screenshots__/
2323
.tanstack
24+
squashfs-root/

0 commit comments

Comments
 (0)