Skip to content

feat(connection): support multiple routes per environment - #7921

Closed
burnmandont wants to merge 9 commits into
pingdotgg:mainfrom
burnmandont:pr/connection-multiroute
Closed

burnmandont wants to merge 9 commits into
pingdotgg:mainfrom
burnmandont:pr/connection-multiroute

Conversation

@burnmandont

@burnmandont burnmandont commented Aug 22, 2026 •

Copy link
Copy Markdown

What Changed

  • Persist multiple connection routes for one stable environment identity.
  • Let desktop users switch between available relay and SSH routes without creating duplicate environments.
  • Reuse an already-running remote T3 server and its credentials when connecting over SSH.
  • Preflight and verify route identity before selection, and make SSH route transitions reliable.
  • Remove only the relay route during relay sign-out, preserving SSH or direct access where available.
  • Keep mobile storage compatible with the shared route catalog without adding mobile route-selection UI.

Why

A remote environment can be reachable through more than one transport. Treating each transport as a separate environment duplicates projects and state, while replacing the active target loses a working fallback. This keeps environment identity durable and makes transport selection a device-local routing concern.

UI Changes

Adds route visibility and manual route selection under Settings → Connections. Mobile route selection is intentionally out of scope.

Screenshots will be added before this draft is marked ready for review.

Verification

  • 107 focused tests passed across client-runtime connection storage/registry/resolver/supervisor, SSH tunneling, web storage/platform, and mobile storage.
  • Typechecks passed for client-runtime, web, mobile, and SSH packages.
  • git diff --check passes against upstream/main.
  • No server migration is required.

Checklist

  • This PR is focused on multi-route connection persistence and selection
  • I explained what changed and why
  • I included screenshots for the Settings UI changes
  • No animation or motion behavior changed

Prepared with GPT-5.6-Sol via the Codex harness in T3 Code.

Note

Add support for multiple connection routes per environment

  • Introduces a routes model in the connection catalog and registry so an environment can hold multiple connection paths (e.g. relay + SSH) simultaneously, with a selectRoute API that prepares the candidate before swapping the active session.
  • Adds a desktop UI dropdown in SavedBackendListRow to switch routes, backed by new atoms and a selectRoute command in createEnvironmentCatalogAtoms.
  • SSH connections now cache and reuse bearer tokens, refreshing them only on authentication failures; the SSH establishment timeout increases from 15s to 120s.
  • Reworks remote SSH scripts to serialize via cross-process flock locks, discover and reuse an already-running T3 server, and retry transient database is locked errors during pairing.
  • Updates persistence layers (ConnectionTargetStore.listRoutes, ConnectionRegistrationStore.select/removeRoute) and storage document helpers to register, select, and remove individual routes while preserving others.
  • Risk: removeConnectionFromCatalog now clears all persisted data for the environment across all routes and deletes remote DPoP tokens; installPlatformRegistration clears stored routes for the environment — reviewers should verify no callers depend on the old single-route removal semantics in storageDocument.ts and registry.ts.

Macroscope summarized 236484a.


Note

High Risk
Touches persisted connection catalogs, credential reuse, SSH launch/pairing scripts, and live session swap. Failures here can drop sessions, mix environments, or leave remote servers in a bad state.

Overview
Lets a single environment keep multiple access methods (T3 Connect, SSH, direct) instead of replacing or duplicating it. Desktop users pick the method from Settings; the choice is local and never auto-falls back.

Selection is preflighted. selectRoute prepares and verifies the candidate (including stable environment ID) while the current session stays live. Persistence and supervisor swap happen only after that succeeds. Failed prep leaves the selected route and session unchanged.

Catalog persistence now stores routes plus one selected target. Registering SSH on a relay environment retains both. Relay sign-out removes only the relay route and falls back to SSH/direct when present. Legacy catalogs treat targets as initial routes.

SSH reuse. Cached SSH bearers are reused and re-paired only after auth rejection. Remote launch discovers a live t3code.service / T3CODE_HOME runtime, pairs against that base dir, serializes operations with flock, and retries locked-database pairing. SSH connect timeout is 120s. Mobile storage is route-capable but has no switcher UI.

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

@coderabbitai

coderabbitai Bot commented Aug 22, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad01a8e4-6d2b-4374-aaf9-5333f62280bf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 22, 2026

@macroscopeapp macroscopeapp 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.

One finding on the new connection-method picker in apps/web/src/components/settings/ConnectionsSettings.tsx: the trigger size does not match the other controls in the same action row. Details inline.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated

@macroscopeapp macroscopeapp 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.

Effect service conventions review of the changed TypeScript. Three findings, all in packages/client-runtime/src/connection: two error-handling shapes that should use Effect.catchTags, and one reuse of a removal-specific error for route selection whose message reaches the user.

Posted via Macroscope — Effect Service Conventions

Comment thread packages/client-runtime/src/connection/registry.ts Outdated
Comment thread packages/client-runtime/src/connection/registry.ts
Comment thread packages/client-runtime/src/connection/resolver.ts
Comment thread packages/ssh/src/tunnel.ts
Comment thread packages/ssh/src/tunnel.ts
Comment thread packages/client-runtime/src/platform/storageDocument.ts
Comment thread packages/ssh/src/tunnel.ts Outdated
Comment thread packages/ssh/src/tunnel.ts Outdated
Comment thread packages/ssh/src/tunnel.ts Outdated

@macroscopeapp macroscopeapp 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.

One finding on the new route picker in ConnectionsSettings.tsx. The earlier trigger-size mismatch is resolved (size="xs" now matches the neighbouring Button size="xs" controls at both breakpoints).

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated

@macroscopeapp macroscopeapp 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.

One finding on the new connection-method picker in ConnectionsSettings.tsx. Trigger geometry (size="xs" + w-full min-w-0 sm:w-48) now matches the sibling Button size="xs" controls and the IntegrationsSettings select pattern, so the earlier sizing/width findings look resolved.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
@burnmandont
burnmandont marked this pull request as ready for review August 22, 2026 21:45
Comment thread packages/ssh/src/tunnel.ts
@macroscopeapp

macroscopeapp Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Skipped

Macroscope did not run approvability analysis for this PR. Macroscope could not determine whether this PR modifies its approvability configuration, so the PR was not approved automatically. A PR that may change the rules that govern approval is never approved automatically.

@burnmandont
burnmandont force-pushed the pr/connection-multiroute branch from b46ff3f to 93ce180 Compare August 22, 2026 22:13
@burnmandont
burnmandont force-pushed the pr/connection-multiroute branch from 93ce180 to 236484a Compare August 22, 2026 22:16

@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 high effort and found 1 potential issue.

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 236484a. Configure here.

return keys;
}, [savedEnvironments]);
const [sshConnectionError, setSshConnectionError] = useState<string | null>(null);
const [switchingRouteEnvironmentIds, setSwitchingRouteEnvironmentIds] = useState<

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.

SSH dedup ignores inactive routes

Medium Severity

savedDesktopSshEnvironmentKeys and savedDesktopSshEnvironmentsByAlias only inspect the selected catalog entry. When relay is selected but an SSH route already exists, that host still appears in unsaved discovered hosts. Choosing it re-runs SSH provisioning and forces a route switch instead of treating the host as already saved.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 236484a. Configure here.

@t3dotgg

t3dotgg commented Aug 23, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

Closing this PR after an automated pass over open pull requests. Introduces a substantial cloud, virtual-machine, remote-filesystem, or forwarding system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 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.

2 participants