The workflow
Linear Desktop can hand an issue to a coding tool two ways: a custom link with query params, or a local script (~/.linear/coding-tools.json, docs). I wanted the Linear "Work on issue" button to drop me into a bb thread on the right repo with the issue context already there.
The same shape shows up outside Linear: Raycast, Alfred, a browser extension, a Slack link, a bookmarklet, or any tool that can emit a URL but cannot run a shell script.
What happens today
The local-script path works. bb thread spawn creates the thread, bb thread open <id> pushes navigation to every connected client ("delivered": 3 in my case), and open -a bb raises the window, since the app takes a single-instance lock and focuses its first window on re-activation. A working script is at the end of this issue.
The URL path does not work, because bb registers no URL scheme:
/Applications/bb.app/Contents/Info.plist has no CFBundleURLTypes key.
- The Electron main process (
dist/main.js in app.asar) never calls app.setAsDefaultProtocolClient and has no open-url handler. The only deep-link string in the bundle is an unrelated comment in the thread-search schema.
So bb://... is inert, and any integration that can only produce a URL cannot reach bb. The CLI workaround also only works on the machine bb runs on, and only for a caller that can execute a script.
What you would expect
A registered bb scheme handled by the desktop app, focusing the window and routing to the existing SPA routes:
bb://thread/thr_abc123 -> focus window, open that thread
bb://project/proj_abc123 -> focus window, open that project
Behavior when the app is not running should match open -a bb: launch, wait for the server, then route. Behavior when the thread id is unknown should be a visible error rather than a blank pane.
Two details worth deciding explicitly:
- Whether to also register
bb-nightly:// or a scheme suffix for dev/nightly builds, so a nightly install does not steal links from a stable one.
- Whether an inbound URL should be allowed to name a machine, or whether it always routes on the local instance.
I have not filed prefill-without-send here; that is a separate request (see the linked issue), since a URL handler is useful on its own.
Context and alternatives
Verified on bb 0.39.0, macOS 15.5 (Darwin 25.5.0).
The working script I use today, registered as Linear's openIssue.path:
# resolve the bb project whose source path covers Linear's work dir
PROJECT_ID="$(bb project list --json | jq -r --arg dir "$LINEAR_WORK_DIR" '
[ .[] | . as $p | .sources[] | select(.type == "local_path") | .path as $src
| select($dir == $src or ($dir | startswith($src + "/")))
| { id: $p.id, depth: ($src | length) } ]
| sort_by(-.depth) | .[0].id // empty')"
THREAD_ID="$(bb thread spawn --project "$PROJECT_ID" --environment "$LINEAR_WORK_DIR" \
--title "$LINEAR_ISSUE_IDENTIFIER" --prompt "$LINEAR_PROMPT" --json | jq -r .id)"
bb thread open "$THREAD_ID"
open -a /Applications/bb.app
Two rough edges I hit building that, which I can file separately if useful:
- The CLI is a
#!/usr/bin/env node script, so it fails with env: node: No such file or directory when invoked from a Finder-launched app whose PATH has no nvm or homebrew node. The workaround is to run the same script under Electron's bundled node, which always ships with the app: ELECTRON_RUN_AS_NODE=1 /Applications/bb.app/Contents/MacOS/bb <cli-path> …. A launcher shim that does not need an external node would remove the need for that trick.
bb thread open [id] [path] reads its single positional as a path when BB_THREAD_ID is set, so bb thread open thr_abc opened a file literally named thr_abc in the current thread's panel instead of switching threads. Unsetting BB_THREAD_ID fixes it, but the silent reinterpretation is easy to miss.
Happy to prototype the handler in a fork if you want it, following CONTRIBUTING's issue-first rule.
Checks
AGENT GENERATED: by claude-opus-5
The workflow
Linear Desktop can hand an issue to a coding tool two ways: a custom link with query params, or a local script (
~/.linear/coding-tools.json, docs). I wanted the Linear "Work on issue" button to drop me into a bb thread on the right repo with the issue context already there.The same shape shows up outside Linear: Raycast, Alfred, a browser extension, a Slack link, a bookmarklet, or any tool that can emit a URL but cannot run a shell script.
What happens today
The local-script path works.
bb thread spawncreates the thread,bb thread open <id>pushes navigation to every connected client ("delivered": 3in my case), andopen -a bbraises the window, since the app takes a single-instance lock and focuses its first window on re-activation. A working script is at the end of this issue.The URL path does not work, because bb registers no URL scheme:
/Applications/bb.app/Contents/Info.plisthas noCFBundleURLTypeskey.dist/main.jsinapp.asar) never callsapp.setAsDefaultProtocolClientand has noopen-urlhandler. The onlydeep-linkstring in the bundle is an unrelated comment in the thread-search schema.So
bb://...is inert, and any integration that can only produce a URL cannot reach bb. The CLI workaround also only works on the machine bb runs on, and only for a caller that can execute a script.What you would expect
A registered
bbscheme handled by the desktop app, focusing the window and routing to the existing SPA routes:Behavior when the app is not running should match
open -a bb: launch, wait for the server, then route. Behavior when the thread id is unknown should be a visible error rather than a blank pane.Two details worth deciding explicitly:
bb-nightly://or a scheme suffix for dev/nightly builds, so a nightly install does not steal links from a stable one.I have not filed prefill-without-send here; that is a separate request (see the linked issue), since a URL handler is useful on its own.
Context and alternatives
Verified on bb 0.39.0, macOS 15.5 (Darwin 25.5.0).
The working script I use today, registered as Linear's
openIssue.path:Two rough edges I hit building that, which I can file separately if useful:
#!/usr/bin/env nodescript, so it fails withenv: node: No such file or directorywhen invoked from a Finder-launched app whose PATH has no nvm or homebrew node. The workaround is to run the same script under Electron's bundled node, which always ships with the app:ELECTRON_RUN_AS_NODE=1 /Applications/bb.app/Contents/MacOS/bb <cli-path> …. A launcher shim that does not need an external node would remove the need for that trick.bb thread open [id] [path]reads its single positional as a path whenBB_THREAD_IDis set, sobb thread open thr_abcopened a file literally namedthr_abcin the current thread's panel instead of switching threads. UnsettingBB_THREAD_IDfixes it, but the silent reinterpretation is easy to miss.Happy to prototype the handler in a fork if you want it, following CONTRIBUTING's issue-first rule.
Checks