Skip to content

Latest commit

 

History

History
104 lines (82 loc) · 6.76 KB

File metadata and controls

104 lines (82 loc) · 6.76 KB

Architecture

T3 Code keeps execution in the environment that owns the workspace. Web, desktop, and mobile clients control it over authenticated RPC. A remote client must never substitute its own filesystem, provider credentials, or machine state for the environment's. The desktop app bundles a server, but its renderer follows the same boundary.

Ownership boundaries

Provider processes, terminals, Git, and project files belong to the server. Shared connection and domain state belongs in packages/client-runtime; clients supply platform services and UI. Keeping that logic shared prevents reconnect and multi-environment behavior from diverging between web and mobile. See connection runtime and remote environments.

The RPC contract is the boundary between independently versioned clients and servers. Subscriptions send the state a client needs, so a client viewing one thread does not pay for every thread's history. Authentication of a socket does not authorize every method on it. See environment auth.

Pull request linking compatibility

Web, desktop, mobile, and environments upgrade independently. Negotiate linking through the environment descriptor, never through a client version or an assumed coordinated release:

Environment capability Client behavior
threadPullRequests: true Use persisted pullRequests[], multi-link commands, stack UI, and reverse thread lookup.
Only threadPullRequestLinking: true Use linkedPullRequest and the existing thread.meta.update single-link operation. Do not call multi-link RPCs.
Neither flag Hide linking actions; existing branch-discovered PR display remains available.

New environments continue advertising the legacy flag, accepting legacy metadata commands, and emitting the derived linkedPullRequest field for older clients. That hostless field includes only links in the thread project's own repository; cross-host and cross-repository links require the multi-link protocol. New clients accept snapshots that omit pullRequests. Retain the legacy wire fields, projection column, and replay support; this feature does not schedule their removal. Missing new capabilities must also override cached multi-link data after an environment downgrade.

Provider-specific behavior belongs behind an adapter. Orchestration works with normalized commands and events, so adding a provider should not require branches throughout the domain or clients. See provider constraints.

Durable intent and side effects

The event log is the source of truth for orchestration state. The engine serializes commands; the decider produces events without performing provider or filesystem work. Events, persisted projections, and the accepted command receipt commit in one database transaction. The in-memory state changes and subscribers receive events after that commit. This keeps command retries idempotent and prevents a persisted projection from getting ahead of the event log.

Reactors perform side effects after intent has been recorded, then feed results back through commands. A command acknowledgement therefore means the intent committed, not that the provider, checkpoint, or other follow-up work finished. Keep external I/O out of the decider and the database transaction.

Persisted events must remain decodable on replay. Changing a schema affects old environments at startup as well as live RPC traffic. Compatibility work must account for stored history, not just what the newest client sends.

Turn completion and checkpoints

A turn ending and its follow-up work settling are separate milestones. The projector settles the turn from its session status. A late checkpoint or diff must not extend the recorded turn duration or keep the client showing provider work as active.

Checkpoints use hidden Git refs to capture workspace state without adding commits to the user's branch. A revert must coordinate workspace state with the provider conversation. A provider that cannot roll back its conversation must reject that operation before changing the filesystem.

Waiting for asynchronous work

Tests use drainable workers to wait until both the queue and its current item have finished. An empty queue alone does not prove the worker is idle.

Runtime receipts mark specific test milestones. Their production layer is a no-op; production behavior must use persisted state and events. These test signals are separate from the durable command receipts that make dispatch idempotent.

The Electron shell acquires DesktopPreReadyPlatform.layer synchronously before asynchronous services. On Linux this sets the desktop-entry identity and global-shortcut portal flags before Chromium initializes its portal connection. Setting the identity later in DesktopAppIdentity is too late: Chromium caches the first registration, including failures. The identity must match the installed entry managed by DesktopLinuxUrlHandler. Pre-ready setup also refreshes that entry's Exec path before portal registration: AppImage updates can remove the previous executable, which makes the old entry invalid even though its filename is correct. The later URL handler avoids rewriting an identical entry while the portal may be reading it. On Wayland, Electron's synchronous shortcut-registration result only confirms submission; it does not confirm desktop consent or an active binding.

Native modules never load in the Electron main process on the startup path, and the two the snapshot feature keeps are isolated: @crowecawcaw/xa11y runs only in forked Node-mode children (SnapShotAccessibilityWorker, RegionSnapShotWorker) and a worker thread, and ffi-rs loads lazily inside WindowsForeground.ts for a handful of Win32 calls. macOS window lookup shells out to osascript instead of a native addon. A crash or stall in any of these must not take the app down, so new native capability goes in a child with a deadline, not an import in main.

See the glossary for shared terms and the development runbook for setup and checks.