Skip to content

Let the desktop app be a client of an existing T3 Code server - #9376

Open
colonelpanic8 wants to merge 333 commits into
pingdotgg:t3code/codex-turn-mappingfrom
colonelpanic8:t3code/orchestration-v2-main/client-environment-suite
Open

Let the desktop app be a client of an existing T3 Code server#9376
colonelpanic8 wants to merge 333 commits into
pingdotgg:t3code/codex-turn-mappingfrom
colonelpanic8:t3code/orchestration-v2-main/client-environment-suite

Conversation

@colonelpanic8

@colonelpanic8 colonelpanic8 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Let the desktop app be a client of an existing T3 Code server

Fixes #6097. Supersedes #4444 and folds in #4496 and #4559.

Based on #2829's branch (t3code/codex-turn-mapping) rather than main: the new orchestrator rewrites the client state and settings surfaces this change touches, so a main-based version would only conflict with it. The same series against main is kept at colonelpanic8/t3code:t3code/client-environment-suite-main for reference.

The problem

Since t3 service (#4286, #6286) a T3 Code server can outlive the desktop app. But the desktop app still assumes it owns the machine's backend: on launch it sees port 3773 busy, picks 3774, and starts a second backend against the same ~/.t3/userdata/state.sqlite. Two servers then contend for one SQLite database and requests fail with database is locked (#6097). Users in that thread asked for the obvious alternative, a thin client, and explained why the browser PWA is not a substitute: browser hotkeys conflict and several settings are unavailable outside the app.

The mobile app already works this way. It owns no backend and pairs with whatever environments it is given. This PR gives the desktop app the same option.

What changes

The desktop app never starts a second backend against a state directory that already has one. On launch it reads the server-runtime.json a live server persists next to its database, exactly as t3 pair does, confirms the pid is alive and the process answers with the environment descriptor recorded next to it, and if so runs this launch as a client of that server instead of spawning its own. This is the same discovery t3 pair and t3 triage already rely on, so there is no new on-disk format and no new HTTP surface. Connections explains why the app is in this state and offers to pair with the running server.

Client-only mode. Users can also opt into this permanently (Settings → Connections → Backend mode) or per launch (--backend-mode client-only). In client-only mode the app serves its packaged renderer from static assets, opens the window when the renderer is ready rather than when a backend is, and does not stop any backend on quit. A client-only app with no saved connections lands on Connections instead of a dead primary-backend state.

Pairing with a server on this computer. Connections lists servers discovered through their runtime state. Pairing mints a one-time credential by running the bundled server's t3 pair --json against that state directory, which writes into the running server's own database. Same-user proof is filesystem access to the state directory, which is the trust model t3 pair already uses. Works on every platform.

Settings target an environment. A client with no backend of its own has nothing to call "primary", so settings that live on a server (environment general settings, providers, source control, keybindings, diagnostics) are addressed to an explicitly selected environment through one shared header that shows the same loading/offline/error state everywhere, and settings that belong to the client (general, appearance) are grouped separately in the navigation. Restore-to-defaults resets only the keys a page owns. Any connected client can manage pairing links and authorized clients for that environment, not only for a locally spawned one.

Commits

The series is squashed onto the orchestrator branch as one commit; the original seven-commit series is on the main-based reference branch and is meant to be read in that order.

  1. feat: client-only desktop mode and environment-scoped settings, the mode, IPC, static renderer serving, web routing, presence scope, and settings pages.
  2. shared: move server runtime state reading into packages/shared, so the desktop can read runtime state without depending on the server package.
  3. cli: add --json to t3 pair, following the existing t3 auth ... --json convention.
  4. desktop: discover local servers through runtime state and pair via t3 pair, replacing an earlier Linux-only advertisement scheme that needed a new unauthenticated endpoint.
  5. desktop: attach to a running server instead of spawning a second backend, the [Bug]: Desktop starts a second backend against the background service database #6097 fix.
  6. web: unify environment-scoped settings selection and presentation.
  7. web: drop per-environment accent colors and display names, cosmetic client preferences split to a follow-up.

Prior art

Paseo, another local-first agent runner, settled on this shape: the daemon runs detached, the desktop app reuses a daemon that is already running rather than starting another, and a manageBuiltInDaemon setting turns the desktop into a pure client. Its desktop shells out to the bundled CLI for daemon status --json the way this PR shells out to t3 pair --json.

Not in this PR

Per-environment accent colors and custom display names, which were part of earlier revisions, are split out to keep this reviewable. Auto-pairing on attach is a one-line follow-up once the approach is agreed; this PR asks for one explicit Pair click.

Verification

  • vp run --filter @t3tools/desktop --filter t3 --filter @t3tools/web --filter @t3tools/contracts --filter @t3tools/client-runtime --filter @t3tools/shared typecheck: clean.
  • vp lint --report-unused-disable-directives and vp fmt --check over every changed file: clean.
  • Focused vp test run over apps/desktop (app, ipc, settings, electron, backend pool, exposure, updates, window), apps/server (cli, auth, startup access, server), apps/web (settings, environments, presence, grouping, hooks), packages/client-runtime (connection), packages/shared, packages/contracts: 132 files, 1307 tests, all passing.

Note

High Risk
Changes desktop startup, shutdown, and custom-protocol serving (including static file handling and pairing subprocess trust), which are security- and data-integrity-sensitive paths.

Overview
Adds a managed vs client-only desktop backend launch path so the app can run without spawning its own server and can reuse one that is already running.

Launch and lifecycle: Settings and --backend-mode resolve the effective mode; packaged managed launches auto-switch to client-only when a live userdata server is found via persisted runtime state (same discovery as t3 pair). Client-only bootstrap registers the custom protocol as a dev proxy or static packaged renderer, opens the window on renderer readiness, skips managed backend startup/shutdown, and surfaces fatal errors for invalid mode flags or missing packaged assets.

Local server UX: New IPC discovers running servers and pairs by shelling out to bundled t3 pair --json, with strict validation of pairing URLs. Changing backend mode persists settings and triggers a shutdown-then-relaunch sequence (with rollback if relaunch fails).

Web: Remote/local thread and sidebar grouping use an environment presence scope instead of comparing everything to the primary id; client-only desktop hides managed local bootstraps. Connections settings logic gains local-server pairing candidates and safer pairing base URLs per connection type.

Shared/server: Server runtime state read/write moves to @t3tools/shared; t3 pair gains --json for machine-readable output.

Reviewed by Cursor Bugbot for commit 5b21d4f. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add client-only backend mode to desktop app and split settings by environment

  • Adds a managed vs client-only backend mode to the desktop app. In client-only mode, the app skips the managed backend, serves the renderer through a development proxy or packaged static assets, and connects to an existing T3 Code server. A packaged managed launch auto-switches to client-only when a live userdata server is discovered.
  • Adds local server discovery and pairing through IPC channels. The connections settings page scans for running local T3 Code servers and lets users pair, pair again, or see already-paired servers.
  • Splits settings into client-owned (general) and environment-owned (environment) pages. Environment settings, diagnostics, resource telemetry, and provider configuration now target a selected environment instead of always the primary environment.
  • Adds an environment selector and shared SettingsEnvironmentScope that withholds content while the environment is loading, connecting, or missing published configuration.
  • Fixes SSH catalog display URLs to omit empty usernames and include configured ports, and removes presentation scopes from pairing registration requests.
  • Risk: DesktopBackendManager.makeBackendInstance finalizer now calls stop only when start was requested; DesktopLifecycle restart now surfaces DesktopLifecycleRelaunchError instead of swallowing failures. setBackendMode IPC restores the prior setting on relaunch failure. Client-settings updates now defer until hydration completes, which changes write timing for useUpdateClientSettings and useUpdateSettingsTarget.

Macroscope summarized 8244310.

PixPMusic and others added 30 commits September 2, 2026 10:48
Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Fixes review: pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Clears the timed-out turn with an identity guard so a late completion cannot clobber a newer active turn.

Addresses pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Passes the current target thread MCP configuration through ACP load, resume, and fork requests instead of reusing the credentials captured when the provider process opened.

Addresses pingdotgg#2829 (comment)

Co-authored-by: codex <codex@users.noreply.github.com>
Integrate the current Grok settlement, monitor/subagent lifecycle, interrupt containment, steer visibility, and image support stack into the orchestration-v2 branch.

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Settle root turns from provider signals and preserve post-settle continuations.

Track asynchronous subagent and monitor work, allow image prompts, and keep steered messages visible.

Separate soft steering from hard Stop while containing and reaping native process trees.
Co-authored-by: codex <codex@users.noreply.github.com>
Reuses the focused compatibility approach from closed PR pingdotgg#3923 and covers the remaining hardware-keyboard reverse iteration.

Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Pretty-print known T3 MCP tool names in work rows
- Show the T3 Code logo for recognized MCP tool entries
- Add logic and UI tests for the new tool presentation
- Extract shared T3 MCP tool label resolution
- Show T3 Code branding for matched tool activity rows
- Add tests for shared resolution and mobile feed output
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
…4457)

Update every deterministic Codex turn/start expectation with the explicit user approvals reviewer emitted by the adapter, restoring exact replay coverage and unblocking the merge lane.
juliusmarminge and others added 18 commits September 2, 2026 10:48
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.

Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopts the round's main features into the v2 architecture: the pingdotgg#9023
media rework (streamed videos, media-file assets, protocol-relative
links), pingdotgg#9098 shared live-activity row folded into the v2 working and
thinking rows, the pingdotgg#9084/pingdotgg#9078 Claude model catalog for v2 consumers,
a native pingdotgg#9005 OpenCode child-session abort in the v2 adapter, pingdotgg#9013's
landed LegendList patch, and per-environment sidebar provider entries.
For pingdotgg#8600 the server-side pieces land, but auto-settle evaluation stays
client-side (reading the new server-owned settings) until the v2
orchestrator grows its own settlement reactor; main's v1-only reactor
and coalescer additions are dropped with the rest of the v1 path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ator

Ports pingdotgg#8600's server-owned settlement to orchestration v2 instead of
keeping client-side evaluation. A ThreadSettlementService sweep runs at
startup, on auto-settle settings changes, and once per minute: it
evaluates inactivity and merged or closed pull requests over v2 thread
shells and dispatches the new guarded thread.auto-settle command, which
rejects threads that changed after the sweep's snapshot or carry any
explicit override, then reuses the orchestrator's settle lifecycle.
With the server deciding, the clients drop their effectiveSettled
evaluation and partition on the persisted settledOverride like main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (pingdotgg#8992), sidebar row subscription leases (pingdotgg#9052),
tool group virtualization and scroll anchoring (pingdotgg#9106), repeated-command
and browser-group presentation, inline assistant citations (pingdotgg#9146),
per-cwd provider skills discovery (pingdotgg#8778), Claude composer skill
dispatch (pingdotgg#9128), grok health probe and model negotiation (pingdotgg#9154), and
the failed-tool thinking fallback (pingdotgg#9165).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 17 adopted main's pingdotgg#8850 ComposerBanner.Attachment (mx-auto plus the
standalone drawer-inset width) without main's matching mounts, so the
stash tab's ml-auto lost to the attachment's auto right margin and the
tab centered over the composer. Column now spans its attachments like
main does, the stash tab zeroes the right margin, and the stash menu
keeps the full dock width.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The branch had drifted from main's composer and work-log design in ways
unrelated to orchestration v2: a pre-revert "Working for" shoulder tab
on the composer (main reverted pingdotgg#8693 and re-landed pingdotgg#8734 without it),
an inline stash variant plus in-flow stash menu, expanded tool rows that
hid their icons, an unmounted woke-thread banner, a composer scroll
observer main never had, and a right-panel toggle that lost its
showRightPanelControl gate so it rendered twice with the panel open.

ChatComposer and its satellites now start from main's files with only
the v2 delta re-applied (dispatch modes, queued-message editing, runtime
request ids, response capability). Background tasks surface as a
ChatView banner in main's backgroundLiveness shape instead of a
composer tab. SimpleWorkEntryRow takes main's PlainWorkEntryRow body
with the V2ItemInspector kept behind the expander.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renumbers the v2 migrations 044-052 to 045-053 behind main's
044_ClearAutomaticProjectModelDefaults, and adopts main's sticky
new-thread selection (pingdotgg#9164), local-only worktree bases in the v2 launch
path (pingdotgg#8751), the PR summary read for settlement (pingdotgg#9176), Claude per-cwd
skills (pingdotgg#9210), the provider editor redesign with the branch's dedicated
environment fields re-grafted (pingdotgg#8508), and the client half of
continue-threads-across-restart (pingdotgg#9167). The server-side continuation
markers stay unported: they live in the v1 session directory, and v2
recovery terminalizes running runs on restart, so the capability is
withheld until the v2 runtime carries them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-scoped settings

Let the desktop app run as a client of an existing T3 Code server.

- A packaged desktop app that finds a live server owning its userdata
  state directory (via server-runtime.json, pid, and environment
  descriptor, exactly as t3 pair does) runs that launch as a client
  instead of picking another port and starting a second backend against
  the same database (pingdotgg#6097).
- A persisted backend mode (managed | client-only) with a launch-only
  --backend-mode override, exposed over IPC. Client-only bootstrap skips
  the backend pool, serves the packaged renderer from static assets (or the
  dev-server proxy), opens the window on renderer readiness, and does not
  stop backends on quit.
- Connections lists servers discovered through runtime state and pairs by
  running the bundled server's `t3 pair --json` against that state
  directory. Runtime-state reading moves to packages/shared so the desktop
  can use it; `t3 pair` gains --json.
- The web app treats a client-only desktop like the hosted static app: no
  primary environment, and a presence scope decides which environments are
  remote. Server-owned settings address an explicitly selected environment
  through one shared header; client-owned settings are grouped separately;
  any connected client can manage an environment's pairing links and
  authorized clients.

Squashed port of colonelpanic8/t3code:t3code/client-environment-suite
(seven commits on upstream main d42254d, PR pingdotgg#9361) onto the
orchestrator branch at d2f1f51. Settings that only exist on main
(diff layout, proactive panels, panel animations) are not referenced.
@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $10.27, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

File Diff Size Estimate
apps/web/src/components/settings/SettingsPanels.tsx 44.71KB $2.24
apps/web/src/components/settings/ConnectionsSettings.tsx 32.23KB $1.61
apps/desktop/src/app/DesktopRunningLocalServers.ts 10.35KB $0.52

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Sep 3, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a broad client-only desktop and local-server pairing capability across startup, authentication, IPC, server CLI, and web settings, rather than making a small isolated change. It also adds a static-analysis suppression and has unresolved reports of normal local pairing failures and an unsafe relaunch sequence.

Not approved because:

  • Per-review cost limit exceeded (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings, or comment @macroscope-app review this PR to bypass the limit and review now. You can add or adjust custom eligibility rules. Learn more.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8244310. Configure here.

reason: "request_failed",
detail: "The local T3 Code pairing command returned an invalid pairing link.",
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pairing rejects valid local URLs

High Severity

Local pairing treats a t3 pair --json link as invalid unless its origin equals the discovered backend origin. t3 pair builds that link from devUrl or resolveHeadlessConnectionString, which is localhost or a LAN address when the server did not bind an explicit host, while persisted origin is 127.0.0.1. Pairing with the default local server therefore fails after the CLI succeeds.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8244310. Configure here.

}),
Effect.forkDetach,
Effect.asVoid,
Effect.tapError((error) => logLifecycleError(error.message, { error })),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relaunch queued before shutdown

Medium Severity

Packaged relaunch now calls electronApp.relaunch() before shutdown. setBackendMode rolls settings back if that later shutdown fails, but Electron has already queued a restart and there is no way to cancel it. The next quit then relaunches unexpectedly with the restored mode, after quitting has already been set.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8244310. Configure here.

colonelpanic8 added a commit to colonelpanic8/dotfiles that referenced this pull request Sep 3, 2026
Assembly tag t3code-assembled/20260903T080821Z: base moved to upstream
#2829's head, every carried topic rebased onto it, and the client suite
carried as the head branch of pingdotgg/t3code#9376.
@colonelpanic8
colonelpanic8 force-pushed the t3code/orchestration-v2-main/client-environment-suite branch from 5b21d4f to 8244310 Compare September 3, 2026 21:32
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch 4 times, most recently from b82facd to 2ac9bfe Compare September 5, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants