Skip to content

feat(desktop): restore new-session deep link and add open-session - #57246

Open
opencode-agent[bot] wants to merge 1 commit into
devfrom
restore-desktop-deep-links
Open

opencode-agent[bot] wants to merge 1 commit into
devfrom
restore-desktop-deep-links

Conversation

@opencode-agent

@opencode-agent opencode-agent Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Desktop still registers opencode:// and forwards links to the renderer, but the app stopped acting on them when the legacy layout was removed (#40947), and the leftover parser was deleted in #43789. Clicking a link focused the window and did nothing.

This restores new-session and adds open-session. open-project was intentionally not restored.

  • opencode://new-session?directory=<path>&prompt=<text> adds the directory to the local server's projects and opens a new draft tab there. prompt is optional and only prefills the composer; nothing is submitted.
  • opencode://open-session?id=<session id> opens (or focuses) the session's tab on the local server.

How it works:

  • The handling now lives in the desktop renderer (startup/deep-links.ts + DesktopDeepLinks in desktop-app.tsx) instead of a window event and global buffer that nothing listened to.
  • Links that arrive before the app is ready, including the one that launched it, are queued until the local server exists and the window's tabs have hydrated, so a new draft isn't overwritten by tab restore.
  • Links only ever target the built-in local server.
  • Windows and Linux pass the launching link in process.argv rather than second-instance; the main process now seeds its pending list from argv so cold-start links aren't dropped.

Not changed: the main process keeps every delivered link in its pending list until a renderer consumes it at startup, so a window opened later replays links that already opened elsewhere. That predates this PR; happy to tighten it here if you want.

Testing: bun test src/renderer/startup/deep-links.test.ts, bun run typecheck in packages/desktop. I couldn't run the Electron app on the build host (it hit thread limits), so this hasn't been clicked through end to end yet.

Requested by: @jlongster (James Long via Slack)


Added by the opencode bot (AI-generated).

Fixes #55106
Fixes #44167

Related: #53529, #47581, #35225

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't verify this end to end: it needs the Electron desktop app, which doesn't run here. The parser tests pass and packages/desktop typechecks; the rest comes from reading the code.

Public API: the SDK, HTTP API, plugin API and config are unchanged. The PR adds the opencode://new-session?directory=&prompt= and opencode://open-session?id= URL handlers back to Desktop. It removes the window.__OPENCODE__.deepLinks global and the opencode:deep-link window event, which nothing in the codebase read.

Main concern: links can open again later (see inline). Now that the renderer acts on links, the main process keeping every delivered link in pendingDeepLinks is a real user-facing problem: reloading the window or opening a new one creates the drafts again and reopens session tabs. I'd fix this in this PR instead of leaving it for later.

Fixes #55106
Fixes #44167
Related: #53529, #47581, #35225

const restoreWindows = windows.restore
const pendingDeepLinks: string[] = []
// Windows and Linux pass the link that launched the app as an argument; later ones arrive via second-instance.
const pendingDeepLinks = process.argv.filter((arg) => arg.startsWith("opencode://"))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the renderer acts on links, keeping them in this list is a problem. emitDeepLinks pushes every link here and sends it to a window, and the list is only emptied when a renderer starts up. So reloading the window or opening a new one replays every link received since launch: another draft tab, another projects.open, or a session tab you had closed opening again. One option: only queue a link when no window can take it yet (no target window, or win.webContents.isLoading()), or keep track of which window has already taken it, so each link opens once.


if (!conn || !tabs.ready()) return
const server = ServerConnection.key(conn)
bindDeepLinks((link) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queued links are run synchronously inside this createEffect, so the reads in addSessionTab/newDraft (for example store.find) make the effect depend on the tabs store. It then cleans up and re-binds on every tab change. Wrapping the handler in untrack, as runtime/extension/host-apis.tsx does around its newDraft call, avoids that. The open-session branch is the same as openNotificationSession(tabs, server, id) in shell/notifications/notification.tsx, which could be reused.

@CFF

CFF commented Oct 20, 2026

Copy link
Copy Markdown

Following up on #44160 and #55106: same gap on our side. Our workflow launches pre-written work blocks as new desktop sessions via opencode://new-session?directory=<path>&prompt=<text>. It stopped working when the legacy layout was removed: the link is received by the main process, then silently dropped. This PR is exactly what we need. Happy to test as soon as it ships in a desktop release.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: opencode://new-session in OpenCode 2's desktop app, as in OpenCode 1 Add a deep link to open a specific Desktop session

2 participants