Skip to content

[Feature]: Recognize same-Mac background services for Open in Zed (patch proposal) #24072

Closed

Description

@wcastand

Summary

On macOS, T3 Code 0.1.2's desktop app treats a paired background service running on the same Mac as a remote editor target. Clicking Open in Zed sends a zed://ssh/... URL, so Zed tries to connect to a host over SSH instead of opening the local worktree.

This is a follow-up proposal to #18473, which was closed as unsupported/a feature request. I am explicitly referencing that duplicate history rather than claiming this is a newly discovered regression. This report adds a reproduction on 0.1.2 and a concrete routing patch proposal. If Discussions is still preferred, please feel free to convert it.

Environment

  • T3 Code desktop (Beta) 0.1.2, background server 0.1.2.
  • macOS 27.0.1, Apple Silicon; Zed 1.25.2.
  • Background service and desktop app run under the same OS user on the same Mac.
  • Desktop Settings → Connections → Local environment is off, so the existing background service keeps ownership of the T3 home and can continue after the desktop app closes.
  • The running service listens on 127.0.0.1:3773; the desktop connects to it as a paired/saved environment.

Steps to reproduce

  1. Run the T3 background service on a Mac.
  2. Leave the desktop app's managed Local environment off and connect the desktop to that existing service.
  3. Open a thread/worktree hosted by that service.
  4. Click Open in Zed.

Actual: Zed opens a remote-host connection flow and times out. The client resolver chooses remote-links, whose Zed URL builder produces zed://ssh/<host>/<path>.

Expected: Open the worktree directly in Zed on the same Mac, without requiring SSH to the Mac itself, starting a second backend, or changing background-service ownership.

Source-level diagnosis

Checked against main at 4812dcad02a86874533540e6a0c4b7f5eaea297a as well as the installed 0.1.2 client:

  • resolveRemoteOpenState recognizes a desktop primary target and isDesktopLocalConnectionTarget(target) as local-exec. A normal saved service connection falls through to SSH/advertised remote targets.
  • desktopLocal identifies the desktop-managed bearer registrations using their local: connection IDs. Ordinary paired service connections do not have those IDs.
  • With the managed Local environment disabled, its bootstrap registrations are absent even though the same-host background service is running.

The distinction should be whether the selected environment is the local service, not whether the desktop app started that service.

Proposed patch

Add a read-only native desktop bridge operation that discovers the existing local service's environment ID. It should work while Local environment is disabled, validate the running local service through native discovery/live loopback identity, and neither start nor stop a backend. Return null when local identity cannot be verified. Do not infer locality from a display name, path existence, or arbitrary remote-advertised hostname.

Pass that verified ID into resolveRemoteOpenState and preserve existing behavior for every other environment. Illustrative resolver diff:

 export function resolveRemoteOpenState(input: {
   readonly target: ConnectionTarget | null;
+  readonly localServiceEnvironmentId?: EnvironmentId | null;
   readonly sshTarget: { readonly alias: string; readonly username: string | null } | null;
   readonly remoteOpenTargets: ReadonlyArray<RemoteOpenTarget> | undefined;
   readonly isDesktopRenderer: boolean;
 }): RemoteOpenState {
   const { target } = input;
   if (target === null) {
     return LOCAL_EXEC;
   }
+  if (
+    input.isDesktopRenderer &&
+    input.localServiceEnvironmentId != null &&
+    target.environmentId === input.localServiceEnvironmentId
+  ) {
+    return LOCAL_EXEC;
+  }
   if (target._tag === "PrimaryConnectionTarget") {

In remoteOpenResolutionAtom, supply localServiceEnvironmentId from that native discovery result. If discovery is asynchronous, make its result reactive so a verified identity updates the resolution without requiring a reconnect. This needs the corresponding typed bridge/IPC implementation; the snippet above is a proposal, not a complete merge-ready patch.

This reuses the existing local-exec → shell.openInEditor path. The RPC goes to the selected environment, which in this case is the same-Mac service, so its existing launcher can invoke Zed with the worktree path. Remote clients connected to this Mac must still use remote links; the desktop-renderer check and native identity comparison are both required.

Verification and acceptance

Observed locally:

  • The installed resolver chooses remote-links for an ordinary paired service target, even in the desktop renderer.
  • Invoking zed <worktree-path> directly succeeds; Zed's log confirms that exact worktree was loaded.
  • A temporary resolver override for this Mac's verified environment ID changed the result to local-exec; different environment IDs and non-desktop clients retained remote-links. No installed app bundle was modified.

For an upstream implementation, verify:

  1. Same-Mac background service + Local environment off → direct local Zed launch.
  2. Another machine's service → existing SSH route.
  3. A remote browser/client connected to this Mac → existing remote behavior.
  4. Unverified/missing local identity → existing fallback.
  5. Desktop-managed primary/WSL targets → existing behavior.
  6. The service continues after desktop closure; discovery does not spawn another server or change service ownership.

The proposed native discovery/IPC integration has not been implemented or exercised end to end. Turning the managed Local environment back on is not an equivalent solution for this setup; it changes backend ownership and is related to the startup-conflict discussion in #20250.

Workaround

Open the worktree with zed <worktree-path> outside the button. No app bundle modification or SSH setup is needed for that workaround.

Activity

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

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