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.
Summary
The desktop app registers the
t3code://URL scheme, but the only handler attached toapp.on('open-url')is Clerk's OAuth callback listener. It returns early for anythingthat is not the OAuth redirect, so no other deep link does anything.
A thread deep link on desktop would therefore be:
appis the host the renderer is already served from, so everything after it can mirrorthe path
buildAgentAwarenessDeepLinkalready produces. That form is used throughoutthis 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):RelayAgentActivityStatecarries that value in itsdeepLinkfield, so mobile clientscan open the exact thread from a push notification.
The renderer has a thread route (
threads/:threadId). Whether it also accepts theenvironment segment, or resolves the environment some other way, I could not tell from
the bundle alone.
The scheme is registered in
Info.plist:What happens instead
The only
open-urllistener is the Clerk OAuth one:second-instancehas the same shape. Any URL that is not the OAuth callback issilently 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-urlandsecond-instancelistener that recognises thread URLs,focuses the main window, and hands the path to the renderer router. The path is the same
string
buildAgentAwarenessDeepLinkalready produces.Suggested acceptance:
open "t3code://app/threads/<environmentId>/<threadId>"focuses the window andselects that thread.
erroring.
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
app.asarand from theopencall above.I have not seen the source repository.