Skip to content

Route t3code:// deep links into the existing thread route #11865

Description

@Birzool

Summary

The desktop app registers the t3code:// URL scheme, but the only handler attached to
app.on('open-url') is Clerk's OAuth callback listener. It returns early for anything
that is not the OAuth redirect, so no other deep link does anything.

A thread deep link on desktop would therefore be:

t3code://app/threads/<environmentId>/<threadId>

app is the host the renderer is already served from, so everything after it can mirror
the path buildAgentAwarenessDeepLink already produces. That form is used throughout
this issue.

Most of what this needs already exists in the app: the scheme is registered, the path
builder is shipped, and the renderer has a thread route. The protocol handler is the
part that does not exist.

What exists today

The app already builds thread deep links, and ships one with every agent activity
update sent to the relay (packages/shared/src/agentAwareness.ts):

function buildAgentAwarenessDeepLink(input) {
  return `/threads/${encodeURIComponent(input.environmentId)}/${encodeURIComponent(input.threadId)}`;
}

RelayAgentActivityState carries that value in its deepLink field, so mobile clients
can open the exact thread from a push notification.

The renderer has a thread route (threads/:threadId). Whether it also accepts the
environment segment, or resolves the environment some other way, I could not tell from
the bundle alone.

The scheme is registered in Info.plist:

CFBundleURLName    = "T3 Code"
CFBundleURLSchemes = ["t3code", "t3code-dev"]

What happens instead

The only open-url listener is the Clerk OAuth one:

const openUrlListener = (event: Electron.Event, url: string): void => {
  if (!isMatchingCallbackUrl(url, redirectUrl)) {
    return;
  }
  event.preventDefault();
  handleCallbackUrl(url);
};

second-instance has the same shape. Any URL that is not the OAuth callback is
silently dropped.

Reproduce

With the desktop app running:

open "t3code://app/threads/<environment-id>/<thread-id>"

Exit code is 0. The app does not react. No window is focused, no thread is selected,
and nothing is logged.

Same result with a bare t3code://threads/<thread-id>.

Proposal

Add a second open-url and second-instance listener that recognises thread URLs,
focuses the main window, and hands the path to the renderer router. The path is the same
string buildAgentAwarenessDeepLink already produces.

Suggested acceptance:

  • open "t3code://app/threads/<environmentId>/<threadId>" focuses the window and
    selects that thread.
  • An unknown or malformed path focuses the window without navigating, rather than
    erroring.
  • A thread id that does not exist in this environment leaves the current thread
    selected and surfaces the usual "not found" state rather than a blank view.

Why it is worth doing

It makes a thread addressable from outside the app: a note, a script, a terminal, a
chat message, a bookmark, a CI comment. Today there is no way to hand someone "open
this thread" on desktop.

It is also the missing half of desktop notifications. A notification that cannot take
you to the thread it is about is a notification you have to act on twice. See #11866.

Environment

  • T3 Code (Alpha) 0.0.40, macOS 26 (Darwin 25.6), Apple Silicon.
  • Findings come from reading the shipped app.asar and from the open call above.
    I have not seen the source repository.

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

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions