The desktop app registers the custom URL scheme codeg:// so another program
can bring Codeg forward and open a specific conversation.
This is the OS handler for the same codeg://session/<id> form already used
as an in-app markdown mention. Mention badges (codeg://agent/…,
codeg://commit/…, codeg://embedded/…) stay in-process and are not
OS navigation.
| URL | Effect |
|---|---|
codeg://session/214 |
Open conversation 214 (Codeg's numeric id) |
codeg://session/<external-id> |
Open by the agent's own session id (Grok UUID, Codex thread id, …) |
codeg://workspace?conversationId=214 |
Same lookup. folderId and agent are optional; when omitted they are read from the row |
codeg://workspace?folderId=3&conversationId=214&agent=grok |
Same, but rejected if folder or agent do not match the row |
codeg://open / codeg:// |
Show the workspace, no tab change |
A missing or deleted conversation is a no-op besides showing the workspace.
# macOS / Linux
open "codeg://session/214"
xdg-open "codeg://session/214"
# Windows
start codeg://session/214From a local web app (the custom scheme cannot be fetch'd; assign it):
window.location.href = "codeg://session/214"A resolved link cannot simply be emitted to the workspace: Tauri delivers an
event only to webviews that have already registered a JS listener, and
queues nothing for the rest. During boot that is every window. So the backend
parks the resolved target in a single slot and sends a payload-less
workspace://deep-link-pending nudge; the frontend takes the slot (an atomic
take, so exactly one caller can ever get a given target) both on the nudge and
once on mount, right after subscribing.
- Already running: the link reaches the live process (macOS Apple Event, or Windows/Linux argv through the single-instance plugin). The nudge arrives at a listening workspace, which drains the slot and opens the tab without reloading.
- Cold start: the nudge is dropped — nobody is listening yet — and the mount drain picks the target up instead.
- Windows / Linux cold start additionally has the URL available in argv
before the main window is even created (the deep-link plugin parses it during
its own setup), so the window is pointed straight at
/workspace?folderId=…&conversationId=…&agent=…andDeepLinkBootstrapopens the tab once folders, tabs and the conversation list have loaded. The two never both fire: whichever delivery reached the plugin before theon_open_urllistener existed is the one that wins.
The desktop installer registers the scheme — CFBundleURLTypes on macOS,
protocol handler on Windows, x-scheme-handler/codeg on Linux — but the Linux
half needs two extra pieces, because Tauri's bundler renders the .desktop
Exec line with no field code (tauri#15928, tauri#16014). Without one, the
freedesktop spec says the launcher passes no URL, so the app is advertised as
the scheme owner and then started empty.
src-tauri/linux/main.desktopis a copy of the bundler's template withExec={{exec}} %u, wired in throughbundle.linux.deb.desktopTemplateandbundle.linux.rpm.desktopTemplate(AppImage reuses the deb entry). Keep it in sync with the bundler'smain.desktopwhen Tauri is upgraded.- Windows and Linux release builds also call the plugin's
register_all()at startup. On Linux that writes aNoDisplay=truehandler entry that passes%u— a second chance for an AppImage that was never registered, though some portals skipNoDisplayentries, which is why the packaged entry above still has to be right. On Windows it adds theHKCUclass key a portable/zip copy never gets from the installer. Debug builds are skipped so a dev run cannot take the scheme away from an installed Codeg.
Not available in codeg-server / browser-only mode — use the
/workspace?folderId=&conversationId=&agent= query string there.