Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
# APP-4087: Fix Warp skill and MCP home config paths after watcher unification Product Spec
## Summary
The immediate regression is that `oz agent run --skill <name>` no longer finds Warp skills stored in Warps home-relative config directory on Linux and Windows. APP-3945 intentionally centralized Warp-owned filesystem watching to avoid recursively watching `.warp*/worktrees`, but it also tied Warp skill lookup to platform app data paths. That works on macOS because Warps app data path is home-relative and channel-aware, but it breaks non-macOS users because app data follows XDG/AppData conventions instead of Warps `.warp*` home config directory convention.
Fixing the skill regression led us to audit other Warp-owned home config paths affected by the same watcher unification. MCP has the same shape: Warps file-based MCP config should live next to other home-relative Warp config for the current app environment. APP-4087 should restore those environment-aware home paths without undoing APP-3945s worktree-watch safety.
## Problem
Before APP-3945, Warp skill discovery could find skills in Warps home config directory, such as `~/.warp/skills`. After APP-3945, `SkillProvider::Warp` stopped going through generic home-provider watching and instead relied on the centralized Warp watcher and app data paths. That prevented broad recursive watches under `~/.warp`, which was intended, but it also meant that home-relative Warp skill directories stopped being considered when app data was somewhere else.
Linux and Windows expose the bug because their app data directories differ from Warps home-relative `.warp*` config directories. A Stable user can therefore have a valid skill at `~/.warp/skills/foo/SKILL.md`, run `oz agent run --skill foo`, and see the skill fail to resolve because the resolver and watcher are looking in the platform app data directory.
macOS hides most of this because Stable and Preview commonly resolve app data to `~/.warp`, while Dev and Local resolve to environment-specific home directories such as `~/.warp-dev` and `~/.warp-local`. The desired behavior is not simply “always use `~/.warp`”; it is “use the home-relative Warp config directory for the current Warp app environment.”
While investigating Skills, we checked MCP because its global config has the same shape. Warp MCP config should use the same environment-aware home config directory as Skills, e.g. `~/.warp/.mcp.json`, `~/.warp-dev/.mcp.json`, or `~/.warp-local/.mcp.json` depending on channel/profile.
## Goals
- Preserve the APP-3945 invariant that Warp does not recursively watch `.warp*/worktrees`.
- Restore `oz --skill <name>` resolution for Warp home skills on Linux, Windows, and macOS.
- Preserve environment isolation for Dev, Local, Integration, OpenWarp, and development profiles.
- Use a single purpose-specific home config path helper for Warp Skills and MCP.
- Keep `data_dir()` and `config_local_dir()` for their existing app-managed configuration responsibilities.
- Keep Warp-specific filesystem watching centralized instead of reintroducing ad hoc recursive watchers in `SkillWatcher` or `FileMCPWatcher`.
## Non-goals
- Changing the public skill file format or MCP config schema.
- Changing project-level skill or MCP discovery.
- Migrating existing files between platform app data directories and home-relative `.warp*` directories.
- Treating non-macOS XDG/AppData `data_dir()/skills` or `data_dir()/.mcp.json` as Warp Skills or MCP sources of truth.
- Changing non-Warp provider paths such as `~/.agents/skills`, `~/.claude/skills`, `~/.codex/config.toml`, or project provider paths.
- Introducing a generic filtering API in `repo_metadata::DirectoryWatcher`.
## Figma / design references
Figma: none provided.
## User Experience
### Warp home skills
- A Stable user can store a skill at `~/.warp/skills/<skill-name>/SKILL.md`.
- Dev, Local, Integration, OpenWarp, and profiled builds use their own home-relative Warp config directories, such as `~/.warp-dev/skills`, `~/.warp-local/skills`, or `~/.warp-local-<profile>/skills`.
- Running `oz agent run --skill <skill-name> ...` resolves the skill from the current app environments Warp home skills directory even when platform app data is elsewhere.
- Warp home skill resolution continues to take precedence over project skill resolution for unqualified skill names.
- The resolver must not require the asynchronous `SkillManager` cache or filesystem watcher to be warmed before `oz --skill` works.
### Warp home MCP config
- A user can configure file-based MCP servers for the current Warp app environment at `<warp-home-config-dir>/.mcp.json`.
- Examples include `~/.warp/.mcp.json`, `~/.warp-dev/.mcp.json`, and `~/.warp-local/.mcp.json`.
- When the MCP file is created, edited, moved into place, or deleted, Warp updates detected file-based MCP servers without requiring a restart, as long as the relevant parent path is watchable.
- Warp MCP config is scoped as a user-level config, not as a project config or platform app-data config.
### Worktree exclusion
- Activity under `.warp*/worktrees` must not trigger reloads for themes, workflows, tab configs, settings, skills, or MCP config.
- Supporting Warp home skills must not be implemented by recursively watching all possible `.warp*` directories.
- Supporting Warp home MCP config must not be implemented by recursively watching all possible `.warp*` directories.
### Existing app paths
- Channel-aware app files under `data_dir()` continue to work as before for non-Skills/MCP app config.
- `data_dir()` remains the root for channel-scoped themes, workflows, launch configs, tab configs, and other app-managed files.
- `config_local_dir()` remains the root for platform-specific config files such as `settings.toml`, `keybindings.yaml`, and `user_preferences.json`.
## Success Criteria
- `oz agent run --skill <name>` can resolve `<warp-home-config-dir>/skills/<name>/SKILL.md` from a cold start.
- Skill resolution still finds project skills when no matching Warp home skill exists.
- Warp home skills still take precedence over project skills for unqualified skill names.
- File-based MCP detection includes `<warp-home-config-dir>/.mcp.json` as a user-scoped Warp provider config when present.
- Dev/Local/Profiled builds use isolated `.warp*` home config directories instead of Stables `~/.warp` directory.
- No code path treats non-macOS XDG/AppData `data_dir()/skills` or `data_dir()/.mcp.json` as Warp home Skills or MCP sources.
- No code path reintroduces a generic recursive watcher rooted at `~/.warp`.
- `.warp*/worktrees` changes remain excluded from Warp-managed reload behavior.
## Validation
- Add or update unit coverage for `oz --skill` resolving a skill from an explicit Warp home skills directory.
- Add or update unit coverage for Warp home config path helper behavior.
- Add or update unit coverage for MCP path classification so `<warp-home-config-dir>/.mcp.json` is recognized as a Warp MCP config path.
- Add or update watcher helper tests to verify managed Skills/MCP helpers return the current environments Warp home paths.
- Add or update skill utility tests so only the current environments Warp home skills directory is classified as home Warp skills.
- Run targeted Rust tests for path helpers, skill resolution, skill file watcher utilities, MCP provider/path helpers, and Warp managed path filtering.
## Alternatives Considered
- Use only hardcoded `~/.warp` for Skills/MCP. Rejected because it loses Dev/Local/Profile environment isolation.
- Keep using `data_dir()` for Skills/MCP. Rejected because non-macOS app data paths are XDG/AppData paths, not Warps home-relative `.warp*` config paths.
- Use `config_local_dir()` for Skills/MCP. Rejected because non-macOS config-local paths are also platform project directories, not home-relative `.warp*` paths.
- Add only a resolver fallback for `oz --skill`. Rejected because it fixes cold CLI resolution but leaves app hot reload, skill discovery, and MCP path behavior inconsistent.
- Re-add Warp to generic home-provider watchers. Rejected because that watcher shape can recursively watch `.warp*` parents and reintroduce `.warp*/worktrees` churn.
- Watch all of `~/.warp` recursively and filter in consumers. Rejected because it recreates the broad watcher shape APP-3945 was designed to remove.
## Open Questions
- Should Warp proactively create the current environments Warp home config directory on startup, or only watch it when it already exists? The implementation should prefer the least invasive approach unless product explicitly wants fresh installs to create these paths.
+124
View File
@@ -0,0 +1,124 @@
# APP-4087: Fix Warp skill and MCP home config paths after watcher unification Technical Spec
## Problem
APP-3945 introduced `WarpDataDirectoryWatcher` to centralize Warp-specific filesystem watching and avoid recursively watching `.warp*/worktrees`. The follow-up problem is that `SkillProvider::Warp` and `MCPProvider::Warp` were tied to app data paths. On macOS those paths are home-relative and channel-aware, but on Linux and Windows they are XDG/AppData project directories.
The technical goal is to preserve centralized watching while separating three path concepts:
- `data_dir()` for channel/platform app data such as themes, workflows, launch configs, and tab configs
- `config_local_dir()` for platform-specific local config such as settings and preferences
- a new Warp home config directory helper for user-facing Warp Skills and MCP, preserving `.warp*` home-relative names and channel/profile isolation across all OSes
## Relevant code
- `crates/warp_core/src/paths.rs` — owns app data/config paths and the new Warp home config directory helpers.
- `app/src/warp_managed_paths_watcher.rs` — singleton watcher for safe Warp-managed roots and app-local wrappers around the core helpers.
- `app/src/lib.rs` — startup registration for the Warp watcher and watch root preparation.
- `app/src/ai/skills/file_watchers/skill_watcher.rs` — subscribes to Warp watcher events and filters Warp home skill updates.
- `app/src/ai/skills/resolve_skill_spec.rs` — resolves `oz --skill` specs and scans home/global skill directories on cold start.
- `app/src/ai/skills/file_watchers/utils.rs` — classifies skill paths and detects home provider skill paths.
- `app/src/ai/skills/skill_utils.rs` — maps changed files to `SKILL.md` paths.
- `crates/ai/src/skills/skill_provider.rs` — defines provider paths, `home_skills_path`, provider classification, and scope classification.
- `app/src/ai/mcp/file_mcp_watcher.rs` — subscribes to Warp watcher events and handles Warp home MCP updates.
- `app/src/ai/mcp/mod.rs` — defines `MCPProvider::home_config_path`, `home_config_file_path`, and `mcp_provider_from_file_path`.
- `app/src/user_config/native.rs` — consumes Warp watcher updates for themes, workflows, launch configs, tab configs, and settings.
## Path helper design
Add purpose-specific helpers in `warp_core::paths`:
- `warp_home_config_dir_name() -> String`
- `warp_home_config_dir() -> Option<PathBuf>`
- `warp_home_skills_dir() -> Option<PathBuf>`
- `warp_home_mcp_config_file_path() -> Option<PathBuf>`
`warp_home_config_dir_name()` uses `ChannelState::channel()` and `ChannelState::data_profile()`:
- Stable and Preview: `.warp`
- Dev: `.warp-dev`
- Local: `.warp-local`
- Integration: `.warp-integration`
- OpenWarp: `.openwarp`
- Debug data profile: append `-<profile>` to the base name
`warp_home_config_dir()` joins that name to `dirs::home_dir()`. This intentionally differs from non-macOS `data_dir()` and `config_local_dir()`, which use `ProjectDirs` and therefore produce XDG/AppData paths.
## Watch roots
`WarpManagedPathsWatcher` registers:
- `data_dir()` recursively, with a filter excluding `<data_dir>/worktrees`
- `config_local_dir()` recursively when distinct from `data_dir()`
- `warp_home_skills_dir()` recursively when it exists and is not already covered by `data_dir()` or `config_local_dir()`
- `warp_home_config_dir()` non-recursively with a filter that only accepts `warp_home_mcp_config_file_path()` when it exists and is not already covered by `data_dir()` or `config_local_dir()`
The implementation must not recursively watch all of `~/.warp` or all possible `.warp*` directories.
If the Warp home config paths do not exist, the watcher should not fail the session. Startup disk parsing and cold resolution should still work when files exist, and future creation behavior can be handled separately if needed.
## Skill watcher consumption
`SkillWatcher` subscribes to `WarpManagedPathsWatcher`.
Initial Warp skill loading reads from `warp_managed_skill_dirs()`, which resolves to `warp_core::paths::warp_home_skills_dir()` when home exists.
Incremental handling filters updates by the current environments Warp home skills directory:
```text
for skills_dir in warp_managed_skill_dirs() {
if let Some(filtered_update) = filter_repository_update_by_prefix(update, &skills_dir) {
handle_repository_update(filtered_update)
}
}
```
`SkillProvider::Warp` remains excluded from generic home-provider watching. The generic home-provider watcher must not be used to watch `.warp*` parents.
## Skill resolver cold-start behavior
`resolve_skill_spec` checks home/global skill directories from disk after cached home matches and before project resolution.
The resolver fallback scans home provider paths in provider precedence order. For `SkillProvider::Warp`, `home_skills_path(SkillProvider::Warp)` resolves to `warp_core::paths::warp_home_skills_dir()`.
Full-path skill specs keep existing root-relative behavior and should not start accepting arbitrary absolute paths.
## Skill path classification
Skill path classification helpers classify the current environments Warp home skills directory as the home Warp skills path:
- `extract_skill_parent_directory`
- `is_home_provider_path`
- `skill_path_from_file_path`
- `get_provider_for_path`
- `get_scope_for_path`
They do not classify non-macOS XDG/AppData `data_dir()/skills` as a Warp home skill path.
## MCP watcher consumption
`FileMCPWatcher` subscribes to `WarpManagedPathsWatcher`.
Startup parsing parses the single `warp_managed_mcp_config_path()` if home exists.
Incremental handling evaluates the single current-environment config path:
```text
let mcp_path = warp_managed_mcp_config_path()
let was_deleted = update deletes or moves out mcp_path.config_path
let was_added = update adds/modifies or moves into mcp_path.config_path
handle_single_config_update(mcp_path.root_path, MCPProvider::Warp, mcp_path.config_path, was_deleted, was_added)
```
The config path is `warp_core::paths::warp_home_mcp_config_file_path()`. The logical root path remains `dirs::home_dir()` so `FileBasedMCPManager` treats it as user-scoped MCP config.
## MCP path classification
`home_config_file_path(MCPProvider::Warp)` returns `warp_core::paths::warp_home_mcp_config_file_path()`.
`mcp_provider_from_file_path` recognizes the exact Warp home MCP path first, then continues to fall back to project-config suffix matching for project configs.
## Preserve user config behavior
`WarpConfig` keeps consuming `WarpManagedPathsWatcher` for themes, workflows, launch configs, tab configs, and settings. Its filtering remains path-specific:
- data-dir content is still checked against `themes_dir()`, `workflows_dir()`, `launch_configs_dir()`, and `tab_configs_dir()`
- settings still uses `user_preferences_toml_file_path()` under `config_local_dir()`
## End-to-end flow
1. Startup prepares the standard channel-aware watch roots.
2. `WarpManagedPathsWatcher` registers `data_dir()` with `worktrees` excluded and registers `config_local_dir()` when distinct.
3. `WarpManagedPathsWatcher` registers safe Warp home roots if not already covered: the Skills directory recursively and the config directory narrowly for `.mcp.json`.
4. The watcher emits `FilesChanged(update)` for all registered managed roots.
5. `WarpConfig` filters the update for user config paths and reloads relevant config.
6. `SkillWatcher` filters the update against the current environments Warp home skills directory and handles skill add/update/delete semantics.
7. `FileMCPWatcher` checks the current environments Warp home MCP config path and emits user-scoped MCP events as appropriate.
8. `oz --skill <name>` resolves from cached home skills first, then scans home/global skill paths from disk, then falls back to project/repo resolution.
## Risks and mitigations
- Risk: recursively watching `.warp*` parents reintroduces worktree events.
- Mitigation: register the exact Skills directory for recursive watching and only watch the config directory non-recursively filtered to `.mcp.json`.
- Risk: path helper changes accidentally reclassify project `.warp/skills` as home skills.
- Mitigation: only classify the exact current-environment Warp home skills prefix as a home path; continue using suffix matching for project provider paths.
- Risk: `FileBasedMCPManager` stores Warp home MCP under the wrong logical root.
- Mitigation: the managed MCP config helper carries both logical root and file path, with `root_path = home_dir`.
- Risk: cold `oz --skill` still races async skill loading.
- Mitigation: resolver scans home/global skill directories directly before project fallback.
## Alternatives Considered
- Use only hardcoded `~/.warp` for Skills/MCP. Rejected because it loses Dev/Local/Profile environment isolation.
- Keep using `data_dir()` for Skills/MCP. Rejected because non-macOS app data paths are XDG/AppData paths, not Warps home-relative `.warp*` config paths.
- Use `config_local_dir()` for Skills/MCP. Rejected because non-macOS config-local paths are also platform project directories, not home-relative `.warp*` paths.
- Fix only `resolve_skill_spec`. Rejected as incomplete because `SkillWatcher` would still not initial-load or hot-reload Warp home skills, and MCP would keep the same platform mismatch.
- Let `SkillWatcher` register a home provider watcher for Warp again. Rejected because `DirectoryWatcher` would watch a `.warp*` parent recursively for skills, which can reintroduce worktree events.
- Add separate filesystem watchers in `SkillWatcher` and `FileMCPWatcher`. Rejected because the central watcher was introduced specifically to make Warp-managed path filtering and exclusions auditable in one place.
## Testing and validation
- Add or update `warp_core::paths` tests for Warp home config directory, Skills directory, and MCP config path helpers.
- Add or update `resolve_skill_spec` tests for resolving a simple skill name from a Warp home skills directory without relying on `SkillManager`.
- Add or update watcher helper tests for current-environment Warp home Skills and MCP helper paths.
- Add or update skill utility tests showing the current-environment Warp home skills directory classifies as a Warp home skill path.
- Add or update MCP helper tests showing the current-environment Warp home MCP file classifies as `MCPProvider::Warp`.
- Run targeted commands such as:
- `cargo test -p warp_core --lib paths`
- `cargo test -p ai skills::skill_provider --lib`
- `cargo test -p warp --lib resolve_from_root_path_by_directory_scan`
- `cargo test -p warp --lib file_watchers::utils`
- `cargo test -p warp --lib mcp`
- `cargo test -p warp --lib warp_managed_paths_watcher`
## Follow-ups
- Consider adding lifecycle support for creating the current environments Warp home config directory after startup without proactively creating it.
- Consider updating public docs if they should explicitly describe Dev/Local/Profile-specific `.warp*` Skills and MCP locations.