Add warp://tab_config/<name> deeplink#9379
Conversation
Mirrors the existing warp://launch flow: resolves <name> against the user's tab configs (case-insensitive on the config name, falling back to the file stem) and dispatches to Workspace::open_tab_config, which already handles the params modal / worktree branch generation. By default the tab config opens as a new tab in the active window; pass ?new_window=true (or have no Warp window open) to open in a brand-new window instead. Gated on the existing FeatureFlag::TabConfigs.
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @haha1903 on file. In order for us to review and merge your code, each contributor must visit https://cla.warp.dev to read and agree to our CLA. Once you have done so, please comment |
|
@cla-bot check |
|
The cla-bot has been summoned, and re-checked this pull request! |
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I requested changes on this pull request and posted feedback. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds a warp://tabconfig/<name> handler that resolves local tab configs by display name or source file stem and opens them in an existing or new workspace.
Concerns
- The URI window-behavior hint can create a fallback window before the tabconfig handler sees
?new_window=true, which can violate the documented default/new-window behavior on platforms that cannot activate the existing window. - Security pass: no additional security findings beyond the window-selection behavior noted inline.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
Use WindowBehaviorHint::Nothing so handle_tab_config_uri is the sole owner of the new-vs-reuse decision.
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
|
Found matching issue #9060 ( |
There was a problem hiding this comment.
Overview
This PR adds a warp://tabconfig/<name> URI host, resolves saved tab configs by display name or file stem, and opens the selected config in an existing or new window.
Concerns
- The new handler imports and calls
root_view::workspace_for_window, but that helper is not present in the repository and is not added by this diff, so the PR will not compile. - This is user-visible behavior and the PR description does not include screenshots or a video demonstrating the deeplink flow end to end; per repository review guidance, please upload visual evidence for faster review.
Verdict
Found: 1 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
|
@seemeroland when you have a minute — could I get a look from you on this one? It mirrors the existing |
- Rename the URL host from tabconfig to tab_config to match issue #9060 - Match tab configs by file stem only; drop the TOML `name` field fallback since names are not unique across files - Drop the wasm-only #[expect(dead_code)] on tab_configs_dir since the URI handler now calls it on all targets
moirahuang
left a comment
There was a problem hiding this comment.
thanks for making the changes! just a few small comments now
- Import `TabConfig` at the top of `uri/mod.rs` instead of inline - Have `find_matching_tab_config` consume `Vec<TabConfig>` and return an owned `TabConfig`, dropping the clone at the callsite and the `'a` lifetime - Add a unit test covering stem matching with/without extension, case-insensitivity, misses, and configs missing `source_path`
# Conflicts: # app/src/uri/mod.rs
|
@haha1903 I just checked out the latest code locally and it's not compiling. Mind making sure it compiles + testing locally please? |
The previous merge commit resolved the import hunk but left the three call sites referencing the removed `workspace_for_window` helper, breaking the build. Swap them for the `WorkspaceRegistry::as_ref(ctx) .get(window_id, ctx)` pattern used elsewhere.
|
@moirahuang apologies for the broken merge — that was my mistake. Root cause: during the master merge I staged the conflict resolution for the Just pushed |
# Conflicts: # app/src/uri/mod.rs
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds a warp://tab_config/<name> URI host, resolves saved tab configs by source file stem, and opens them through the existing tab-config workspace flow.
Concerns
- Dotted tab-config file stems cannot be opened without the
.tomlsuffix because the requested stem is always passed throughremove_extension, which strips valid stem content after the final dot.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| /// Case-insensitive match against each tab config's file stem. Tab config | ||
| /// `name` fields are not unique across files, so we key off the filename. | ||
| fn find_matching_tab_config(target: &str, configs: Vec<TabConfig>) -> Option<TabConfig> { | ||
| let stem = remove_extension(target).unwrap_or(target).to_lowercase(); |
There was a problem hiding this comment.
foo.bar.toml cannot be opened with warp://tab_config/foo.bar even though foo.bar is its file stem. Only strip the known .toml suffix, or try both the raw target and a .toml-stripped target.
There was a problem hiding this comment.
Fixed in 2a2a1fbf — switched to the same two-step pattern find_matching_config uses (try the target as-is first, then with the extension stripped). foo.bar.toml now resolves via both warp://tab_config/foo.bar and warp://tab_config/foo.bar.toml; added a test case covering both.
`remove_extension` strips everything after the last `.`, so a config file named `foo.bar.toml` (stem `foo.bar`) could not be reached via `warp://tab_config/foo.bar` — the target got rewritten to `foo` before the lookup. Mirror `find_matching_config`'s pattern: try the target as-is first, then with the extension stripped. Covers both `foo.bar` and `foo.bar.toml` writing styles, and adds a test case.
|
/oz-review |
|
I'm re-reviewing this pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR adds a warp://tab_config/<name> custom URI host, resolves saved tab configs by filename stem, opens them in the active workspace or a new window, and exposes Workspace::open_tab_config for reuse by the URI handler.
Concerns
- Manual testing is required for changes that can be manually tested. Please include screenshots or a screen recording that show the deeplink working end to end for the active-window and
?new_window=trueflows, or justify why visual evidence is not possible.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
|
@haha1903 I just tried to test this locally and it wasn't opening a tab config. Mind recording and attaching you testing this locally please? |
CleanShot.2026-05-14.at.23.52.13-converted.2.mp4 |
|
Thanks @moirahuang for the review and merge! 🙏 |
Pins file-type defaults, Hammerspoon Wispr auto-submit, and the checked-in Brewfile to install and target Warp Preview alongside Stable. Preview ships weekly so newly-merged URI handlers (warpdotdev/warp#9379, the warp://tab_config/ scheme) light up in the daily driver within days of merge instead of weeks. Stable stays installed as the named fallback. URL schemes are channel-specific: warp:// owns Stable, warppreview:// owns Preview, so coily tooling that fires URIs picks the channel at call site. Preview auto-symlinks launch_configurations, tab_configs, and themes into ~/.warp/, so checked-in configs cover both channels for free. settings.toml is the one file that does not auto-share; the install playbook in warp/README.md symlinks Preview's settings.toml to the same source as Stable's so they stay in sync. set-warp-default-editor.sh now defaults to dev.warp.Warp-Preview and gates on WarpPreview.app, with WARP_DEFAULT_EDITOR_BUNDLE_ID and WARP_DEFAULT_EDITOR_APP_PATH env vars for per-host override (e.g. pinning kai-server or Windows to Stable). The Hammerspoon Wispr auto-submit accepts either Warp channel as frontmost so the flow works in both, not just whichever channel is the daily driver this month. closes #107
closes #108 Description string, config-location section, and SQLite/binary debug paths now cover both ~/.warp/ (Stable) and ~/.warp-preview/ (Preview, daily driver). Add a Channels table summarizing bundle ids, URL schemes, brew formulae, and Spotlight strings. Add a Launch configurations and tab configs section that names the warp:// and warppreview:// URI shapes plus the warpdotdev/warp#9379 provenance. Rename Host portability to Host and channel portability and call out the symlink-chain dependency hidden inside default_tab_config_path. Resolve the Cmd+I open question. Point See also at warp/README.md for the install playbook so the duti / lsregister / WARP_DEFAULT_EDITOR_BUNDLE_ID story is one click from the skill.
…override closes #273 Preview is the Mac daily driver per coilyco-flight-deck/agentic-os#107 and was the motivating consumer for the warpdotdev/warp#9379 tab_config URI handler. Stable is the named fallback when Preview wedges. The URL scheme picks the channel: warppreview:// always lands in Preview, warp:// always lands in Stable, with no LaunchServices toggle that flips this. Add a `--channel preview|stable` flag (default `preview`), introduce a `channelScheme` + `launchURL` pair that maps channel to scheme, and thread the resolved URL through the openWarpLaunch seam, dry-run output, and soft-fail fallback. Reject unknown channels at flag-parse time so the operator can't accidentally open Stable thinking they opened Preview. The launch-config name `claude-dispatch-interactive` resolves identically under either scheme because Preview auto-symlinks launch_configurations into ~/.warp/, so no agentic-os change is needed. Tests cover the channel -> scheme map, the unknown-channel rejection, and pin the new default-channel constant alongside the existing seam strings. Audit-log: coily://1779270571/AGPEJSSU - coily ops aws sts get-caller-identity Audit-log: coily://1779270571/AGPEJSSW - coily ops aws ssm get-parameter Audit-log: coily://1779271344/AGPEJVRB - coily ops gh issue view 270 Audit-log: coily://1779271371/AGPEJVUJ - coily ops gh run list Audit-log: coily://1779271378/AGPEJVVG - coily ops gh issue list Audit-log: coily://1779271395/AGPEJVXG - coily ops gh issue create Audit-log: coily://1779271486/AGPEJWCL - coily exec test
closes #115 warpdotdev/warp#9379 merged 2026-05-15. The previous 2026-05-13 Preview threshold was speculation from before the PR landed. Collapse to a single 2026-05-15 across both channels.
Warp's TabConfig schema (warpdotdev/warp#9379) defines commands as Vec<String>, not Vec<{exec: String}> like launch_config YAML. With deny_unknown_fields, the inline-table form failed toml deserialization silently — parse errors only surface via a UI toast that's suppressed on startup loads, so the failure was invisible in ~/Library/Logs/warp*.log and the URI handler logged "couldn't find a tab config matching X" even though the file existed on disk. closes #118 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes warpdotdev#9060 Related to warpdotdev#9083 ## Description Add a `warp://tab_config/<name>` URL scheme handler so users can launch a saved tab config straight from a deeplink (alongside the existing `warp://launch/<name>`). By default the tab config opens as a **new tab in the active window**. Pass `?new_window=true` (or invoke when no Warp window is open) to open in a brand-new window instead. `<name>` is matched case-insensitively against the tab config's file stem, so both `warp://tab_config/my_tab` and `warp://tab_config/my_tab.toml` resolve to `my_tab.toml`. We key off the filename (not the `name` field inside the file) because multiple tab configs can share the same `name`. The handler dispatches to the existing `Workspace::open_tab_config`, so the params modal and worktree branch generation flows are reused unchanged. Gated on the existing `FeatureFlag::TabConfigs`. ## Why Lets users (and external tools / scripts / browser bookmarks) jump straight into a configured pane layout without going through the `+` menu. Mirrors the long-standing `warp://launch/...` deeplink for launch configs. ## How - New `UriHost::TabConfig` variant in `app/src/uri/mod.rs`, parsed from `tab_config` host string and listed in `validate_custom_uri`'s allowlist. - New handler `handle_tab_config_uri` that resolves the config and either reuses the active window's workspace or opens a new window (via `open_new_window_get_handles`), then calls `workspace.open_tab_config(...)`. - `Workspace::open_tab_config` promoted from private to `pub(crate)` so it can be invoked from the URI handler. - Added a wasm-side stub for `load_tab_configs` so the cross-platform `pub(crate) use imp::load_tab_configs;` in `user_config/mod.rs` matches the pattern already used by `load_launch_configs` (no `cfg` gate needed). ## Testing Manual: - `open "warposs://tab_config/<name>"` opens the config as a new tab in the focused window. - `open "warposs://tab_config/<name>?new_window=true"` opens it in a new window. - Tab config with `params` triggers the existing params modal. - Worktree-style tab configs still get an autogenerated branch name. - Unknown `<name>` logs a warning and is a no-op. `cargo fmt` and `cargo clippy --workspace --all-targets --all-features --tests -- -D warnings` both pass locally. Full `./script/presubmit` will run on CI. ## Server API dependencies No server changes. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode ## Changelog Entries for Stable CHANGELOG-IMPROVEMENT: Added a `warp://tab_config/<name>` deeplink that opens a saved tab config in the active window (or a new one with `?new_window=true`).
Closes warpdotdev#9060 Related to warpdotdev#9083 ## Description Add a `warp://tab_config/<name>` URL scheme handler so users can launch a saved tab config straight from a deeplink (alongside the existing `warp://launch/<name>`). By default the tab config opens as a **new tab in the active window**. Pass `?new_window=true` (or invoke when no Warp window is open) to open in a brand-new window instead. `<name>` is matched case-insensitively against the tab config's file stem, so both `warp://tab_config/my_tab` and `warp://tab_config/my_tab.toml` resolve to `my_tab.toml`. We key off the filename (not the `name` field inside the file) because multiple tab configs can share the same `name`. The handler dispatches to the existing `Workspace::open_tab_config`, so the params modal and worktree branch generation flows are reused unchanged. Gated on the existing `FeatureFlag::TabConfigs`. ## Why Lets users (and external tools / scripts / browser bookmarks) jump straight into a configured pane layout without going through the `+` menu. Mirrors the long-standing `warp://launch/...` deeplink for launch configs. ## How - New `UriHost::TabConfig` variant in `app/src/uri/mod.rs`, parsed from `tab_config` host string and listed in `validate_custom_uri`'s allowlist. - New handler `handle_tab_config_uri` that resolves the config and either reuses the active window's workspace or opens a new window (via `open_new_window_get_handles`), then calls `workspace.open_tab_config(...)`. - `Workspace::open_tab_config` promoted from private to `pub(crate)` so it can be invoked from the URI handler. - Added a wasm-side stub for `load_tab_configs` so the cross-platform `pub(crate) use imp::load_tab_configs;` in `user_config/mod.rs` matches the pattern already used by `load_launch_configs` (no `cfg` gate needed). ## Testing Manual: - `open "warposs://tab_config/<name>"` opens the config as a new tab in the focused window. - `open "warposs://tab_config/<name>?new_window=true"` opens it in a new window. - Tab config with `params` triggers the existing params modal. - Worktree-style tab configs still get an autogenerated branch name. - Unknown `<name>` logs a warning and is a no-op. `cargo fmt` and `cargo clippy --workspace --all-targets --all-features --tests -- -D warnings` both pass locally. Full `./script/presubmit` will run on CI. ## Server API dependencies No server changes. ## Agent Mode - [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode ## Changelog Entries for Stable CHANGELOG-IMPROVEMENT: Added a `warp://tab_config/<name>` deeplink that opens a saved tab config in the active window (or a new one with `?new_window=true`).
Closes #9060
Related to #9083
Description
Add a
warp://tab_config/<name>URL scheme handler so users can launch a saved tab config straight from a deeplink (alongside the existingwarp://launch/<name>).By default the tab config opens as a new tab in the active window. Pass
?new_window=true(or invoke when no Warp window is open) to open in a brand-new window instead.<name>is matched case-insensitively against the tab config's file stem, so bothwarp://tab_config/my_tabandwarp://tab_config/my_tab.tomlresolve tomy_tab.toml. We key off the filename (not thenamefield inside the file) because multiple tab configs can share the samename.The handler dispatches to the existing
Workspace::open_tab_config, so the params modal and worktree branch generation flows are reused unchanged.Gated on the existing
FeatureFlag::TabConfigs.Why
Lets users (and external tools / scripts / browser bookmarks) jump straight into a configured pane layout without going through the
+menu. Mirrors the long-standingwarp://launch/...deeplink for launch configs.How
UriHost::TabConfigvariant inapp/src/uri/mod.rs, parsed fromtab_confighost string and listed invalidate_custom_uri's allowlist.handle_tab_config_urithat resolves the config and either reuses the active window's workspace or opens a new window (viaopen_new_window_get_handles), then callsworkspace.open_tab_config(...).Workspace::open_tab_configpromoted from private topub(crate)so it can be invoked from the URI handler.load_tab_configsso the cross-platformpub(crate) use imp::load_tab_configs;inuser_config/mod.rsmatches the pattern already used byload_launch_configs(nocfggate needed).Testing
Manual:
open "warposs://tab_config/<name>"opens the config as a new tab in the focused window.open "warposs://tab_config/<name>?new_window=true"opens it in a new window.paramstriggers the existing params modal.<name>logs a warning and is a no-op.cargo fmtandcargo clippy --workspace --all-targets --all-features --tests -- -D warningsboth pass locally. Full./script/presubmitwill run on CI.Server API dependencies
No server changes.
Agent Mode
Changelog Entries for Stable
CHANGELOG-IMPROVEMENT: Added a
warp://tab_config/<name>deeplink that opens a saved tab config in the active window (or a new one with?new_window=true).