Skip to content

Architecture proposal: first-class remote backend targets (with WSL as the first implementation) #671

@AxENSRennes

Description

@AxENSRennes

Related: #192

Summary

T3 Code should support running its backend outside the local desktop environment through a first-class BackendTarget model, instead of treating WSL or other remote environments as shell/path special cases.

The most immediate use case is Windows + WSL, but the same architecture would also make future remote targets possible (for example SSH or other Linux hosts).

The core idea is:

  • keep the desktop UI local
  • run the backend natively in the selected target environment
  • let the desktop process resolve, start, supervise, and reconnect that backend
  • keep the renderer connected through one stable desktop-provided endpoint
  • expose target capabilities to the UI instead of scattering target-specific checks everywhere

Why this matters

WSL support is deceptively hard to get right if it is approached as a subprocess or path-conversion problem.

A naive implementation usually turns into some combination of:

  • spawning wsl.exe ad hoc
  • translating paths back and forth in multiple places
  • letting the renderer infer execution context indirectly
  • mixing Windows desktop concerns with Linux runtime concerns

That tends to become brittle around:

  • terminal behavior
  • Git/toolchain behavior
  • cwd semantics
  • Linux-native workspace paths
  • reconnect/restart handling
  • version compatibility
  • network transport differences
  • desktop integrations like folder selection or opening files in an editor

If T3 Code wants WSL to feel reliable and native, WSL should be modeled as a real backend target, not as a compatibility mode.

Why this is also a general remote-backend issue

After looking at T3 Code’s current structure, VS Code’s remote architecture, the public Remote - WSL package, code-server, devcontainers/cli, and WSL docs, the pattern is pretty consistent:

  • the client UI stays local
  • the backend runs natively in the target environment
  • transport is a separate concern
  • startup is deterministic
  • auth and version compatibility are explicit
  • target capabilities are modeled directly

That is useful for WSL, but it also sets up a clean path for future remote targets.

So this issue is intentionally broader than “add WSL support”: it is proposing the abstraction that would make WSL the first clean implementation.

Current T3 Code shape

T3 Code already seems close to supporting this architecture:

  • the desktop app starts the backend process in apps/desktop/src/main.ts
  • the renderer already depends on a desktop-provided WebSocket URL through the desktop bridge
  • the backend is already separated enough from the UI boundary that target-aware startup could live mostly on the desktop side

That suggests this can be introduced as a lifecycle/target refactor, not as a frontend rewrite.

Proposal

1. Introduce an explicit backend target model

Something like:

  • local
  • wsl:auto
  • wsl:<distro>

Longer term this could also support:

  • ssh:<host>
  • other remote Linux targets

2. Move backend lifecycle behind a desktop-side controller

Instead of assuming one local child process forever, the desktop app should own a target-aware controller responsible for:

  • resolving the target
  • selecting the distro/host
  • bootstrapping the backend
  • readiness detection
  • reconnect/restart policy
  • surfacing errors and diagnostics
  • exposing target metadata/capabilities to the renderer

3. Run the backend natively in the target

In WSL mode, the backend should run inside the selected distro, not on Windows.

That preserves the right semantics for:

  • Linux paths
  • shell/cwd behavior
  • Git
  • package managers
  • local toolchains
  • terminal sessions

4. Keep one stable renderer-facing connection contract

The renderer should not need to know if the backend is local, in WSL, or elsewhere.

It should keep consuming:

  • one desktop-provided connection endpoint
  • one set of target metadata/capabilities

5. Expose capabilities instead of adding isWsl checks

For example:

  • requiresLinuxWorkspacePaths
  • supportsNativeFolderPicker
  • supportsDesktopEditorBridge
  • supportsTargetBootstrap
  • supportsReconnect

This keeps UI logic from becoming target-specific over time.

6. Keep desktop-only integrations on the desktop side

Especially in WSL mode:

  • folder picking should not blindly inject Windows paths into a Linux backend
  • opening files in an external editor should remain desktop-owned
  • path translation should happen only at explicit boundaries, not throughout core runtime logic

7. Keep backend startup deterministic

Startup should not depend on interactive shell init files or user shell customization.

That is one of the clearest lessons from the mature remote tooling already out there.

Why WSL should be the first target

WSL is the most practical first implementation because it exercises the exact boundaries that a general remote architecture needs:

  • different runtime OS from the desktop app
  • different filesystem semantics
  • different path formats
  • different shell/toolchain environment
  • target-local backend process
  • desktop-local UI integrations
  • transport/reconnect concerns

If the abstraction works for WSL, it is much more likely to scale to future remote targets cleanly.

Sources that support this direction

VS Code / Remote WSL

VS Code’s public OSS and distributed Remote - WSL package strongly suggest the following model:

  • WSL is treated as a real remote authority / target identity
  • the client resolves that target on the desktop side
  • a Linux-native server is started in WSL
  • the client connects through a stable resolved endpoint
  • startup is kept deterministic

Relevant references:

  • VS Code remote authority infrastructure:
    • src/vs/platform/remote/common/remoteAuthorityResolver.ts
    • src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
  • WSL detection in core:
    • src/vs/platform/remote/node/wsl.ts
  • Windows shell handoff:
    • resources/win32/bin/code.sh
  • WSL sanity tests:
    • test/sanity/src/wsl.test.ts

Public docs / package-level references:

WSL platform docs

WSL networking and behavior vary depending on configuration, which is a strong argument for an explicit target/transport layer rather than assumptions baked into the renderer:

Other relevant open-source references

code-server is useful as a reference for remote server concerns such as auth, transport, and reverse-proxy assumptions:

devcontainers/cli is useful as a reference for separating target bootstrap, environment resolution, and runtime lifecycle:

WezTerm is a useful reference for modeling WSL as a first-class domain/target rather than a subprocess trick:

Suggested implementation order

  1. Introduce BackendTarget
  2. Introduce a desktop BackendController
  3. Wrap current behavior as LocalBackendTarget
  4. Add WslBackendTarget
  5. Expose target metadata/capabilities through the desktop bridge
  6. Make renderer behavior capability-driven
  7. Add WSL-aware workspace selection and editor-open flows
  8. Add Windows + WSL integration tests

Expected outcome

This would give T3 Code:

  • a clean way to support WSL on Windows
  • a better separation between UI, transport, and backend runtime
  • a path toward future remote backends without redoing the architecture later

I’m opening this as an architecture proposal rather than a PR because the main value here is agreeing on the model before implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions