This is a maintainer and reviewer reference. For the user-facing explanation, start with Coder workspaces and Product decisions and upstream differences. To merge upstream, follow the upstream sync checklist.
T3 Coder runs its browser interface on the developer's computer while repository, Codex, Claude,
Pi, Kilo Code, terminal, checkpoint, and durable orchestration work stays inside Linux Coder workspaces. The
laptop runs only the loopback gateway, the Coder CLI, and a browser; AGENTS.md lists the
boundaries, and this document records how the code keeps them and where it departs from upstream.
The local process is a Node gateway that binds to an IPv4 loopback port and serves the web client to
a browser opened by the user. It reuses the port saved in gateway-port beside config.json when
that port is free, so browser storage keeps one origin across restarts; otherwise it binds an
ephemeral port and saves that. It stores only non-secret Coder deployment URLs, workspace targets,
structured port-forward rules, an optional Coder executable path, and the last gateway port. A
composer attachment stays in gateway memory while it is streamed to the workspace and is never
written to local disk by the gateway. The browser may store and cache what upstream does, except
credentials. Browser UI preferences
such as theme and panel size may use browser storage; as on main, uiStateStore keeps sidebar
project expansion, order, and scope, thread visit times, changed-file folder expansion, and the
last merge method there, and session storage holds main's one-reload guard for stale split chunks
(lib/chunkReloadGuard.ts). As on main, composer drafts and prompt stashes keep their text,
images, and upload ids in browser storage, and IndexedDB caches each
environment's shell, settled thread snapshots, server config, and full branch lists so a reload
renders before the workspace answers; the workspace remains the source of truth. Open Files tabs and
editor state and provider sessions are memory-only.
Each active workspace accepts one loopback WebSocket at a time. The workspace helper can outlive
that browser connection, so the gateway treats every accepted WebSocket as a distinct RPC session:
it translates browser-local request IDs to helper-lifetime unique IDs, restores the browser IDs on
responses, and interrupts every still-active request when the session detaches. A browser Eof
ends only that logical session and is not forwarded to the helper. If interrupted requests do not
terminate within five seconds, the gateway closes the helper instead of retaining unowned work.
The gateway translates frame-delimited browser RPC into newline-delimited helper RPC and does not
persist those application messages. While the helper's stdin is backed up, the gateway stops reading
browser frames until it drains, so a slow helper pushes back instead of growing gateway memory.
The browser estimates workspace latency by timing server.probe RPC round-trips over the
workspace's existing WebSocket session, so a sample covers the whole path the user's input takes:
browser, loopback gateway, and workspace helper. Sampling is adaptive — every five seconds per
connected workspace, every second after a high sample until the connection reads fast again — and
pauses while the browser tab is hidden, so no probe traffic occurs in the background. At most one
probe is in flight per workspace. The browser retains the last sample with a stale marker when
probes stop succeeding and shows a slow-connection warning only after consecutive high-latency
samples. The gateway exposes no latency endpoint and starts no ping process of its own.
The header's workspace health card shows Coder's workspace health from the status loop's
coder list --output json. While the card is open, the browser asks the connected helper for
CPU, memory, and home-disk usage every ten seconds over its existing RPC connection
(coder.workspaceResourceUsage). The helper runs Coder's coder stat commands in the workspace
and accepts only their fixed JSON result shape, so the laptop starts no process for it. Nothing
samples resources while the card is closed.
For every connected workspace, the gateway starts one foreground process through the authenticated
Coder CLI. The process runs a version-matched helper in the Linux workspace and carries T3's Effect
RPC envelopes as newline-delimited JSON over stdin and stdout. The helper has no HTTP server,
WebSocket server, or other listening socket. Closing the Coder connection stops the helper and any
active turn: the gateway sends the helper the gateway-only coder.helper.shutdown request, so the
helper exits and coder ssh closes its session itself (Coder's remote PTY never delivers
end-of-file, and on Windows a signal force-stops coder.exe), then escalates to SIGTERM and SIGKILL
one grace period apart (packages/coder-cli/src/processTermination.ts, shared by every Coder
child process). The helper launch switches the remote PTY to raw mode before its ready line and
reports a preflight failure if stty cannot. Reloading or temporarily disconnecting the browser does not stop the helper; the
gateway keeps it attached and reconnects the loopback WebSocket. If the helper or Coder SSH process
exits, the next browser connection runs preflight again and starts a fresh foreground helper.
Shell and thread subscriptions use upstream's optional requestCompletionMarker negotiation.
The helper advertises shellResumeCompletionMarker, threadResumeCompletionMarker, and
threadSnapshotPagination, and the browser requests the corresponding synchronized items.
Restored data stays in synchronizing state until the marker arrives, except for upstream's warm
resume behavior: a recently viewed live thread renders its retained snapshot immediately and only
shows synchronization progress if replay changes its contents. The marker follows buffered live
events accumulated during snapshot or replay loading. The browser and helper are built from the
same checkout; helper protocol version 3 remains the transport compatibility fence (version 3 adds
the gateway hub methods; see the linked-environments entry).
Live shell and thread subscriptions are bounded (LiveStreamBudget.ts), including batches awaiting
an RPC acknowledgement; overflow detaches that live source, and reconnect uses the existing
snapshot/replay and synchronization marker. Idle thread snapshots follow upstream's resume-snapshot
design with Coder's entry and size cap (threadRetention.ts), sized from string lengths so
navigating away never serializes large message bodies. Terminal attaches resume from an event
sequence when the helper's replay window still covers the gap. Thread snapshots and older pages
target bounded encoded sizes but always keep the newest requested turn; older pages use a unary
RPC on the existing connection. Review file snapshots stay in bounded helper memory
(ReviewService.ts) and are fetched only when the diff renderer expands omitted context; a file
above the expansion limit returns a typed tooLarge outcome rather than an RPC failure. GitLab
merge-request diffs are paged by file below the CODER_RPC_FRAME_MAX_BYTES frame. Migration
049 stores manual active-thread order in the workspace.
Branch-to-merge-request discovery is workspace-owned. The helper discovers GitLab MR links at startup, after relevant thread changes, and periodically without an open browser. It uses the existing repository-scoped GitManager cache and glab-backed MR service, verifies both the branch and project repository identity before saving, and rejects updates after the lookup inputs change. Migration 048 adds the branch MR projection independently of explicit links. Migration 050 adds multiple explicit MR links. Link commands validate the URL and its host against workspace GitLab metadata at the helper RPC boundary. The helper refreshes link snapshots and serves linked-thread lookups over the existing stdio connection. Recent MR summaries are cached beneath the workspace provider-status cache directory. Background summary reads are upstream's: one merge request detail read each. Settled-thread backfill has a bounded retry count. Inactivity settlement does not wait for an MR lookup.
Agents reach upstream's T3 toolkits over a workspace file bridge instead of MCP, because work
Claude Code and Codex policies block custom MCP servers. Each provider
session credential from upstream's McpSessionRegistry is a private directory under the temporary
directory, named t3-tools-<hash> from the environment and thread ids, holding a standalone CLI
(run with the helper's pinned Node runtime) and a read-only tool catalog; no socket, listener, or
MCP server is opened. The CLI writes one request per call into its own call directory,
and the helper runs the named tool through upstream's toolkit handlers with the credential's
thread identity, never one the agent supplies. Plan-mode threads may call only tools upstream marks
read-only. Requests and responses are bounded (FileBridge.ts). A call that outlives the inline
budget answers with a bridge-job: task id that task_status resolves, so long tools never depend
on a provider's shell timeout; the number of such calls per thread and the retention of unread
results are bounded (T3ToolBridge.ts). Upstream's lifecycle owns the bridges: credentials are reused across turns and
revoked, which deletes the directory, when the session is released, the thread is archived or
deleted, or the helper stops. The thread's next credential recreates the same directory, so a
command in the agent's history keeps working after its session rotates. Each bridge marks the
directory as its own and, once another helper in the workspace recreates it (the mark differs or
is gone), stops serving and leaves it in place; a call directory a killed CLI left behind is
removed once it is older than STALE_CALL_MS. If a bridge cannot be
created, turns run without T3 tools. Workspace processes run as the same OS user; these
directories are not an isolation boundary between mutually untrusted agents.
The bridge carries upstream's orchestrator, thread, attachment, project, environment, worktree,
pull-request, and html_render toolkits. The pull-request tools accept only merge requests on a
GitLab host that a workspace project uses; project clones go through the same GitLab-only repository
service as the browser. With no HTTP origin to upload to, t3_attachment_prepare_upload takes the
absolute workspace path of a file the agent already has and stores it as a pending upload in
process, so attachment bytes never pass through the bridge's request files. Attachments reach only
threads in the caller's own workspace: the attachment tools take no environmentId, as upstream's,
so a thread in a linked workspace answers thread_not_found, and an upload forwarded through the
gateway hub is refused because its path would name a file in the other workspace. Preview, device,
and html_preview toolkits are not carried, and neither is upstream's MCP HTTP server.
Thread settlement is workspace-owned. The helper's settlement reactor checks persisted workspace settings at startup, after relevant settings changes, and once per minute, including while no browser is connected. It resolves saved branches to GitLab merge requests without changing the checkout and dispatches a guarded internal settlement command through the normal orchestration engine. The engine rejects settlement if the thread changed after the reactor snapshot or still has live background work. Clients render the resulting persisted settlement state instead of deriving it from local timers or merge-request data.
T3 reads coder list --output json to distinguish stopped, starting, and running workspaces and to
report whether a template update is available. It does not implicitly connect to a stopped
workspace because Coder SSH would start it without an explicit user action. Starting, stopping,
restarting, or updating a workspace first closes its helper and active sessions and stops its saved
port forwards before invoking the corresponding Coder command through the same deployment-specific
CLI profile. A successful start, restart, or update restores the saved forwards and reconnects; a
successful stop leaves the helper and forwards stopped. The browser reports workspace
and port-forward status as unavailable when their status requests fail; it does not leave a request
checking indefinitely or retain a stale running label.
For an active start build, the browser surfaces Coder's current build deadline as an idle-stop
countdown. It also surfaces max_deadline, when present, as the absolute stop required by a template
policy. A stopped or non-start build never exposes either countdown. Status discovery
for starting or temporarily unavailable workspaces backs off from two to thirty seconds and retries
immediately when the browser becomes visible again. Stable workspace status refreshes once per
minute so deadline, health, and template-update state do not remain stale.
The gateway stores each workspace and saved forward in one tagged lifecycle state held by an Effect
SynchronizedRef (apps/coder-gateway/src/workspaceConnections.ts and portForwards.ts; the
states and claims are in lifecycleState.ts, and server.ts keeps the routes). Workspace connection and action claims, and port-forward start and stop claims,
are serialized transitions. Duplicate requests for the same workspace action share its result;
conflicting actions are rejected instead of being coalesced into a different command. Process exits
can update only the state that still owns that exact connection, so a late exit cannot overwrite a
newer start, stop, or restart transition.
The gateway keeps a bounded number (MAX_WORKSPACE_DIAGNOSTIC_EVENTS) of in-memory connection
phase events per workspace for preflight, helper
installation, helper negotiation, connection, and disconnection. Each attempt and phase duration is
visible in Settings and the active phase is shown on the reconnecting screen. This timeline is not
persisted and contains no command output or credentials.
Each saved port-forward rule starts a separate foreground coder port-forward process. The rule
contains only a configured workspace, TCP or UDP protocol, and validated local and remote ports. The
gateway always supplies 127.0.0.1 as the local bind address. It reports process state to the
settings UI, does not loop on failures, and stops the exact captured process when a rule changes, is
removed, or the gateway exits. A running forward's status adds ready once the process prints
Coder's Ready! line on stderr. The thread details card's Servers section saves the same rules
(see Web chat, composer, and files); its free-port check
(/api/port-forwards/free-port, at most MAX_LOCAL_PORT_CANDIDATES ports past the requested one)
binds and closes a probe listener on 127.0.0.1 only and opens no connection. On Windows a
specific-address bind can succeed while another program listens on 0.0.0.0 with the same port,
so the check may call such a port free (unverified on a Windows laptop); the gateway cannot probe
the wildcard address or connect out to tell, by boundary 1 and its no-outbound-connection rule.
browser -> 127.0.0.1 gateway -> coder ssh stdio -> workspace helper -> codex / claude
browser -> 127.0.0.1 gateway -> coder ssh stdio -> workspace helper -> git -> Git remote
browser -> 127.0.0.1 gateway -> coder ssh stdio -> workspace helper -> glab -> GitLab
browser -> 127.0.0.1 gateway -> coder ssh stdio -> workspace helper -> coder stat
local client -> 127.0.0.1:configured port -> coder port-forward -> workspace service
The workspace helper owns the existing T3 orchestration store, project records, threads, provider sessions, repository-local Git and filesystem operations, terminals, and checkpoints. Its durable state remains in the workspace. Legacy screenshot artifacts also remain in the workspace; the local gateway does not open or mirror its SQLite file or artifact directory.
The helper starts workspace-installed provider executables directly with argument-array spawning.
Codex uses its app-server protocol over stdin/stdout; Claude uses streaming JSON over stdin/stdout;
Pi uses its RPC mode (pi --mode rpc) over stdin/stdout; Kilo Code speaks ACP over stdin/stdout
(kilo acp).
No provider executable or Anthropic Agent SDK runtime is bundled. The Agent SDK is a type-only
development dependency; pnpm's ignoredOptionalDependencies keeps its bundled Claude Code
binaries from ever installing, and also skips @napi-rs/canvas, pdfjs-dist's Node-only renderer
that the browser PDF viewer never loads, so no native binary lands on the laptop. T3 does not inject its removed
preview MCP server or a local-host transport into Codex. Codex authentication and other
configuration remain workspace-owned and subject to workspace policy, including the MCP servers
and app integrations each provider loads from workspace configuration, as upstream. Each provider
connection remains owned by its workspace executable.
Native context compaction and asynchronous Codex questions use the same provider stdio sessions
and orchestration event stream; they do not introduce another listener or transport. Upstream's
usage/cost dashboard is not carried (remote pricing aggregation and CLI-proxy sources are an
external-data and secret-bearing surface). API-only provider scope is a product rule, not runtime
enforcement: shared provider probes may still report subscription metadata, which is not shown.
The helper also starts repository-scoped Git commands and the workspace-installed glab
executable with argument-array spawning and shell: false for GitLab source-control operations.
GitLab authentication and network policy remain owned by the workspace CLI; T3 never asks for,
reads, copies, persists, or logs its token.
Coder owns deployment authentication. For the supported Coder CLI 2.25.3, the gateway assigns each
deployment an isolated Coder-owned --global-config directory, invokes coder --no-open login <url>, and supplies both that config directory and --url <url> to every deployment-specific
command. The directory is keyed by deployment id, so POST /api/config rejects a saved
deployment whose URL changed (409); otherwise Coder could send that session to the new host. Coder prints its login URL and hidden token prompt in the terminal running T3 Coder. The
gateway never asks for, reads, copies, logs, or writes tokens. Coder 2.25.3 itself stores the session
token as plaintext in the selected config directory; multi-deployment OS-keyring storage is not
available until Coder 2.29. Network telemetry and direct workspace connections follow the
configured Coder deployment and CLI defaults. All generated Coder invocations include Coder
2.25.3's --no-version-warning because the managed deployment may run a newer fixed server version.
The loopback gateway has no application token. It binds only to 127.0.0.1, validates the exact
Host and Origin values for commands and upgrades, exposes no CORS policy, and treats local
processes and managed browser extensions as trusted by the deployment environment.
Browser diagnostics stay in DevTools. Filter the Console for [t3-error] to see failed RPC
requests and streams, handled command failures, gateway HTTP/network failures, React errors,
and unhandled browser errors/rejections. Reporting is independent of per-action toast handling
and console-suppression options. Entries contain a timestamp, operation, error type, bounded
message and available stack; known credential formats are redacted, and request bodies and
arbitrary error fields are omitted. Repeated observations of the same error object are deduplicated
and normal cancellations are ignored. No diagnostic upload, trace exporter, or saved log file is
created. Errors caught and discarded outside these boundaries cannot be observed automatically.
Development is supported on macOS. The production local host is Windows 11, so local paths and
processes must use Node platform APIs and argument-array spawning with shell: false; no OpenSSH
client is needed. The initial
workspace target is Linux x86-64. The helper launch is one foreground coder ssh session that
first runs the workspace preflight: it checks the remote OS and architecture, realizes a Node.js
24 package from the workspace's configured nixpkgs only when that runtime is not already
available (the preflight accepts any Node.js 24, below the root engines.node floor the
development suite needs: the server never binds a raw ArrayBuffer, and the SQLite checkpoint
worker falls back to the writer on an older SQLite, so an older 24 is sound in the workspace),
and checks Git, the transfer tools (tar, sha256sum, head), at least one of
Claude Code, Codex, Pi, or Kilo Code, and the workspace state directory. A failed check prints a T3_CODER_PREFLIGHT_FAILED: line, which the gateway reports.
The preflight has its own five-minute budget; helper negotiation starts its 60-second budget only
after the launch prints the ready sentinel. As upstream, server settings keep sensitive provider
environment values out of settings.json in a 0700 secrets directory in that state directory;
they never leave the workspace. The helper carries its locked Linux x86-64 node-pty runtime and
is launched with the Nix package's absolute Node path without changing PATH, so workspace shells
and helper children retain the workspace's default Node.js version. Platform and protocol versions
are then negotiated before a helper is used.
The gateway makes no external request of its own. The installed Coder CLI is the only local process
that connects to a workspace or deployment; its network telemetry and direct connections follow
the configured deployment and CLI defaults. Structured port-forward rules use foreground
coder port-forward processes bound to IPv4 loopback; reverse forwarding, arbitrary bind
addresses, and raw tunnel arguments are not exposed. The helper opens no network listener; Codex,
Claude, Pi, Kilo Code, and user-initiated terminal commands remain subject to workspace policy.
The helper bundle install streams over the stdin of one foreground
coder ssh <workspace> -- sh -l -c '<command>' process
(packages/coder-cli/src/transfer.ts); no OpenSSH client is involved. Coder 2.25 always allocates
a remote PTY, so the remote command first runs stty raw -echo and prints
T3_CODER_TRANSFER_READY; only then does the gateway write, and head -c <size> reads exactly the
expected byte count because a PTY never delivers end-of-file. The transfer writes a generated
temporary name under $HOME/.t3-coder/bin, checks the received size, and renames atomically into
place. The helper bundle travels as a ustar archive built in
Node (Windows has no tar -c to stream) and is extracted with tar -xf; the workspace shell then
recomputes hashCoderHelperBundle's digest and refuses a mismatch before replacing the helper and
recording .t3-bundle-sha256. Failed, damaged, or interrupted transfers are removed by a follow-up
coder ssh cleanup. Bytes, local paths, and Coder credentials are never logged, and nothing is
staged on local disk.
apps/coder-gateway/src/boundaryGuard.test.ts reads the gateway and coder-cli sources as text and
fails on any non-loopback URL literal, fetch(, outbound node:net/tls/https use, child
process import other than spawn, spawn target other than an invocation's executable, executable
literal other than coder, open, xdg-open, or explorer.exe, or shell: true.
Provider version checks are workspace-originated network requests: the helper asks the
workspace's own npm view (its configured registry, #27847) and otherwise registry.npmjs.org
for the latest version of each enabled provider whose installer it can identify; manual installations are not checked. The workspace setting enableProviderUpdateChecks
is on by default; disabling Settings → Maintenance → Provider update checks opts that workspace
out. Explicit provider updates run the installation's identified installer inside the workspace.
Versions marked broken or unsupported by the bundled compatibility policy are not offered. The
model manifest and compatibility policy remain bundled-only and are never refreshed over HTTP.
Composer attachments are the only laptop-to-workspace upload: an image or file pasted, picked, or
dropped into the message composer or a question answer. They use upstream's upload flow:
attachments.createUploadUrl mints a signed upload URL (assets/AttachmentUpload.ts), the browser
POSTs the bytes to it with upstream's upload queue, progress, compression, and HEIC decoding
(heic-to's bundled WASM decoder, which the gateway's wasm-unsafe-eval script policy allows),
and attachments.delete releases an abandoned upload. The gateway serves the URL at
/api/workspaces/<id>/api/attachments/upload/<token>: it requires the exact Origin, a
Content-Length within MAX_FORWARDED_UPLOAD_BYTES, and a connected workspace, then streams the
body to the helper in chunks of CODER_ASSET_BODY_CHUNK_BYTES over coder.writeRequestBody, each
sent once upstream's upload route has read the previous one (coderAssets.ts). The route checks
the token and the exact size and stores upstream's pending-upload name, pending-<uuid>-<ext>.
Bytes pass through gateway memory only. Closing the request interrupts the helper's read. The
helper advertises upstream's attachmentUploads, questionAttachments, and fileAttachments
capabilities. Drafts and stashed prompts keep their images and upload ids in browser storage, as
upstream's do. Upstream's data-URL assets.persistChatAttachments is not carried (ws.ts), and
client-runtime's state/attachments.ts keeps isAssetAttachmentNotFoundFailure module-private,
because only upstream's mobile app imports it.
As upstream does, the helper claims each pending upload into a thread-scoped copy when it accepts
the message; AttachmentClaims.ts reads the staged file once through a no-follow handle at its
exact declared size (and, for images, a matching signature) and writes it exclusively. Files reach
the provider as workspace paths; images are validated again before Codex and Claude read them.
Images Coder stored before upstream's attachment ids (<uuid>.<ext>) decode as
legacy-<uuid>-<ext> attachments that are never claimable. Sent images and files load back from
upstream's signed attachment URLs for previews, Save, and rewind.
The composer uses upstream's structured context records (t3-context://v1/<kind>/<id> links plus
message.context) without preview annotations, element captures, or SnapShot frames
(useComposerContextImport.ts skips those records when pasting).
ComposerAttachmentStrip.tsx's media row has upstream's image and video tiles without SnapShot
frames, and TimelineUserMessageRow.tsx's message media (#27306) has none either. The work log
uses upstream's client-runtime presentation without provider tool sources, favicons, logos, or
native app icons. File chip icons and size tooltips use upstream's filesystem.getMetadata, which
stats absolute workspace paths and reads at most 512 header bytes of an extensionless file to name
its type; it returns no contents.
The Files surface, filename search, and content search are upstream's. Project files are read and
written relative to the project root, and absolute or ~/ paths read host files in the workspace
as upstream does (#20950); writes stay inside a known workspace with upstream's git-folder
refusal, and reads stop at upstream's 1 MiB. Open files and editor state stay in browser memory.
A folder listing returns at most MAX_PROJECT_DIRECTORY_ENTRIES children, because a helper reply
larger than the stdio frame ends the helper connection. Content search needs no extra cap: fff
truncates each matched line to 512 bytes and upstream caps a search at 500 matches.
filesystem.getMetadata, which file chips use for their icons and size tooltips, is served as
upstream has it: it takes absolute workspace paths (or ~/ paths) with no thread or project-root
check, reads only stat plus a header sniff of at most 512 bytes for a file without an extension,
and never returns file contents.
Media, documents, and attachments load from upstream's signed asset URLs: assets.createUrl,
assets/AssetAccess.ts, assets/MediaFile.ts, and upstream's asset route (http.ts, which
carries only that route; auth/utils.ts carries only upstream's token signing helpers, because
upstream's HTTP session auth is not carried). Native app icons (upstream's resolver answers only on macOS) are
not carried, so that resource kind is cut from contracts/assets.ts. Upstream's source control
media resource (SOURCE_CONTROL_MEDIA_ASSET, with sourceControlMediaResponse.ts) is carried for
GitLab's Markdown uploads, which GitLab serves only to a signed-in session: the browser asks for a
signed URL, and the workspace reads the upload through GitLab's API with glab (see
Upstream seams), so only the bytes reach the laptop. Project favicons are upstream's: ProjectFaviconResolver with
T3ProjectFileLoader, the favicon URL atoms and IndexedDB image cache, and Settings → Project's
file picker, without the desktop-only picker for files outside the project. For the same reason
shared/projectFavicon.ts keeps PROJECT_FAVICON_EXTENSIONS module-private, and
shared/t3ProjectFile.ts drops buildT3ProjectFileJsonSchema, which only upstream's marketing
site uses.
The gateway serves a workspace's asset URLs at /api/workspaces/<id>/api/assets/*
(apps/coder-gateway/src/assetProxy.ts). It forwards GET and HEAD, with only Range and
If-Range, over the helper's gateway-only coder.serveAsset stream (coderAssets.ts), which runs
upstream's route in process and returns its status, an allowlist of its headers (type, length,
range, disposition, caching, validators, and its document CSP), and the body in acknowledged chunks
of at most CODER_ASSET_BODY_CHUNK_BYTES. It answers 503 unless the workspace is already connected,
so an asset request never starts a connection. A closed request interrupts the read; the RPC bridge
rejects the method from the browser. Responses keep upstream's caching (private, max-age=3600,
and no-store for video and audio).
A workspace's httpBaseUrl is that gateway path, and client-runtime's resolveAssetUrl resolves
upstream's root-relative URL below it (Coder:). External web images and videos load from their
host as on main. The gateway page CSP allows https:/http: and blob: in img-src,
media-src, and connect-src, keeps script-src to the app, and allows frame-src 'self' blob:
and object-src 'self' blob: for upstream's sandboxed HTML frames and PDF embeds.
Git action control and merge-request detail are upstream's with a GitLab-only provider registry.
Repository status, fetch, pull, commit, push, publishing, merge-request creation, and checkout run
in the workspace over helper RPC, using repository-scoped Git and the workspace glab. GitLab
writes are attempted as upstream does, with no write-access pre-check; a write that workspace policy
blocks fails like any other glab error. Generated commit and MR
text comes from the workspace Claude CLI. A review guide checks the merge request's head out into
a temporary worktree under the workspace worktrees directory, which the writer model reads
read-only and T3 removes when the run ends. The gateway never runs Git or glab, never connects to
GitLab, and receives no GitLab credentials.
Settings parity uses two bounded metadata reads in the Linux helper. projects.getConfig accepts
only a project ID, resolves an active project through the projection query, and reads the fixed
t3.json file at its real root (bounded by PROJECT_CONFIG_MAX_BYTES). It returns only decoded script fields, checkout
mode, and worktree submodule mode, or a missing/invalid/unavailable status. The browser uses the
same read to show t3.json as a settings tier; new worktrees read the checkout's own t3.json
through the same bounded, symlink-checked reader. It accepts no caller path, returns no raw file, and
never logs parser input or file contents. Importing an action remains an explicit settings write.
Workspace themes come only from <stateDir>/themes/*.json. The helper examines a bounded number of
candidate files, each and in total bounded in size (environmentTheme.ts). Reads reject symlinks, non-regular
files, invalid UTF-8, NUL bytes, and oversized files, and bind the opened file to the expected
directory. A symlinked theme directory is rejected. Reserved theme IDs and invalid or colorless
files are skipped. The watcher is scoped to the helper lifecycle; a sequenced, bounded publication
stream prevents stale changes from overwriting a reconnect snapshot. Only decoded theme metadata
travels over the existing server-config stdio stream. It introduces no listener, general file API,
local file transfer, credential handling, or telemetry.
Shared product subsystems are upstream's code with the Coder deltas below layered on top. When
syncing, take upstream's version of these files and reapply only these seams; a difference not
listed here or under Cut surfaces is drift to remove rather than fork behavior to
keep. Each entry names the file or symbol and the delta; the code carries a Coder: comment at each
one, except the merge-request wording swap (Wording). node scripts/seams-check.mjs
checks that every name here still exists and that every modified upstream file is marked or listed.
ws.ts,server.ts,serverRuntimeStartup.ts: upstream's files minus the cut surfaces; the fork's handlers and layers live incoderWs.tsandcoderServer.ts.ws.tskeeps upstream'slayerWsRpcand handler order, builds the methods it carries over the gateway's stdio bridge, and returns them merged withcoderWs.ts's at one hook asCoderWsRpcGroup(upstream's two disjoint handler groups split the whole group, fork-only methods included).server.tsexports the layer declarations the helper uses at one hook;coderServer.ts'smakeCoderRuntimeLayercomposes them with the Coder provider and orchestration layers,CoderRuntimeStartup,StorageCleanup,DatabaseStorage, the T3 tool bridge binding, and the RPC layer. Inserver.ts, settings also provide the secret store, the VCS status broadcaster takes the demand-only background policy, and the terminal shares its PTY adapter and process runner and upstream's port scanner (layerPortScanner, which the helper also provides to the Claude runner and the RPC handlers) with no native telemetry.CoderRuntimeStartupcompletes before the RPC layer is built, replacing upstream's startup command queue, with upstream's recovery order (provider runtimes, thenrecoverDelegatedTasks);coderServer.tsstarts the delegated-task question reactor with the other workers, and welcome/ready events are synthesized from workspace projections.- The helper sends Effect logs to stderr, which the launch discards (
2>/dev/null, because Coder's remote PTY merges it into stdout), so handler defects are not observable; T3 keeps no log file. - Server config comes from the Coder environment descriptor. A failed keybinding-config load falls back to defaults; config subscriptions do not force a provider refresh.
coderEnvironment.tsadvertises upstream's capabilities and protocol version exceptCODER_OMITTED_CAPABILITIES, each with a reason;coderEnvironment.test.tsfails on a key in neither list. It also declaresServerEnvironmentIdentity, whichThreadManagementService.tsimports from the uncarriedenvironment/, with upstream'smakeIdentitypersistence carried as is (temp file linked without replacing, so concurrent helpers agree on one id), and advertisesproviderWorkspaceSnapshotsOnDemand.coderWs.ts(CODER_WS_METHODS) adds local ref status, branch and worktree rename (moveWorktree), chunked review files, the gateway's asset stream (coder.serveAsset) and upload body (coder.writeRequestBody), fixed project-config reads, merge-request diffs, and upstream's HTTP thread snapshot (orchestration.getThreadSnapshot), history page (getThreadHistoryPage), and transcript (orchestration.getThreadTranscript) over stdio. Their payloads carryviewand a booleandeferWorkand omitcompactIds. Snapshots and pages keeptargetBytesbudgets and the newest requested turn, and fail before encoding when over the stdio frame; a transcript over the limit fails withOrchestrationThreadTranscriptTooLargeError.ws.ts:withPullRequestVieweris an identity (GitLab uses the workspace'sglablogin); the on-demand workspace-snapshot stripping (workspaceSnapshotsOnDemand) has no usage-limit commands.persistence/DatabaseStorage.tsis built besideStorageCleanuponce startup completes; itst3 doctorfile-size status is cut (no CLI in the helper).coderServer.tsruns upstream's idle Claude compaction worker (layerIdleCompactionWorker) inCoderRuntimeCoreLiveand givesProviderRegistrythe provider support layer (CoderProviderRegistryLive).workspace/WorkspaceFileSystem.ts,WorkspaceEntries.ts,WorkspaceSearchIndex.ts: a folder listing returns at mostMAX_PROJECT_DIRECTORY_ENTRIESchildren, because a larger reply ends the helper connection.- Office document text (#21358):
apps/coder-helper/src/bin.tsdispatches upstream's__document-textargument and imports only the worker on that path (the stdio runtime inhelper.tsloads lazily);DocumentText.tsruns thatbin.tsfrom source or the bundle (import.meta.url);coderServer.tsprovidesDocumentText.layer, andProviderHostLivecarriesresolveExtractedTextPath. config.ts(server) is paths under the workspace state directory only.- Transcript drops: client-runtime's
threadTranscriptis an RPC command, so the orchestration atoms need no HTTP client; the composer reportsOrchestrationThreadTranscriptTooLargeErroras upstream reportsthread_transcript_too_large. - Linked environments (#16653–#17130) run between Coder workspaces through the gateway hub instead
of server-to-server HTTP
/mcpand pairing (AGENTS.mdboundaries 2, 3, and 6).peer/PeerMcpClient.tsandpeer/PeerLinks.tskeep upstream's service tags but send calls and read links throughcoderHub.ts(helper protocol v3:coder.hub.outbox,coder.hub.reply,coder.hub.invokeinpackages/coder-cli/src/rpc.ts); the gateway (hub.ts) checks the requester'sworkspaceLinksrule (edited inWorkspaceLinkSettings.tsx) and runs the call on the target helper ascoder-link:<rule id>with the rule's access and the caller's modes asnarrowedTo. A workspace that is not connected answersorchestration_error; no matching rule answerscapability_denied; editing a rule's endpoints mints a new id. NoT3-Mode-Limitheader;PeerLinkshas no pairing, storage, or expiry (expiresAtis far-future);coder.hub.invokerefuses calls while Labs' switch is off with a non-finalorchestration_error;T3ToolBridge's binding gainsinvoke;t3_environment_links'notListedand the orchestration instructions point to the Links settings. Migrations 070 and 071 keep their IDs and create nothing.peerLinksandlinkFenceare advertised;mcpModeLimitHeaderis omitted.threadShell.test.ts's linked-task case drops the switched-off parent step. Cut client pieces are under Cut surfaces. @-mentioning a machine (#17130) is carried; its machines are the connected workspaces the composer's workspace links to.coder/linkedWorkspaces.tsreads theworkspaceLinksrules from that workspace and the Linked environments switch, in place ofoffersLinkedEnvironmentsAtom(state/peerLinks.ts, cut), anduseComposerMenuItems.tsoffers only those environments. SharedcomposerContextReferences.tstells the agent to ask for a link in the Links settings in place of callingt3_environment_link.- The
@picker lists no threads on linked machines (#26201):composerThreadItems.ts, sharedcomposerContextReferences.ts(threadContextsOutsideEnvironment), and the composer hooks keep the same-server rules.
Drivers/ClaudeCli.tsimplements the Agent SDK'squery()andQueryover the workspaceclaudeexecutable. Rollback and resume useresumeSessionAt. A stream-json line may use the 32 MiB pending-message budget (a 10 MiB base64 tool-result image fits); longer fails the session. Plain-text stdout lines before the first JSON line are dropped (managed launchers print a banner).Querymethods sent as control requests:interrupt,stopTask,setModel,setPermissionMode,setMaxThinkingTokens,applyFlagSettings,getContextUsage,getSettings,getUsage(withskipBehaviors),setMcpServers(no deadline),backgroundTasks(resolves tobackgrounded, true when absent),initializationResult, andclose.can_use_toolpassesmatchedAskRuleandsuppressAlwaysAllowRuletocanUseTool.Drivers/ClaudeAgentSdk.tsprovides SDK-typedqueryandgetSubagentMessagesover the CLI, typed as the full SDKQueryso a new method fails typecheck until mapped or rejected; it answerssupportedCommands,supportedModels,supportedAgents, andaccountInfofrom the initialize response and rejects every other method. Options the CLI cannot honour fail (SUPPORTED_QUERY_OPTIONS);mcpServersbecomes--mcp-configand in-process (sdk) servers are rejected;executableArgsgo before the CLI's arguments;spawnClaudeCodeProcessstarts the CLI as the SDK does (its stderr is not read). Launch args reach the CLI except the stream-json transport flags.- No
forkSession:ClaudeAdapterV2.forkThreadstores the source session and boundary asclaudeForkmetadata, and the fork's first query runs--resume --fork-session --resume-session-at --session-id. Fork-head capture (#21188,forkHeadMessageId) is not carried. Forks also carryclaudeAttachmentBudget. ClaudeAdapterV2.ts: pasted images go throughresolvePastedImageAttachments, counted toward the PDF and attachment budget bysizeBytes; bridge sessions getCLAUDE_BRIDGE_BACKGROUND_WAIT_INSTRUCTIONS(no ToolSearch sentence); nodeviceToolsAvailableinput orSubagentStartdevice hook;resolveBypassAvailabilityreads the settings files (cached remote, user, project, local, managed) where upstream calls the SDK'sresolveSettings, andresolveSubagentPromptCacheTtlreadssubagentPromptCacheTtlfrom them (last set wins).Drivers/ClaudeSkills.tskeepsclaudeSettingsPathsexported for that. Upstream's out-of-processrunClaudeWorkeris not carried; onlyencodeClaudeJsonstays.- T3 tools over the file bridge, not MCP (
AGENTS.mdboundary 6):mcp/McpSessionRegistry.tskeeps upstream's lifecycle, but each credential is a bridge (mcp/bridge/FileBridge.ts) whosetoolCommand(a Coder field on provider-core'sMcpProviderSessionConfig) runs the tools and whoseendpointis the per-thread directory;mcp/bridge/T3ToolBridge.tsruns upstream's handlers by name with the credential'sMcpInvocationContext, refuses non-read-only tools in plan mode (and any call when the thread cannot be read), turns slow calls intobridge-job:tasks (the per-thread cap counts running tasks and is checked before a call starts; a finished result stays until its reply is published), and printsadvertisedJsonSchemafor--schema. toolkits/environment/reads theCoderEnvironmentdescriptor in place ofServerEnvironment.- provider-core's
server/t3ToolBridgeInstructions.tsreuses upstream's orchestration sections, rewriting "html_preview, thenhtml_render" to "html_render" and dropping thepreview_*bullet; its test fails if upstream rewords them. CodexAdapterV2.tsconfigures nomcp_servers(neithert3-codenor the direct-onlyt3-code-directserver fort3_thread_wait, #29026 and #29068;codexThreadRuntimeParamsadds only upstream's per-threadT3CODE_THREAD_ID), attaches T3 context only when the bridge exists, and takes the bridge text ast3ToolBridgeSections(one context entry per section, underCODEX_ADDITIONAL_CONTEXT_VALUE_MAX_BYTES);CodexDeveloperInstructions.tsandClaudeAdapterV2.tsdescribe the bridge command, and Claude pre-approves it as a Bash prefix (read-only tools in a read-only sandbox).CodexAdapterV2does not rewrite failures throughCodexManagedErrors.PastedImageAttachments.tsis the only provider image reader:localImagepaths for Codex, base64 for Claude; Read-tool image views are limited to PNG, JPEG, and WebP; Codex branch-name and title generation read images through it.AttachmentClaims.tsreads each staged upload once through a no-follow handle at its exact size, checks image signatures, and writes0600copies;ResourceCleanupService.tsskips attachment deletion and closes no preview sessions.attachmentStore.tsresolves the fork's pre-upstream<uuid>.<ext>images aslegacy-<uuid>-<ext>ids that are never claimable.provider/builtInDrivers.tsregisters only Codex, Claude, Pi, and Kilo Code, with no usage driver list;settingsSecrets.tsreads secret fields from Pi's and the ACP Registry's client definitions only;ProviderOrchestrationAdapterInfrastructure.tsprovides only the Claude query runner and the Codex app-server factory;ProviderInstanceRegistryHydration.tsseeds no replay instance and needs noCrypto;testkit/DormantProviderCapabilities.tsis kept for orchestrator tests.- Pi:
buildPiRpcLaunchhands upstream's T3 extension the file bridge (T3_TOOL_COMMAND,T3_TOOL_CATALOG); it registers the catalog's tools under upstream's names, runs each through the bridge with arguments on stdin, returns the printed JSON asstructuredContent, and mapsreadOnlytoreadOnlyHint.mcpExtensionSource.tskeeps upstream's HTTP MCP client dormant (never givenT3_MCP_URL). - Pi text generation (
provider-pi/src/server/textGeneration.ts) loads the workspace's Pi extensions (no--no-extensions), since one may register the only reachable model providers. textGeneration/ClaudeTextGeneration.tsdrops plain-text stdout lines before the first JSON line, asClaudeCli.tsdoes.- Kilo Code is upstream's ACP Registry driver (
@t3tools/provider-acp-registry, kindacpRegistry) limited to the localkilo acpcommand:settings.tskeeps onlycommandPath(defaultkilo), hiddencommandArgs(["acp"]),customModels, andenabled(default off; contracts'DEFAULT_DISABLED_PROVIDER_DRIVERSlistsacpRegistry);client.tslabels it "Kilo Code", inlines its icon, and has a default instance;AcpRegistrySupport.tskeeps only local-commandinspectandresolve(noacpRegistryManagedBinaryDirectories);driver.tsreports only local readiness (canAuthenticatefalse, sign-in told to happen in the workspace) and noconfigurableProviders, and real sessions setauthenticateOnAuthRequired: false; the probe declines URL elicitation;driver.tskeepsacpRegistrySnapshotReadinessandtesting.tskeepsprobeAcpRegistryConfigurationexported for the fork's tests;AcpRegistryRuntimeCoordinator.tshas no URL-auth consent;adapter.tshas no Devin, Copilot, or Mistral Vibe flavor or native logging. - Kilo Code native sessions: of upstream's ACP session management only the session list and import
are carried (Settings → Providers → Kilo Code → Native sessions). provider-core's
acpSessionManagementhas onlylistSessions;probe.ts's session manager offers no URL elicitation or auth method;ws.tsservesserver.listAcpRegistrySessionsandserver.importAcpRegistrySession(the import launches without upstream's startup queue), andcoderServer.tsprovides the runtime coordinator alone (upstream:layerFromHost);rpc.ts, client-runtime'sstate/server.ts, andAcpSessionManagementSection.tsxcarry only those two. Session delete is cut because Kilo Code advertises nosession/delete; logout and agent provider configuration are account and provider management. The section keeps upstream'sreadOnlyprop (upstream's browser test passes it) andprobe.tskeeps upstream'smanagementFailurereasons for the cut actions; neither is read here. - provider-acp's
adapter.tsgives ACP sessions no MCP server and sendst3ToolBridgeInstructionswith the first prompt through provider-core'st3AcpPromptWithInstructions;mcpOverAcpBridge.tsandclientTerminals.tsstay dormant (cutting them would add about 34 seams). HTTP MCP servers (#26968) are cut: the adapter's flavors have nomcpOverHttp(only Copilot's uncarried flavor set it) andAcpSessionRuntime.tstakes nohttpMcpServers.scripts/acp-mock-agent.tskeepsT3_ACP_COMMAND_ADVERTISEMENT_DELAY_MSfor the adapter test. The user guide is the fork'sdocs/user/providers-kilo.md, adapted from upstream'sproviders-acp.md(not carried). project/AgentSessionScanner.tsdeclaresresolvePiSessionsDir(upstream exports it from Pi's uncarried usage reader);coderServer.tsprovides the scanner;ImportAgentSessionsDialog.tsxruns the welcome wizard's import step from Settings → Providers → History.ProviderAuthServicereports every sign-in, logout, and credential transfer unavailable;CodexManagedRuntimekeeps only upstream's resolution contract;ProviderHostLivegives drivers no credential store.CodexDriveroffers no managed install (setupMode: "managed", so nocompatibilityhook), has noCodexUsageHistory, and redeems no rate-limit reset credits;ClaudeDriverreads no organization id, so its one-probe fallback skips the same-organization check; the Claude signed-out message names API credentials.ModelManifest.layerBundledserves the bundled manifest with no fetch or disk cache.- Runtime modes: Claude and Codex fill upstream's provider-level
supportedRuntimeModesfrom workspace policy (Claude'sdisableAutoMode/disableBypassPermissionsModethroughClaudeCli, Codex'sconfigRequirements/read), reporting the safe modes until the first probe and on failure (provider/runtimeModeCapabilities.ts,provider/CodexRuntimeModes.ts). A mode the provider does not offer steps down to the broadest offered mode below it inruntimeModeConfig.ts'sresolveCompatibleRuntimeModeandRuntimePolicy.providerRuntimeMode, asdelegatedTaskModes.resolveRuntimeModealready does. - No metrics:
Orchestrator.tsandProjectService.tshave nowithCommandMetrics,ProviderSessionManager.tsno session or turn metrics,ScheduledTaskService.tsno webhook metrics,SecretRequests.tsno consumed-ref count,EventSink.tsno run outcome metrics (RunMetrics.ts), andRunExecutionService.tsnoPreviewAgentActivity. Provider token analytics (#29001) is cut:telemetry/ProviderUsageAnalytics.tskeeps only its report types and the no-opProviderTurnAnalyticsreference thatProviderEventIngestor.ts,ProviderTurnStartService.ts, andRunExecutionService.tscall, with no analytics layer or request ledger; the token usage counts those turns carry are upstream's.EventNdjsonLoggerandProviderEventLoggerskeep only the no-op service. provider-core'smaintenanceResolver.tsandproviderStatusCache.tslog the first cause tag in place of the omitted observability helper. - No
lastErrorCode: the server'sthreadErrorSummary,ProjectionStore.ts's shell state, client-runtime'sThreadRuntimeSummaryandstate/models.tsdrop it (the contract field stays). mcp/toolkits/orchestrator/handlers.tshas not3_environment_linkort3_environment_unlink.mcp/toolkits/attachment/tools.ts:t3_attachment_prepare_uploadtakes apathbesideupload, needs storage's services, returns onlyattachmentId, and its description names the path instead of a URL to POST to.handlers.tsstores the file through upstream'svalidateAttachmentUploadTokenandstoreAttachmentUpload(storeWorkspaceFile) after checking it is an absolute path to a regular file of exactlyupload.sizeBytes, and refuses a call the gateway hub forwards (client.linked). Upstream'score.test.tsattachment cases run inattachment/handlers.test.ts.persistence/Errors.tshas no pairing-link correlation or auth repository errors.
- The bridge carries
html_renderonly.htmlRender/HtmlRender.tskeeps image inlining and storage withoutpreviewor height measurement (work workspaces cannot obtain the headless browser); the tool description omitshtml_previewand the mobile scroll-cap sentence. htmlRenderFromBridgeCommand(sharedtoolOutput.ts) recognizes a completedt3.mjs html_renderbridge command;WireProjectionkeeps only that compact reference.- Pages are kept like other attachments; deleting a thread does not delete them.
rpc.tsomits RPCs whose schemas belong to cut modules (chat attachment persistence, preview automation, relay, resource telemetry, usage, editor launch, GitHub routing, feedback upload, OTLP check) and adds the helper-only methods andCoderWsRpcGroup, the only group the helper serves. Upstream'sWsRpcGroupstays dormant (knip.jsoncignoresrpc.ts's unused exports).CoderWsRpcGroupomitsserver.getDatabaseStorage,server.getNpmRelease,server.prepareTriage, the browser preview's RPCs (it keepspreview.stopLocalServerandsubscribeDiscoveredLocalServers), guest share creation, the peer-link RPCs,orchestration.getNativeChildWork(Antigravity's native child work, #28629), and thesourceControl.signIn*,sourceControl.appAccess, andsourceControl.starredRPCs.server.ts(contracts) mirrorsipc.ts'sDesktopUpdateChannelSchemaforServerSelfUpdateInput, becauseipc.tsis not carried.ServerConfigomits auth, editors, remote open targets, and observability; the optionallastEventLoopStallstays in the schema but is never sent.vcs.tsandgit.tsadd the helper-only ref-status and thread-branch rename schemas;assets.tsomits native app icons; tool items keep legacy screenshotartifacts; rate-limit events carry the raw payload.- Terminal attach input adds
afterSequenceandafterEpoch, snapshots addattachEpoch, and the attach stream adds aresumedevent. settings.tsdeclaresUsageModelFilterfor theusageModelFilterserver setting (#28952) because contracts'usage.tsis not carried; client-runtime'sstate/server.tshas no usage atoms.- Client settings keep
providerPreferencesByEnvironment, read only as the legacy lists each workspace migrates (see Web state and persistence).
terminal/Manager.tskeeps a bounded attach replay window (DEFAULT_ATTACH_REPLAY_*) and answers an attach withafterSequenceby replaying the gap and aresumedevent; each shell session has anattachEpoch, and a cursor naming another epoch gets a snapshot. Terminals poll the process table themselves, record no metrics, and get no managed ACP directories onPATH.- client-runtime adds
TerminalBufferCache, a bounded memory cache that seeds a reattach and supplies itsafterSequenceandafterEpoch; a resumed attach of a closed terminal gets upstream'sclosedevent.ThreadTerminalDrawernever opens terminal links.
source-control-definitions'registry.tsregisters only GitLab's definition and the server'ssourceControl/sourceControlDefinitions.tsonly the GitLab driver, so every other kind reads as the generic host.sourceControlClients.tsdropsreadHostCredentialSettingsand its types. The registry'sparseChangeRequestUrl(coreshared/definition.ts) rejects a URL with credentials.canonicalizeGitCafePullRequestUrlis an identity.- source-control-core drops the driver's
signInandisRepositoryStarred, the definition'sappSignInandsignIns, andSourceControlHost.settings.updateandgetWithSecrets(also from the test host); core'sSourceControlMediaRequestaddscwd, whichsourceControlMediaResponse.tspasses from the claim. sourceControlHostSecrets.tshas no secret-reference resolution or invalidation, soserver.refreshProviders'reloadSecretsinvalidates nothing.- GitLab's definition (
source-control-gitlab/src/shared/definition.ts):authorProfileUrllinks authors under the host root;referenceAutolinks(shared/referenceAutolinks.ts) links!N,#N, and full SHAs with GitLab's/-/routes;mediaUrl(shared/gitLabMedia.ts) claims Markdown uploads and maps them to the projects uploads API, which the driver'sfetchMedia(server/GitLabMediaFetch.ts) reads withglab apiin the mintedcwd(no--hostname), buffering at mostGITLAB_MEDIA_MAX_BYTES. The package also exportsserver/GitLabCli, whichws.projects.test.tsstubs. GitLabCli.tsfixes bugs still in upstream (checked against upstreammain47f2c8d29e): merge requests between projects post to the source project with a numerictarget_project_id; merge request URLs reachglabas--repo <url> … -- <iid>.glab auth statuslines with a token label orglpat-token are never surfaced; clones accept only GitLab URLs without credentials, query, or fragment and pass--before the URL; diff output is capped (DIFF_MAX_OUTPUT_BYTES) underCODER_RPC_FRAME_MAX_BYTES;GitLabClisupplies "Merge request not found." as its detail.PullRequestServiceomits cross-environment routing (routing identities, verified credentials,expectedAccountIdrefs) and runs delete-branch without the verified-credential wrapper.coderServer.tsusesserver.ts'slayerRepositoryIdentityResolver, whose refine hook lets GitLab confirm a self-hosted host throughglab, and providesFetchHttpClient.- Shared
sourceControl.tsaddsparseGitLabCloneSource, which keeps a small table of other hosts so their URLs are still rejected. - Review guides:
coderServer.tsprovidesPullRequestReviewGuideServiceto the RPC handlers and bridged tools; the guide tools resolve only merge requests on a GitLab host the projects use, and the service's reader-facing errors say merge request and!N. - The pull-request T3 tools accept only merge requests on a GitLab host a workspace project uses.
- Web merge requests: diffs come over
pullRequests.diffwithout GitHub routing; a project's default merge method is a workspace setting whosenullmeans "last selected"; client-runtimepullRequestMarkdown.ts'sresolveGitLabUploadUrlresolves/uploads/below the repository, andpullRequestMarkdown.logic.ts'spullRequestAutolinkPluginsaddsremarkGitLabUploadsto each repository's cached plugin list, andPullRequestMarkdown.tsxsplits the body against the context'srepositoryUrl; video uploads play inline. lib/openPullRequestLink.tsalways offers the "Open link" toast for a commit outside the thread's workspace;changeRequestLinks.ts'sisGitLabProject(also used byfindProjectOnChangeRequestHost) skips checkouts whose provider is neither GitLab nor unknown;gitLabMergeRequestBrowserUrlreplaces the GitHub fallback URL and the definition URL inLinkPullRequestDialog'sresolveLinkPullRequestProject, keeping a self-hosted origin and path prefix (nothing setsRepositoryIdentity.webUrl). The link dialog accepts!123(pullRequestLinkInput.ts); a plain click opens the panel or page, a modifier click or an unreadable MR the system browser.SettingsPanels.tsx's Diffs page defines the "Open merge requests in T3 Coder" row, because upstream's Integrations page is not carried.pullRequestList.logic.ts's filter haystack also matches!123.pullRequestEditing.tshas nocanEditPullRequestMaintainerEdits; GitHub maintainer edits (#25588) have no web control.GitManager.ts: merge request wording in its ref fetch and uncommitted-changes errors.
vcs/GitVcsDriverCore.tshas no Git metrics or span events; addsmoveWorktree(renames a thread's worktree folder with its branch, under the 5-minute worktree remove deadline) andrefStatusLocal(never refreshes the real index); review file expansion allows up toMAX_REVIEW_DIFF_FILE_BYTESand fails withReviewDiffFileTooLargeError, rejecting malformed UTF-8; a top-level reviewsourceKindreturns only that source; worktree creation readst3.jsonthrough the boundedreadProjectConfig; checkpoint commits use the "T3 Coder" identity.vcs/VcsProcess.tsrecords no Git command metrics.git/GitWorkflowService.tsaddsmoveWorktreeandlocalRefStatuspass-throughs.vcs/VcsStatusBroadcaster.tsaddsstreamRefStatusforsubscribeVcsRefStatusand resolves auto-pull withresolveProjectAutoPull(vcs/projectAutoPull.ts, which honors legacyproject.autoPulland holds upstream'sautoPullProjectsstartup step); itsBackgroundPolicyis a Coder stub that always allows work (shouldRunOpportunisticWorkis always true), soThreadPullRequestService's sweep runs while the gateway holds the helper.review/ReviewService.tsreplacesgetDiffFileContentswith chunked file snapshots (openDiffFileContents,readDiffFileChunk) held in bounded helper memory.
state/primaryEnvironment.tsmakesprimaryEnvironmentIdAtomthe active workspace (the first to send its welcome);__root.tsx'sEventRouterreads welcome events per workspace,state/entities.tskeeps onlyinitializeActiveEnvironmentId, there is no available-editors atom, andusePrimarySettingsAvailablehas no hosted-app case.- Always-grant scopes (Coder owns authentication):
useEnvironmentScope,readEnvironmentScope, anduseFilesystemReadAccessgrant for a known workspace; client-runtimecommandPermissionsauthorizes every command and installs theRpcPermissionGuard; settings sync writes without grant checks and worktree removal is always offered;state/terminalSessions.tsreads terminal scopes throughreadEnvironmentScope, andfiles/fileSaveSessions.tssubscribes to no write-scope changes. connection/platform.tsregisters only the configured Coder workspaces through the gateway. client-runtime'sconnection/driver.ts,connection/index.ts,connection/wakeups.ts, andplatform/persistence.tsdrop multi-route checks, credential and profile stores, saved targets, onboarding, GitHub routing, host updates, and the mobilenetwork-changedwakeup.connection/supervisor.tsgives the route no kind, so probe timeouts treat it as remote (#25824);checkHostnever answers (the gateway answers either way);connectedLeaseEndends a lease only on a disconnect.connection/registry.tsstarts every registered supervisor desired, applies every reconcile (no #26511 skip), carries no cached unsupported-host rejection, and has noassertKnownAddressorknownAddressOnly;connection/resolver.tshas no remote HTTP prepare path.state/shell.tstreats every workspace as remote, so upstream'sshell.test.ts, which tests its primary-environment factory, is not carried.- client-runtime's
threadSnapshotHttp.ts,shellSnapshotHttp.ts, andthreadHistoryHttp.tskeep upstream's paths but load over helper stdio; shell snapshots use upstream's socket fallback. - client-runtime's
rpc/protocol.tsbuilds its client fromCoderWsRpcGroup, andrpc/index.tsexports it without the HTTP client;client-runtime/environment/index.tsandclient-runtime/platform/index.tsexport no endpoint, descriptor, capability, or storage document modules. lib/runtime.tshas no primary-environment HTTP client, relay, DPoP, or tracer;branding.tsfixes the "T3 Coder" name.localApiTypes.tskeeps the context-menu and confirm-dialog types upstream takes fromcontracts/ipc.ts, soconfirmDialog.ts,externalLinkContextMenu.ts, andpullRequestLinkContextMenu.tsimport them from there;localApi.tsopens only HTTP(S) links.ChatHeader.tsx's merge request button tests"desktopBridge" in window;threadNotifications.tsalways badges the favicon;ThreadNotificationCoordinator.tsxfocuses the tab without the desktop reveal;vite-env.d.tsdeclares no desktop bridge or hosted, relay, or desktop env vars.- client-runtime
errors/diagnostics.tsis the[t3-error]DevTools reporting (see Authentication);state/runtime.tsexportsexecuteAtomCommandfor its test and callsonAnsweron the non-persisted query path;errors/network.tskeeps onlyUNRESPONSIVE_HOST_HINT. state/environments.tshas no relay discovery,relayManaged, oruseEnvironmentHttpBaseUrl.- A thread whose workspace is not connected shows
WorkspaceConnectionStatus, as does_chat.index.tsxafter the draft branch (#20183) while workspaces are pending; the/projects/$projectKeyredirect has no auth gate. - App entry:
main.tsxrenders insideCoderBootstrapand installsconsoleDiagnostics;appInit.tsxstarts no provider auth delivery, Electron service, default-theme adoption, agent-opened previews, SSH prompt, host-freeze toast,PermissionUpdateNotice, desktop update notice, browser host, preview title recording, browser profile reporting, favorite-editor command, or desktop paste-as-text;AppRoot.tsxmounts noElectronBrowserHostorQuitHoldOverlay;__root.tsxkeeps the fork's minimal shell;_chat.tsx'sbeforeLoadhas no auth gate or prompt-link card;shortcuts/dispatcher.tsregisters no desktop menu actions or preview focus;shortcuts/chatRouteCommands.tshas no preview commands;KeybindingsUpdateToast.tsxshows no config-warning actions; client-runtimestate/presentation.tsshows an available placeholder as connecting (noentry.enabledorunsupportedReason);lib/bootError.tskeeps reload and error details only. AppSidebarLayout.tsx:readUsagePageOpenis always false andregisterNavigationHistoryCommandsstays unexported (upstream exports it for an uncarried test); no desktop menu-action forwarding, fullscreen insets, or preview keybinding context.shortcuts/commandPaletteCommands.tsreadsusagePageOpenas false and has no usage or preview commands.ProviderUpdatesAction.tsx's Update all has noquietoption or returned runs, andProviderUpdateRunno environment id (no "Update everything").index.cssdrops thewcovariant, drag regions, and desktop resize inset; withoutlib/windowControlsOverlay.ts,ui/tooltip.tsxreads a zero titlebar height,chat/ZoomableImage.tsxsizes to the window, and the sidebar sheet gets no inset.env.tsreportsisElectron = false.- Branding:
ui/standalone-page.tsx's wordmark reads "T3 Coder",SidebarChrome.tsx's logo link is "T3 Coder home",QueuedRunsControl.tsxsays "Sent by T3 Coder", andPullRequestsColumn.tsxlabels its F6 area "Merge requests".
ChatView.tsx: no browser or device panels, mini-player, automatic machine placement, self-update or version-skew banners, usage-limit panel, feedback upload,OpenInPicker, or favicon store; the active workspace stands in for the primary environment and drafts read their route workspace's config. The modules upstream split from it carry the matching cuts:RightPanelSurfaceContentrenders nothing for browser and device surfaces;useRightPanelSurfaceClosecloses no preview sessions;useSystemComposerBannersshows only the offline or reconnecting banner, whose Reconnect only retries;useDraftEnvironmentRoutingkeeps only the manual machine switch;useComposerSendhas no feedback upload,/usage-limits, load balancing, or preview-annotation send (composerSend.logic.tshas no load-balancing helpers), and its/sidetext-only check reads no annotations;useRightPanelActionshas no browser or device surfaces, so noembeddedflag;useChatTerminalActionsopens no script preview;useProjectCloneBannershows no file-copy banner;useComposerResumeanduseThreadLifecyclecall noclearUsageLimitsFor;ThreadErrorBannerandChatBannerLanetake no error code;ChatOverlayHosts.tsxhas no device setup host.useTimelineRewindreads the message's images back through the helper instead ofchatViewSend.ts'sprepareRevertedMessageAttachments.chatCanvasLayout.tshas no preview obstacles (it acceptsfindBarand ignores it).RightPanelTabs.tsxis upstream's strip andPreviewPanelShellwithout browser, device, and preview surfaces or per-tab memoization (#20853); never-opened preview surfaces get a plain title and icon. Its inline tabs renderRightPanelTabContent, which reads a side chat's shell for the tab's title and state where upstream's memoizedRightPanelTabdoes. The branch toolbar's workspace options are never primary and use the server's machine kind, with no "Auto balance" or server-update control; the branch picker adds "Rename current branch…" (vcs.renameThreadBranch).- Preview annotations, element captures, and SnapShot frames are absent from the composer and
timeline:
useComposerContextImport.tsskips their records,ComposerAttachmentStrip.tsxandTimelineUserMessageRow.tsxshow no SnapShot frames,composerCommandKey.ts,useComposerStash.ts,useQueuedRunEdit,ChatView.logic.ts, andchatViewSend.tscarry no annotations, andquestionAttachments.tshas no SnapShot draft tracker. work-log/presentation.tsformats token counts inline (@t3tools/shared/usageFormatbelongs to the usage dashboard); native app icons fall back to the tool glyph; client-runtime'sstate/attachments.tskeepsisAssetAttachmentNotFoundFailureprivate.- Markdown (
ChatMarkdown.tsx,chat/ChatMarkdownMedia.tsx,chat/MarkdownFileLink.tsx): workspace media load from signed asset URLs and a missing file names the workspace and path;MarkdownFileLinknever getsonOpen,onOpenInBrowser, oronReveal, and the link menu never offers the integrated browser; relative and non-web links render as inert text; GitLab references open directly (confirmBeforeOpenfalse, the candidate URL is the link itself). - Files and search UI: previews load from signed asset URLs, and HTML files are detected locally
(
isBrowserPreviewFilelives with the in-app browser);fileContextMenu.tskeepsresolveFileContextMenuAbsolutePathbut offers Open in Files and Copy path; the Git actions dialog opens changed files in the Files surface (openFileSurfaceStablethroughThreadDetailsPanel'sonOpenFile), mapping repository-relative paths to the thread's folder, and closes, keeping its commit message;projectFilesQueryState.tshas noisFile. - Diff panel (
DiffPanel.tsx): expanded context loads through the chunked review RPCs (createChunkedGitDiffFileContentsLoader), a file over the limit is listed inDiffFileExpansionErrorNotice, branch previews ask for one top-levelsourceKind, and a file title opens the Files surface with no local-editor fallback. patches/@pierre%2Fdiffs@1.6.1.patchadds a guard that ignores loaded contents unless the diff is still the partial diff that asked, and lets a contents loader returnnull(FileDiffContentsLoaderandLoadedPartialDiffContentstypes), which 1.6.1 still lacks.- Project actions: repository actions come from
projects.getConfig, which dropsiconPathand script preview fields; the editor has no preview URL; the thread details card has no Open in or usage items, sothreadDetailsUsageEnabledis never read and the Context window item (#27892) starts hidden.chat/ThreadDetailsUsage.tsxkeeps onlyThreadDetailsContext, soThreadDetailsUsageInputcarries onlycontextWindow. - Servers (
chat/ThreadServersPanel.tsx): selecting an unforwarded server is Forward in place of opening the browser panel (coder/serverForwards.ts): the gateway's/api/port-forwards/free-portpicks the server's port or the next one free on127.0.0.1and unused by a saved TCP rule, the browser saves an ordinary rule throughuseCoderSettingsConfig, waits for the forward'sreadystatus (Coder'sReady!line, up toFORWARD_READY_TIMEOUT_MS), and points a tab it opened during the click athttp://127.0.0.1:<local port>/; a forward that never runs is removed again. A forwarded row shows its local address, opens it, and adds Stop forwarding, which removes the rule; stopping the server keeps the rule. No modified-click system-browser open (no desktop shell). Client-runtime'sstate/preview.tskeeps onlydiscoveredServersandstopLocalServer, and sharedpreview.tsonly the loopback checks. - The worktree setup card says "Use project checkout";
ChatComposer.tsx'saddComposerFoldersalways takes the remote-environment branch and its toast. - Command palette (
CommandPalette.tsxand its split modules): every workspace is remote; Add project always shows the workspace picker, which also lists unconnected workspaces and connects the chosen one, runs workspace discovery once, and opens connection settings with no Coder domain; there is no desktop or WSL folder picker, browser preview, usage page, or file manager action; review actions say merge request.
- client-runtime's
state/runtime.tsquery atoms take nopersistenceoption andstate/pullRequests.tspasses none (upstream's offline query store is mobile-only); its query key normalizer andpullRequest/filesViewedStore.ts's scope key dropexpectedAccountId. hooks/useSettings.tsrunsstartModelPreferencesMigrationwith the legacy lists from the workspace'sproviderPreferencesByEnvironmententry, falling back to the global lists (legacyModelPreferences).storage.tskeeps the IndexedDB environment cache without the connection catalog, credentials, or GitHub routing permissions;threadRetention.tscaps idle thread snapshots by entries and size.- Cached data and drafts are cleared only when a workspace leaves the Coder config (stopped and disconnected workspaces also leave the platform registrations); the mapping is memory-only.
state/server.ts(client-runtime) and the web provider list stay limited to the helper's methods and the four drivers (isCoderProviderDriver);providerClients.tsregisters only those, and the Add provider dialog shows all four with no "Show more" fold or ACP Registry search (#25753).ProviderSettingsPanel'sProviderInstanceRowpasses no ACP sign-in, managed Codex runtime, or provider setup section (it passesacpProjectsfor Kilo Code's native sessions), andRemoteSessionGatedProviderSettingsgrants operate access without the remote-session check.
- Upstream's layout, pages, navigation, and search with Coder's Connections, Providers, GitLab, and
background-activity panels; no access, browser, devices, SnapShot, diagnostics, Integrations,
secrets, pairing, or
keybindings.jsoneditor pages._chat.settings.connections.tsxrenders the Coder deployments, workspaces, port forwards, and workspace links;settingsLayout.tsx'sSettingsSectiontakes adescriptionfor them.SettingsSidebarNav.tsxanduseAvailableSettingsSearchItems.tstake no settings scope search and have no T3 Connect sign-in, local backend, cloud, or WSL entries;movedSettingsPathnever points at a cut page; Labs' Beta section has only the Linked environments switch (no guest links or Simlock row); About has no mobile app row, privacy link, or update track switch. - Search carries
sourceControlHostSearchItemsbut notSOURCE_CONTROL_HOST_LABELS; the MR link target row lives on Diffs with GitLab search terms. Agent-credit removal applies only to GitHub merges, soProjectDefaultsSettings.tsxhas noremoveAgentCreditsOnMergerow and search has no "Remove agent credits when merging" item. - Appearance's Add theme is
ThemeImportDialogwithout the remote catalog or desktop picker. - Each workspace row carries
EnvironmentIconMenu; the helper reports noplatform.machine.environmentTransportLabelnames every workspace "Coder workspace", souseEnvironmentTransportLabelignores the prepared connection; older links naming one checkout resolve to its group. ProviderModelPicker.tsxhas noChatGptSharingControl, inline or in the docked list footer (subscription plans are out of scope).- Providers lists only the four drivers, without sign-in, setup, managed install, per-instance environment variables, ACP registry, or usage-limit sources; Source Control appends GitLab workspace status; update checks and the health interval do not mention model catalog updates.
ProviderInstanceCard.tsx,ProviderSettingsPanel.tsx, andProviderSettingsForm.tsxkeep the plain value andSecretInputfor environment and secret fields (no secret sources).- Background activity uses upstream's profiles without power-monitor intervals or lock pauses.
hooks/useEnvironmentDisconnectDelay.tskeeps onlyuseEnvironmentStateHeldFor. - Scheduled tasks: no "On webhook" option, URL, token rotation, signature, filter, replay, or coalesce fields, Deliveries dialog, or "Listening" status (no inbound webhook route); webhook tasks created another way keep their schedule but never run or offer Run now.
useNewProject.tssuggests no app access after publishing;state/sourceControlActions.tsneither.
persistence/Migrations.tsis upstream's registry with the same IDs; the auth migrations (20–22, 31, 32, 41) and 070–071 keep their IDs and create nothing.CoderMigrationHistory.tsfinishes the fork's old renumbered registry (IDs 41–58 with theCoderLegacy/migrations 050 and 055) and rewrites the history to upstream's IDs before upstream's migrator runs, reconciling a V2 preview ledger first.migrationEntriesstays exported for those tests;Migrations.test.tsomits #26288's file-name check. New migrations take upstream's next ID; never add a Coder-only ID.
- User-facing text says "merge request", "MR", and
!123wherever upstream says "pull request", "PR", or#123, and "T3 Coder" for "T3 Code": the web panels, composer, settings, toasts, and keybinding labels; the strings the web shows from client-runtime and shared; and the agent-facing server text (pullRequestWatch.ts,PullRequestWatchReactor.ts,mcp/toolkits/pullRequests/tools.ts, the orchestrator's unconfirmed-answer error,GitManagererrors). Identifiers, wire names, and search haystacks keep upstream's spelling; the composer trigger stays#;runtimeInstructions.tsstays upstream's. GitLab's definition supplies "MR" wherever upstream reads a host's terminology, and!123is applied by hand. Text for paths GitLab never reaches (native stacks,PullRequestsUnavailableState's GitHub link, GitHub-only rows) stays upstream's. These pure substitutions are not marked line by line; the seams check recognizes them.
apps/web/vite.config.tscarries upstream's office/pdf asset handling, route splitting and build manifest (the gateway reads.vite/manifest.jsonto cache hashed assets) but not the render scenarios project,VITE_RELEASE_CHANNEL, or source maps.- Root
vite.config.tsis upstream's without the remote task cache and cached test tasks (infra/is cut), the per-package test projects (vite.coder.config.tsreplaces upstream'sapps/server/vite.config.tsand extends this file, which therefore loadsgitConfig.setup.ts), and theoxlint-plugin-t3codeand@shadcn/lintrules. pnpm-workspace.yamlsetssupportedArchitectures(Linux x64 glibc) on every host, because the helper bundle ships those native modules (upstream sets it in the uncarried.pnpmfile.cjs);overridespin only the patched packages the fork carries plus Tailwind and lightningcss;@effect/platform-node>undiciis removed; the gateway pins its ownws/@types/ws;ignoredOptionalDependencieskeeps the Agent SDK's Claude binaries and@napi-rs/canvasoff the laptop.- TypeScript is Microsoft's TypeScript 7 (
typescript: 7.0.2), not the@tsc-rs/typescriptdrop-in whose unsigned Windowstsc.exeendpoint security may block; the fork omits its build approval, peer rule, and.pnpmfile.cjshook, and never ran@effect/tsgo. Rootengines.nodestays^24.13.1. - Package manifests (
package.json) andtsconfig.jsonfiles drop dependencies, scripts, exports, and includes for cut surfaces and uncarried tooling;routeTree.gen.tsis regenerated without cut routes;third-party-licenses.config.jsonlists no desktop bundle or desktop-only assets;scripts/lib/third-party-licenses.tsreads no device tool version pins. patches/@ff-labs__fff-node@0.11.0.patchadds the native grep struct'sfuzzy_scoreread at its real u16 width;patches/@legendapp__list@3.3.5.patchkeeps only thereact.jsandreact.mjssections.knip.jsonclists upstream files whose exports only cut surfaces use.packages/effect-codex-app-server: a spawned Codex child may print a bounded non-JSON preamble (CHILD_PROCESS_STARTUP_PREAMBLE_MAX_BYTES) before its first message; theprobescript is not carried.- No tracked shell scripts (a corporate download scanner rejects archives with one):
ProviderInstanceRegistry.test.tsandGitVcsDriverCore.test.tswrite upstream'scodexCollabMockPeer.shandGitVcsDriverCore.fixture.shinto their temp directories. - The real-Coder live harness (
scripts/coder-live-test.mjs,scripts/coder-live-template/) is local only and listed in.gitignore;scripts/coder-live-images.mjsandscripts/coder-live-provider-images.mjs(pnpm coder:live:providers) are tracked;pnpm coder:live:*andpnpm test:coder:livefail in a fresh clone. - Test adaptations, each marked: upstream's GitHub and Azure DevOps fixtures in the GitManager,
review-guide, guide-tool, T3 tool bridge, sync-key, and linked-thread tests use GitLab projects
and
refs/merge-requests/<n>/head; tests of uncarried hosts' behaviour are cut;GitManager.test.tsis upstream's fake-provider harness with a GitLab default kind;PullRequestSyncReactor.test.tscloses withglab mr merge/glab mr close;ClaudeAdapterV2.test.tsdrives the MCP control-channel tests through a fakeclaude;ClaudeAgentSdkQueryRunner.test.tsstubs the CLI transport'squery;ProviderSessionManager.test.ts's parallel shutdown test waits in real time;storageCleanup.test.tsuses real temp paths;serverSettings.test.ts,DatabaseStorage.test.ts,PullRequestService.test.ts,SourceControlRepositoryService.test.ts,presentation.test.ts,pullRequests.test.ts,threadShell.test.ts, andws.test.tsomit cases for cut surfaces;threads-sync.test.tsandthreads-atoms.test.tsfake history pages over the helper RPC;pullRequestsRouteSearch.test.tsruns under happy-dom;linkCreatedPullRequest.test.tsandopenPullRequestLink's browser test use GitLab URLs (no merge request commit-URL case);GitVcsDriverCore.test.tsexpectsReviewDiffFileTooLargeErrorwith a branded exit code;ProviderInstanceRegistry.test.tsruns the Claude one-probe fallback against the CLIquery;ProviderRegistry.test.tsruns without the Antigravity and OpenCode layers;SourceControlProviderRegistry.test.ts,SourceControlRepositoryService.test.ts, andRepositoryIdentityResolver.test.tsrun upstream's cases on GitLab remotes with the fork's mocks (the resolver's folder checks, #27980, read a FileSystem that reports every path as a folder);PullRequestService.test.tspasses branded GitLab kinds;chatCanvasLayout.test.tsandcanvasStore.test.tscarry no preview cases; the ACP Registry replay harness (AcpRegistryAdapterV2.testkit.ts,AcpAdapterV2.testkit.ts) runs without registry, Devin, Copilot lost-session (#26651), and session-management cases, plus a Coder test that the bridge command reaches the prompt;AgentScope.test.tsdrops the launcher check (agentScopeLauncherScriptis cut);GitLabPullRequestCli.legacy.test.tsexpectsDIFF_MAX_OUTPUT_BYTES;ProviderReplayFixtures.tslists only the carried drivers;CodexAdapterV2.test.tsexpectsT3CODE_THREAD_IDwithout the MCP servers (throughcodexThreadRuntimeParams, exported for it); client-runtime'sassets.test.tsbuilds the gatewayConnectionTargetin place of upstream's primary target;ChatView.logic.test.tsdrops preview annotations,useThreadActions.permissions.test.tsthe mini-player state,mediaContent.test.tsthe desktop media read, andsettingsSearch.test.tsthe browser search row. - Upstream's
*.browser.test.*files run in headless Chromium as thebrowserVitest project;reactCompilerCoverage.test.tsskipsCODER_UNCOMPILED_FILES. The fork keepsjsdomandreact-test-rendererfor its unit tests and forChatMarkdown.test.tsx,ProjectSettingsPanel.test.tsx, andRightPanelTabs.test.tsx, which stand in for uncarried browser tests (ChatMarkdown.browser,ChatMarkdown.permissions.browser).CommandPalette.browser.test.tsxmocksuseCoder; upstream'scomposerContextUndo.test.ts(preview annotations only) is not carried. Carried browser tests drop cut-surface cases:CommandPalette.compositionmocksuseCoderand picks the workspace first,StorageSettingskeys on the saved-image-artifacts title,useComposerContextImportdrops linked environments, images, and annotations,FilePreviewPanelhas no remote-open mock,PullRequestMarkdownruns on the GitLab-only registry,ProjectSettingsPanelkeepsprojects.getConfigpending and drops the fallback-model search target,ExpandedImageDialogdrops the SnapShot accessibility case, andProviderSettingsForm,ProviderModelPicker.composition, andReopenClosedViewShortcutdrop secret-source, provider, and preview cases,ChatHeadermocksCoderWorkspaceLatency, andPullRequestStackMenudrops the GitHub CLI refusal case.modelSelection.test.tsruns upstream's OpenCode instance cases on Claude instances and drops the Antigravity alias case (#27859). The fork-onlyhooks/useThreadActionMenu.test.tsxkeeps upstream's deleted hook test.
Files the fork deletes are listed, with a reason per category, in DELETED_PATHS in
scripts/sync-resolve-deleted.mjs; that list is the source of truth for whole deleted files and
directories. The surfaces below are cut; where a carried upstream file only loses code for one of
them, the file is named here.
- Desktop, mobile, hosted web, and T3 Connect. No Electron shell, desktop IPC
(
contracts/ipc.ts,resolveDesktopTheme), desktop update notices or pills, window controls,DesktopWebLinkCoordinator, desktop folder path lookup (folderDrop.ts), back/forward swipe navigation (HistorySwipeNavigation.tsx,navigationHistory.ts), mobile app links (MobileAppSettingsRow), hosted app, or prompt links (components/promptLinks/, the "Copy prompt link" actions, the automation row's link).Icons.tsxdropsOnePasswordIcon.media/mediaContent.ts'sfetchMediaBlobhas no desktop native read after a failed fetch (#29079). - Auth, pairing, and relay. No HTTP/WebSocket listener, session scopes, pairing, DPoP, relay,
or connection catalog;
settings/AddEnvironmentDialog.tsxis cut. The server'sauth/keepsServerSecretStore, its utils, andserverInternalPaths.ts(#28041), which the carried file readers import. With no session scopes, scheduled task lists show every webhook URL. - Browser preview and devices. No in-app browser, preview panel, mini-player, preview MCP
toolkits, device hosts, or agent device shim (port discovery stays:
preview/PortScanner.ts); provider-core's device instructions never reach an agent. Without browser preview,composerDraftStore.tskeeps no empty draft alive for an open page, andmergeDirectPreviewAnnotationis not carried. Deleting a thread clears its right-panel and diff-panel state (useThreadActions.ts'sclearDeletedThreadPanelState, #28386) but has no preview or mini-player state to clear. - Telemetry, usage, and diagnostics. No T3 telemetry, analytics, client-origin attribution,
metrics, OTLP or trace export (upstream's OTLP
config.test.ts), diagnostics page, NDJSON event logs, resource telemetry,observability/EventLoopMonitor.ts(no host-freeze toast orlastEventLoopStall), usage page or dashboard (shared/usageLimits.ts, provider-core and provider-piusage.ts;ProviderDriver.usageisnever), the thread details usage-limit rows (ThreadDetailsUsage's limit windows),useUsageLimitsPanel, or upstream's out-of-usage fallback (#26164;fallbackModelSelectionstays in the schema only;ProjectDefaultsSettings.tsxhas no fallback row or effort picker andsettingsSearch.tsno "Fallback model" item). Without the usage page,timestampFormat.tshas noresolveHour12. - Server self-update and CLI. No npm release check (
cloud/npmRelease.ts), "Update everything", update tracks,t3 doctorstorage status (DatabaseStorageNotice, client-runtime'sdatabaseStorageatom),persistence/DatabaseMaintenance.ts(sorebuildMessageSearchhas no caller),t3 triage, or desktop update button inlib/bootError.ts. - Local editors and open targets. No
OpenInPicker, open-in-editor, reveal, file manager, or remote open mode (MarkdownFileLink.logic.tshas nocanUseMarkdownFileShellActions). - Other providers and provider setup. Cursor, OpenCode, Muse, Grok, Antigravity, fx, the
dev-only replay provider (#26207:
DevReplayHost.tsx,apps/server/scripts/dev-replay*,window.t3dev), their replay fixtures (testkit/fixtures/index.tsandshared.tsdrop their entries), managed Codex (CodexManagedTokenBroker,__managed-chatgpt-token, ChatGPT Business admin requests #23361), provider sign-in, and Kilo Code's registry index, installs, auth controller, logout, native session deletion, and agent provider configuration (copilotAcp.ts,devinAcp.ts,nativeLogging.ts,@noble/hashes), the Antigravity send block, and Antigravity's native child work (#28629:NativeChildWorkQuery.ts,NativeChildWorkDialog.tsx, client-runtimestate/orchestration.ts'snativeChildWorkatom, and theChatView.tsxslot that rendered it). Codex feedback upload (client-runtimethreadCommands.tshas nouploadFeedback) and SnapShot sources are cut. - Hosted source control other than GitLab. GitHub, Azure DevOps, Bitbucket, Forgejo, and
GitCafe packages, host settings, tokens, accounts, routing, forge app sign-in (#26245,
SourceControlSignIn), app-access notices (sourceControlAppAccessToast.ts), and the GitHub star prompt (#27832,GitHubStarPrompt,checkStarred,useComposerSend'srecordPromptSent). WebSourceControlAppAccessNotice.tsx,T3AppIcon.tsx, andsettings/SourceControlAppSignInSettings.tsxare cut, and client-runtimestate/sourceControl.tsandsourceControlClients.tshave no app-access or sign-in atoms orappSignInTargetForRemote. - Linked-environment client pieces. The hub replaces pairing, so web
chat/LinkRequestCard.tsx,settings/LinkAccessPicker.tsx,LinkMachineSelect.tsx,LinkedEnvironmentsSettings.tsx,state/peerLinks.ts,state/peerPairingCode.ts, client-runtimelinkRequest.ts,PeerLinkRequests, the link-request timeline card (TimelineV2EventRow.tsx,session-logic.ts), and thet3_environment_link/unlinktool presentations (t3McpToolPresentation.ts,t3ToolSummary.ts) are cut. The peer tests that pair two HTTP servers (PeerForwarding.test.ts,RemoteDelegation.test.ts,linkOrigin.test.ts,PeerLinks.testkit.ts,PeerMcpClient.test.ts) are not carried;coderHub.test.tsand the gateway'shub.test.tstest the transport. - Guest sharing (#24104). Guest routes, pages, share controls, the "share-guest" thread action
(
threadActionMenu.logic.ts,useThreadActionMenu.ts,Sidebar.tsx,contextMenuFallback.ts), guest footers and bubbles (ChatView.tsx,TimelineUserMessageRow.tsx,QueuedRunsControl.tsx, which has no guest names or per-itemeditableflag), the guest-request pill (Sidebar.logic.ts,SidebarThreadRow.tsx), Labs' guest-links row (LabsSettingsPanel.tsx),mainAppLocation.ts's guest page, the--guest*CSS tokens, and guest screenshots (#26323:HostImageUrlContext,hostImageUrl.ts,TOP_STATUS_ICONS' guest entry).runtimeLayer.tsprovides noGuestShareService; the contracts, decider, commands, and projection columns stay for the unions. - Triage (#22753).
apps/server/src/triage/**,server.prepareTriage, the palette entry (CommandPalette.tsx), the draft hero (DraftHeroHeadline.tsx),useHandleNewThread'spromptoption, client-runtime'sprepareTriage, anddocs/user/triage.md. - Secret providers (#25709, #27044, #27115, #27746). The secrets settings, 1Password, the
T3CODE_FEATURE_SECRETSflag, the/settings/secretsroute,@t3tools/secret-provider-core, and the server'ssecrets/SecretResolver.ts,secretProviderDefinitions.ts, andsecrets/settingsSecretValue.ts.secrets/coderSecretResolver.tsstands in for the resolver inProviderInstanceRegistry.ts,ProviderInstanceRegistryHydration.ts, andserverSettings.ts: it reads no reference (an instance whose variable points at one is unavailable with upstream's "Could not read …" reason) and lists no kind (secretProviderswrites are rejected);ws.tsdoes not advertisesecretReferences. - Managed policy (#27197). Organization-wide policy files, the Windows registry and macOS
profile readers (
ffi-rs),t3 policy, policy-locked settings and providers, runtime-mode ceilings, and their notices are cut: no contractsmanagedPolicy.ts, sharedmanagedPolicyFile.ts, serverpolicy/, webManagedPolicy.tsxorstate/managedPolicy.ts, ordocs/user/managed-policy.md. The sync merged #27197 with the tree of its parent, so these carried files keep upstream's code from before it in place of its hunks: contractsauth.ts,index.ts,orchestratorMcp.ts,providerPolicy.ts(noisRuntimeModeAbove),scheduledTask.ts(blockedByPolicy),server.ts, andsettings.ts; provider-coreProviderAdapter.ts(maxRuntimeMode) andinstanceEnvironment.ts; provider-acpadapter.ts(runtimeModeForSessionMode); serverauth/utils.ts,mcp/McpInvocationContext.ts,mcp/OrchestratorMcpService.ts,mcp/threadAccess.ts,mcp/toolkits/project/handlers.ts,ClaudeAdapterV2.ts,CheckpointRollbackService.ts,DispatchModeLimit.ts,Orchestrator.ts,ProviderTurnStartService.ts,RestartContinuation.ts,RuntimePolicy.ts,ThreadMessageIntake.ts,testkit/ProviderReplayHarness.ts,AgentSessionImporter.ts,ProviderInstanceRegistry.ts,ProviderInstanceRegistryHydration.ts,ScheduledTaskService.ts,server.ts,serverSettings.ts, andws.ts; webChatComposer.tsx,ComposerFooterControls.tsx,ModelPickerSidebar.tsx,ThreadAutomationsPanel.tsx,AddProviderInstanceDialog.tsx,LabsSettingsPanel.tsx,ProjectDefaultsSettings.tsx,ProviderInstanceCard.tsx,ProviderSettingsForm.tsx,ProviderSettingsPanel.tsx,ScheduledTasksSettings.tsx,SettingsPanels.tsx,StorageSettings.tsx, andsettingsLayout.tsx; anddocs/user/install.mdandpermission-modes.md. Later upstream code that builds on #27197's non-policy refactors takes upstream's form (CodexDriver.tspassesHostProcess.EnvironmenttomergeProviderInstanceEnvironment). - Add to another machine (#22180, #22254). It copies ignored files such as
.envbetween workspaces through the browser: nolistIgnoredFiles,projects.listIgnoredFiles(ignoredFileListingomitted), client-runtimeprojectCommands.tscommand,BranchToolbar.tsxmenu entry (BranchToolbar.logic.ts'sADD_TO_MACHINE_LABEL_CLASS), orChatView.tsxfile-copy banner. - Offline query persistence and upstream's mobile-only helpers. See Web state and persistence.
- Upstream repository tooling and CI-only checks.
apps/web/scripts/verify-built-boot.ts,AgentContextBudget.test.tsandagentContextBudget.json,.pnpmfile.cjs, and upstream's 14k-lineAcpAdapterV2.test.ts. The v1 importer carries only messages, so pre-v2 screenshotartifactsare not shown, as on upstream. - Shared helpers only cut surfaces used:
shared/projectFavicon.tskeepsPROJECT_FAVICON_EXTENSIONSprivate,shared/t3ProjectFile.tsdropsbuildT3ProjectFileJsonSchema, sharedAgentScope.tsdropsagentScopeLauncherScript, sharedshell.tsdrops the desktop'sapplyShellEnvironment(#28556), andPullRequestsPage.tsxdrops its preview-session placeholders.
npm start builds the web client and a Linux x86-64 helper bundle from the checked-out source and
lockfile, including the locked native runtime packages needed by terminals and workspace search,
then starts the local gateway and opens its loopback URL in the default browser. Connecting never installs from npm or
downloads an application update. The first connection may download the pinned Node.js package
through Nix if it is not already in the workspace's Nix store. The gateway hashes the locally
built helper bundle (SHA-256 over its relative paths and contents) once per session and passes the
hash to the helper launch, which compares it with the .t3-bundle-sha256 file in the installed
helper directory. When they differ, the launch prints T3_CODER_HELPER_INSTALL_REQUIRED and exits
before starting the helper; the gateway then replaces the remote helper directory with the local
bundle over coder ssh stdin, verifies and records the hash, and launches again. A workspace whose helper
is current therefore connects with one coder ssh session and no transfer. Connection diagnostics
show the preflight, any installation, and helper negotiation as separate phases.
The helper runs upstream's opt-in storage cleanup policies. Worktree cleanup holds the same
workspace lease as provider startup and terminal open, rechecks sessions and Git state,
and preserves branches and thread history. Artifact retention maps upstream's browser-artifact
store to the legacy screenshotArtifactsDir; it never visits attachmentsDir or current image
source paths. Artifact, worktree, and rotated-log policies are disabled by default.
Upstream's Delete now action and latest cleanup report travel over the helper's
server.runStorageCleanup and server.getStorageCleanupReport RPCs; the report keeps only the
latest sweep in helper memory. Each of these is marked Coder::
coderServer.tsbuildsStorageCleanup.layerafterCoderRuntimeStartupcompletes, where upstream parks its sweeps until server activation.- The report calls artifact rows "saved image artifacts".