Where the Work Lives: Environment Ownership
This chapter examines the most important boundary in T3 Code: the environment that owns the workspace, rather than the client showing it. The practical goal is to trace an agent action—from a provider process or terminal to files, Git, and durable thread state—and then see why web, desktop, and mobile clients can remain replaceable views of that reality. Once this ownership model is clear, remote access becomes easier to reason about: changing the route to a machine does not change which machine is responsible for the work.
One environment, many kinds of state
An “environment” in T3 Code is not simply a URL or a server port. It is a running server together with the machine, credentials, workspace access, and state that the server owns. That definition matters because coding agents do not operate on conversation text alone. They need a current directory, project files, installed tools, provider authentication, terminals, and often Git credentials. Those resources have to belong somewhere, and T3 Code puts them on the environment side of the boundary.
The server therefore owns the provider processes that perform agent work, the terminals through which commands run, Git operations, and project files. It also owns durable state such as threads and their work history. A client can ask the server to start a turn, display a terminal, change a setting, or show a diff, but the client is not the authority that decides which file exists or which provider account is available. The request travels to the environment that owns those resources.
That rule is easy to miss when using a desktop application, because the desktop app can bundle a server. Packaging makes the two components feel like one product, but it does not change their responsibilities. The renderer is still a client of the server boundary. The same is true when the client is a browser or a phone: the screen may be close to the user while the process and files remain elsewhere.
Consider a simple task: ask an agent to update a configuration file and run the test suite. The file change is made in the environment’s workspace. The test runs in a terminal owned by that environment. The provider credentials used to authorize the agent are those configured on that machine. If the user later opens the thread from a phone, the phone is not expected to reproduce any of those conditions locally. It requests the environment’s state and displays the result.
This is more than a convenient division of labor. If clients were allowed to maintain their own competing copies of provider sessions or workspace state, a reconnect would create an ambiguous question: which copy reflects reality? By assigning execution and durable state to the environment, T3 Code gives every client the same answer. The client can be replaced; the environment remains the reference point.
The client is a view, not a second workshop
T3 Code has several surfaces because different contexts call for different controls. A desktop window is useful when the user is actively editing or reviewing. A web client can provide access from a browser. A mobile client is useful for monitoring a long-running task, answering an agent’s question, or sending a follow-up away from the workstation. These surfaces differ in layout and platform services, but the underlying relationship is the same: they control an environment over authenticated RPC.
The desktop case makes the boundary especially visible. A desktop app normally starts its local environment, but it can also be configured as remote-only. In that mode, the local server, local agents, terminals, and WSL backends stay off while saved remote connections remain available. The computer is still running a T3 Code client, but it is no longer being treated as the place where the work must happen. That is a useful test of the architecture: if the renderer can operate without a local environment, the renderer cannot be the source of execution truth.
The repository reinforces this separation in its structure. The server, web app, desktop app, mobile app, and shared packages have distinct development and build boundaries. That fact alone does not prove how fast any surface is or how complete its feature set is, but it shows the product is designed as a set of clients and shared runtime pieces around server-owned behavior, not as one monolithic screen with a different skin for each device.
A shared client runtime is what keeps the boundary usable. The web client, desktop renderer, and mobile client share one connection owner per environment. Instead of allowing every view to invent its own retry loop, the runtime gives transport retry policy to a single supervisor. That supervisor can retry transient failures with backoff and jitter, while waiting for a meaningful wake-up when the problem is an offline condition or an authentication failure that has not changed.
The distinction between transport and data is crucial. A socket can be open while a thread or shell subscription is still catching up, stale, or unavailable. Conversely, cached projections can remain readable while the live connection is down. T3 Code therefore treats “the network connection exists” and “this particular data is current” as different facts. A user looking at a cached thread should not be told that they are watching live work merely because the client process is open.
This design also explains why reconnection is not the same as replaying every action. Durable subscriptions can follow a replacement session, and cached state can be resumed from a snapshot and cursor. Mutations, however, are not blindly repeated after a transport failure. Repeating a command such as “publish this change” could create a second side effect if the first request succeeded but its response was lost. The runtime leaves retry and idempotency to the operation that understands what the command means.
The connection lifecycle has another useful separation: being registered is not the same as being actively connected. An involuntary disconnect can leave an environment registration and cached data in place so that a client can try again. Explicitly removing an environment is stronger: it closes that scope and clears credentials, projections, and platform-owned state such as drafts. This difference respects user intent. A temporary network failure should not erase the relationship, while a deliberate removal should not leave an old client scope quietly alive.
The same principle applies before a connection is considered ready. Opening a socket is only the transport step. The shared runtime waits for the environment’s initial configuration, and thread or shell data can have their own synchronization state. A client that has reached the server but has not received the data needed for a view should not claim that the view is current. This is a small but important form of honesty: the interface reports what it knows, not merely that a network handshake succeeded.
Endpoint selection also remains a client-side fact, not a new identity for the server. An address advertised by an environment is a reachability hint; only the device making the connection can prove that the route works. A loopback address that is correct on the host refers to the connecting device when opened elsewhere. The client must not silently fall back to a loopback endpoint when a shareable route is unavailable, because that would turn an inability to reach the intended environment into a misleading connection attempt against the wrong machine.
The model has an important asymmetry. The client depends on the environment for state, but the environment does not depend on one particular client staying open. A thread can continue to exist after a browser closes. A server-side process can retain terminal output for a later connection. A project remains tied to its environment even when the user changes devices. This asymmetry is what makes a control surface useful for work that lasts longer than one interaction.
Identity and scope keep work from drifting
If an environment were identified only by its current endpoint, changing from a LAN address to T3 Connect or SSH could look like moving to a new machine. T3 Code keeps environment identity independent of the route used to reach it. The same environment can be reached through different endpoints while retaining its identity and durable state. The client’s saved connection is local to that client profile; it is not the environment itself.
Projects and threads remain environment-local. A repository identity can help correlate clones, but it does not silently route a thread from one environment to another. This matters when a person has a laptop, a desktop workstation, and a remote server that all contain related repositories. Similar names or matching remotes do not make their workspaces interchangeable. The task belongs to the environment where its thread and checkout were created.
Settings follow the same logic. Preferences that describe the current device—such as appearance—can stay local. Environment defaults and project overrides belong to the server that will use them. A selected project can override an environment default, while a repository declaration such as t3.json can provide a lower-priority value. The result is a chain of ownership rather than a single global switch.
This layering solves a subtle problem. Suppose a user connects a browser to two machines and chooses a permission default while viewing one project. If that choice were treated as a universal client preference, it could silently change the policy for work on the other machine. Instead, T3 Code makes the target environment and project part of the setting’s meaning. “All environments” is an explicit bulk edit of connected, loaded servers, not a promise that offline or future machines will synchronize later.
The same care appears in resource selection. When load balancing is enabled, it helps choose an environment for a new thread among eligible machines. Existing threads stay where they started. A draft can be assigned to a particular machine or retain a selected branch/worktree relationship. This avoids a dangerous form of convenience in which an old thread silently moves because a different server currently has more capacity.
The ownership model is also not a claim that a project name creates a new operating-system boundary. A project organizes a workspace, thread history, provider choices, and settings within an environment; it does not turn the client into an independent host or make provider credentials portable between machines. The environment remains the meaningful unit for files, tools, authentication, and server-side capabilities. Project scope makes those resources easier to manage; it does not replace the host’s permissions or lifecycle.
That boundary produces a useful rule for interpreting any T3 Code feature: ask where the state is authoritative and which environment will perform the side effect. A provider setting is about the machine that launches the provider. A terminal is about the server that owns the PTY. A Git action is about the environment with the repository and credentials. A thread view is about the durable record held by the environment, even if the view is currently on a phone.
This rule also explains why the next problem is not simply “how do I connect?” The harder question is how a route proves that it reaches the intended environment and what that environment allows the connected client to do. Remote access extends the ownership model only when reachability and authorization remain separate.