Files

130 lines
7.5 KiB
Markdown

# Separate Preview Config Directory on macOS
## Summary
On macOS, give the Preview channel its own config directory (`~/.warp-preview`) instead of sharing `~/.warp` with Stable. On first launch, migrate existing config by symlinking each top-level entry from `~/.warp` into `~/.warp-preview`, so existing Preview users keep all their customizations.
## Problem
Stable and Preview currently share the `~/.warp` directory on macOS. This means:
- Settings changes made in one channel affect the other.
- Preview experiments (themes, keybindings, tab configs, etc.) can break the Stable experience.
- There is no safe way to test config-level changes on Preview without risking Stable user data.
Other channels (Dev, Integration, Local) already use separate directories (`.warp-dev`, `.warp-integration`, `.warp-local`). Preview is the only non-Stable channel that still shares with Stable.
## Goals
1. Preview uses `~/.warp-preview` as its config directory on macOS.
2. Existing Preview users retain all their customizations after the change.
3. Stable users see no change whatsoever.
4. The migration is automatic and requires no user action.
## Non-goals
- Changing behavior on Linux or Windows (these platforms already use separate directories via `ProjectDirs`).
- Migrating the SQLite database (already stored separately in `~/Library/Application Support/` or the App Group container).
- Changing Dev, Integration, or Local channel directories.
- Achieving full bidirectional sync between Stable and Preview configs going forward.
## Figma
Figma: none needed (no UI changes).
## User Experience
### First launch after upgrade (Preview channel)
When a Preview user launches Warp for the first time after this change:
1. Warp detects that `~/.warp-preview` does not exist.
2. Warp creates `~/.warp-preview`.
3. For each top-level entry in `~/.warp` (files and directories), Warp creates a symbolic link in `~/.warp-preview` pointing to the corresponding entry in `~/.warp`.
4. Preview proceeds using `~/.warp-preview` as its config directory.
After migration, the directory looks like:
```
~/.warp-preview/
keybindings.yaml -> ~/.warp/keybindings.yaml
themes/ -> ~/.warp/themes/
workflows/ -> ~/.warp/workflows/
tab_configs/ -> ~/.warp/tab_configs/
...etc
```
### Subsequent launches (Preview)
No migration occurs. Preview reads and writes from `~/.warp-preview`.
### Stable users
Zero change. Stable continues to use `~/.warp`.
### settings.toml is not symlinked
The `settings.toml` file (used by the Settings File feature) is intentionally kept separate between Stable and Preview. The migration uses an explicit exclude list (`MIGRATION_EXCLUDED_FILES`) to skip `settings.toml` during symlinking. This handles the case where a user runs Stable first (which creates `settings.toml` in `~/.warp`) and later updates Preview — without the filter, the migration would symlink the file, causing both channels to share settings.
### Behavior after migration
- **Reading config**: Preview reads through symlinks, so existing Stable config is visible.
- **Modifying a shared file**: If Preview modifies a symlinked file (e.g., `keybindings.yaml`), the change affects Stable too, since the symlink points to the same file. This is the intended tradeoff — users who customize on Preview are likely the same user customizing on Stable.
- **Creating new entries in a symlinked directory**: If Preview creates a new file inside a symlinked directory (e.g., a new tab config in `tab_configs/`), the file is created in `~/.warp/tab_configs/` because the directory symlink resolves there. This is an acceptable limitation of the symlink approach.
- **Breaking the symlink**: If the user wants full independence for a specific config, they can delete the symlink in `~/.warp-preview/` and replace it with a real file or directory. Preview will use the local copy from that point on.
### Edge cases
- **`~/.warp` does not exist**: No migration needed. Preview creates `~/.warp-preview` fresh, and Warp's existing directory-creation logic populates it.
- **`~/.warp-preview` already exists**: Migration is skipped entirely. This handles the case where the user has manually created the directory or is launching for a second time.
- **Entries in `~/.warp` are themselves symlinks** (e.g., `keybindings.yaml -> ~/dotfiles/...`): The migration creates a symlink to the symlink. The chain resolves correctly. No special handling needed.
- **`.DS_Store` and hidden OS files**: These should be skipped during migration to avoid unnecessary clutter.
- **Simultaneous Stable and Preview launch**: The directory creation (`create_dir`) fails atomically if the directory already exists, so concurrent launches are safe. The migration will run in one process and be skipped in the other.
- **Permissions errors**: If symlink creation fails for a specific entry, log a warning and continue with the remaining entries. Partial migration is better than no migration.
## Alternatives Considered
### 1. Full copy instead of symlinks
Copy all files and directories from `~/.warp` to `~/.warp-preview`.
- Pro: Full independence from day one.
- Con: Doubles disk usage for themes, workflows, etc. Changes in Stable no longer propagate to Preview, which could confuse users who expect their config to be shared.
### 2. Symlink the entire directory
Create `~/.warp-preview` as a symlink to `~/.warp`.
- Pro: Simplest implementation.
- Con: Not actually a separate directory. Any new entries created by Preview (e.g., new directories Warp adds in future versions) would appear in `~/.warp`. Defeats the purpose of separation.
### 3. No migration (clean start)
Simply start using `~/.warp-preview` with no migration.
- Pro: Simplest. No migration code.
- Con: Users lose all custom keybindings, themes, workflows, launch configs, tab configs, and settings. This is a bad experience.
### 4. Deep symlink (per-file in each subdirectory)
For each directory like `themes/`, create the directory in `.warp-preview` and symlink each individual file.
- Pro: New files created inside directories stay in `.warp-preview` rather than leaking into `.warp`.
- Con: Significantly more complex. The improvement is marginal — most users don't create new config files frequently, and those who do are likely sophisticated enough to understand the symlink behavior.
**Decision**: Symlink top-level contents (option in the main proposal) is the best balance of simplicity, backwards compatibility, and user experience.
## Success Criteria
1. After upgrading, a Preview user's keybindings, themes, workflows, launch configs, tab configs, MCP config, and settings are all accessible in Preview without manual action.
2. A Stable user's `~/.warp` directory is unchanged after the upgrade.
3. `~/.warp-preview` is created on first launch of Preview and contains symlinks to each top-level entry in `~/.warp`.
4. If `~/.warp` does not exist, `~/.warp-preview` is created empty (normal startup logic applies).
5. If `~/.warp-preview` already exists, no migration runs.
6. The migration only runs on macOS.
7. Partial migration failures (e.g., one symlink fails) do not prevent Warp from launching.
## Validation
- **Manual testing on macOS Preview build**:
- Fresh install with no `~/.warp`: Preview creates `~/.warp-preview`, normal setup.
- Existing `~/.warp` with custom keybindings/themes: After upgrade, verify symlinks exist and config loads correctly.
- Launch Stable after Preview migration: Stable still uses `~/.warp` and is unaffected.
- **Integration test**: Verify the migration function creates expected symlinks given a mock `~/.warp` directory.