Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# Finalize TOML Schema for Tab Configs
|
||||
|
||||
Linear: [APP-3575](https://linear.app/warpdotdev/issue/APP-3575/finalize-toml-schema-for-tab-configs)
|
||||
|
||||
## Summary
|
||||
|
||||
Replace the recursive `[layout]` / `[[layout.panes]]` TOML nesting in tab configs with a flat `[[panes]]` array where nodes reference children by string ID. This makes deeply nested split layouts readable and hand-editable, and ships a bundled Oz skill so users can generate tab configs from natural language.
|
||||
|
||||
## Problem
|
||||
|
||||
The existing tab config layout format uses recursive TOML tables (`[[layout.panes]]`, `[[layout.panes.panes]]`, etc.). At depth 3+ this becomes unreadable and error-prone for hand-editing. Users who want a 2x2 grid or deeper nesting have to mentally track nested array-of-tables syntax, which is a significant barrier to adoption.
|
||||
|
||||
Additionally, there is no guided way for users to create tab configs — they must hand-author TOML from scratch.
|
||||
|
||||
## Goals
|
||||
|
||||
- A flat, ID-referenced pane tree format that supports arbitrarily deep nesting while remaining readable.
|
||||
- A bundled Oz skill (`tab-configs`) that generates valid tab config TOML from natural language descriptions.
|
||||
- A default template that is ready to use out of the box (single terminal pane, uncommitted, with `commands = []` pre-populated).
|
||||
- Tab color support (`color` field) matching launch config parity.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Supporting non-terminal pane types beyond agent and cloud (notebook, code, settings, etc.).
|
||||
- Multi-tab or multi-window configs (tab configs define a single tab by design).
|
||||
- Proportional/flex sizing of children within a split.
|
||||
- Converting existing launch configs to the new tab config format.
|
||||
|
||||
## Figma
|
||||
|
||||
Figma: none provided. This feature has no new UI — it changes the file format and adds an Oz skill.
|
||||
|
||||
## User experience
|
||||
|
||||
### Creating a new tab config
|
||||
|
||||
1. User clicks `+` → "Create new tab config..." in the tab bar menu.
|
||||
2. Warp writes the default template to `~/.warp/tab_configs/my_tab_config.toml` and opens it in the user's configured editor.
|
||||
3. The template contains an active single-pane config with `commands = []`, and commented-out examples for two-pane split, 2x2 grid, and parameterized configs.
|
||||
4. The template header mentions the Oz skill: "Ask Oz to generate a tab config for you!"
|
||||
|
||||
### Using the Oz skill
|
||||
|
||||
- User invokes `/skills → tab-configs` or asks Oz naturally (e.g. "create me a 2x2 tab config with one pane running my dev server").
|
||||
- Oz generates a valid `.toml` file and writes it to `~/.warp/tab_configs/`.
|
||||
- The file immediately appears in the `+` menu (the filesystem watcher picks it up).
|
||||
|
||||
### Opening a tab config
|
||||
|
||||
- User clicks `+` → "New Tab: <config name>".
|
||||
- If the config has `[params]`, a modal appears for the user to fill in values.
|
||||
- Warp opens a new tab with the specified pane layout, running any configured commands.
|
||||
- If the config has a `color` field, the tab gets that color.
|
||||
|
||||
### Format behavior
|
||||
|
||||
- Pane layout is defined with a flat `[[panes]]` array.
|
||||
- The first `[[panes]]` entry is the root of the tree.
|
||||
- Split nodes have `split` (horizontal/vertical) and `children` (ordered array of child IDs).
|
||||
- Leaf nodes have `id`, required `type` (`"terminal"`, `"agent"`, or `"cloud"`), optional `cwd`, optional `commands`, and optional `is_focused`.
|
||||
- `terminal` opens a standard shell session. `agent` opens a terminal in Agent Mode. `cloud` opens a cloud mode (ambient agent) pane with no local shell.
|
||||
- `cwd` and `commands` apply to `terminal` and `agent` types; they are ignored for `cloud`.
|
||||
- `worktree_name_autogenerated` (optional, bool, default false): when `true`, Warp auto-generates the worktree branch name instead of prompting the user. The app detects worktree configs by scanning `commands` for `git worktree`.
|
||||
- All children within a split are equally sized.
|
||||
- If no pane has `is_focused = true`, the first leaf pane gets focus automatically.
|
||||
|
||||
### Error handling
|
||||
|
||||
- If the flat pane tree has validation errors (missing child references, duplicate IDs, fewer than 2 children in a split), the config falls back to a single empty terminal pane and logs a warning.
|
||||
- Invalid TOML or missing `name` field causes the file to be skipped with a warning logged.
|
||||
|
||||
## Success criteria
|
||||
|
||||
1. A tab config using the flat `[[panes]]` format with a horizontal 2-pane split opens correctly: two side-by-side terminal panes, each with the specified `cwd` and `commands`.
|
||||
2. A tab config using the flat format with a 2x2 grid (horizontal split → two vertical splits → four terminals) opens correctly with four equal-sized panes.
|
||||
3. A tab config with `color = "blue"` opens with a blue tab.
|
||||
4. A tab config with `is_focused = true` on a specific pane gives that pane initial focus.
|
||||
5. A tab config with no `is_focused` gives focus to the first (leftmost/topmost) leaf pane.
|
||||
6. A tab config with `[params]` shows the param-fill modal before opening.
|
||||
7. A tab config with a `[[panes]]` format that has an invalid child reference logs a warning and opens a single empty terminal pane.
|
||||
8. The `tab-configs` bundled skill appears in `/skills` in Warp.
|
||||
9. The default template, when uncommitted and left as-is, parses as a valid single-pane tab config named "My Tab Config".
|
||||
|
||||
## Validation
|
||||
|
||||
- Unit tests for parsing and rendering the flat format (single pane, split, 2x2, focus handling, error cases).
|
||||
- Manual verification: create a 2x2 tab config TOML, open it from the `+` menu, confirm four panes appear with correct `cwd` and `commands`.
|
||||
- Manual verification: invoke the `tab-configs` skill and confirm it generates a valid TOML file that opens correctly.
|
||||
|
||||
## Open questions
|
||||
|
||||
(None outstanding.)
|
||||
@@ -0,0 +1,118 @@
|
||||
# Finalize TOML Schema for Tab Configs — Tech Spec
|
||||
|
||||
Linear: [APP-3575](https://linear.app/warpdotdev/issue/APP-3575/finalize-toml-schema-for-tab-configs)
|
||||
|
||||
## Problem
|
||||
|
||||
The recursive `[layout]` / `[[layout.panes]]` TOML format becomes unreadable at depth 3+. We need to replace it with a flat `[[panes]]` array where nodes reference children by string ID, add tab color support, and ship a bundled Oz skill for generating configs.
|
||||
|
||||
## Relevant code
|
||||
|
||||
- `app/src/tab_configs/tab_config.rs` — `TabConfig`, `TabConfigPaneNode`, `render_tab_config`, `resolve_pane_tree`
|
||||
- `app/src/tab_configs/tab_config_tests.rs` — existing tests for parsing and rendering
|
||||
- `app/src/tab_configs/mod.rs` — public exports
|
||||
- `app/src/workspace/view.rs:4702-4780` — `open_tab_config_with_params`, `open_tab_config`, `create_and_open_new_tab_config`
|
||||
- `app/src/launch_configs/launch_config.rs` — `PaneTemplateType`, `SplitDirection`, `CommandTemplate` (the output types tab configs produce)
|
||||
- `app/src/pane_group/mod.rs:1181-1333` — `pane_tree_from_template` (consumes `PaneTemplateType` to create panes)
|
||||
- `app/src/user_config/native.rs:228-232` — `load_tab_configs`
|
||||
- `app/src/user_config/util.rs:167-180` — `parse_tab_config_dir_entry` (TOML parsing)
|
||||
- `app/resources/tab_configs/new_tab_config_template.toml` — default template
|
||||
- `resources/bundled/skills/tab-configs/SKILL.md` — bundled Oz skill
|
||||
- `app/src/ai/skills/skill_manager.rs` — bundled skill loading from `resources/bundled/skills/`
|
||||
|
||||
## Current state
|
||||
|
||||
Tab configs are TOML files in `~/.warp/tab_configs/`. They previously used a recursive `TabConfigLayout` struct with nested `panes: Vec<TabConfigLayout>` for child splits, which became impractical at depth 3+.
|
||||
|
||||
There is no `color` field on `TabConfig` — launch configs support color via `TabTemplate.color` but tab configs don't.
|
||||
|
||||
There is no bundled skill for generating tab configs.
|
||||
|
||||
## Proposed changes
|
||||
|
||||
### 1. New struct: `TabConfigPaneNode`
|
||||
|
||||
A flat node in the `[[panes]]` array. Distinguished as split vs leaf by the presence of `split` + `children`. No `type` field — all leaves are terminal panes (a `type` discriminator will be added when non-terminal pane types are supported).
|
||||
|
||||
Fields: `id`, `pane_type` (serde-renamed to `type`), `split`, `children`, `is_focused`, `cwd`, `commands`, `worktree_name_autogenerated`.
|
||||
|
||||
`worktree_name_autogenerated` (bool, default false): when `true`, the param-fill UI auto-generates the worktree branch name instead of showing a free-text input. The app infers "is this a worktree config?" by scanning `commands` for `git worktree` — no separate `worktree` flag is needed.
|
||||
|
||||
### 1b. New enum: `TabConfigPaneType`
|
||||
|
||||
Terminal / Agent / Cloud — maps to `PaneMode` at render time.
|
||||
|
||||
### 1c. New enum: `PaneMode` (in `launch_config.rs`)
|
||||
|
||||
Terminal (default) / Agent / Cloud — added as a field on `PaneTemplateType::PaneTemplate` with `#[serde(default)]` so launch config deserialization is unaffected.
|
||||
|
||||
### 2. Updated `TabConfig`
|
||||
|
||||
Add two fields:
|
||||
- `color: Option<AnsiColorIdentifier>` — tab color, applied after tab creation (matching the launch config pattern in `open_launch_config_window`).
|
||||
- `panes: Vec<TabConfigPaneNode>` — flat pane list. The first entry is the root of the pane tree.
|
||||
|
||||
Remove the old `layout: TabConfigLayout` field and the `TabConfigLayout` struct entirely. The legacy `[layout]` format is no longer supported.
|
||||
|
||||
### 3. `resolve_pane_tree` function
|
||||
|
||||
Converts the flat `panes` list into a `PaneTemplateType` tree:
|
||||
1. Index all nodes by ID. Reject duplicate IDs.
|
||||
2. Root = first entry.
|
||||
3. Recursively resolve: split nodes look up children by ID; leaf nodes produce `PaneTemplate { cwd, commands, is_focused }`.
|
||||
4. Focus handling: if any pane has explicit `is_focused = true`, use it. Otherwise auto-focus the first leaf (matching legacy `render_layout` behavior).
|
||||
5. On error (missing refs, <2 children), return `Err` and the caller falls back to a single empty terminal.
|
||||
|
||||
### 4. Updated `render_tab_config`
|
||||
|
||||
Always calls `resolve_pane_tree`. On error (empty panes, missing refs, missing `type` on a leaf, etc.), falls back to a single empty terminal pane with a logged warning. Leaf resolution maps `TabConfigPaneType` to `PaneMode` and sets it on the produced `PaneTemplate`.
|
||||
|
||||
### 5. Updated `open_tab_config_with_params` in workspace view
|
||||
|
||||
After `add_tab_with_pane_layout`, apply `tab_config.color` to the new tab's `selected_color` — the same pattern launch configs use at `workspace/view.rs:2386`.
|
||||
|
||||
### 6. Updated template
|
||||
|
||||
`app/resources/tab_configs/new_tab_config_template.toml` uses the new flat format. Active (uncommented) content is a single-pane terminal with `commands = []`. Commented examples show two-pane split, 2x2 grid, and parameterized configs.
|
||||
|
||||
### 7. Bundled Oz skill
|
||||
|
||||
`resources/bundled/skills/tab-configs/SKILL.md` contains the full schema reference, examples, validation rules, and common natural-language-to-layout mappings. The build script (`script/prepare_bundled_resources`) copies it into the app bundle automatically.
|
||||
|
||||
## End-to-end flow
|
||||
|
||||
1. User creates/edits a `.toml` file in `~/.warp/tab_configs/`.
|
||||
2. Filesystem watcher in `WarpConfig` detects the change and calls `load_tab_configs`.
|
||||
3. `parse_tab_config_dir_entry` calls `toml::from_str::<TabConfig>()`. The `panes` field deserializes from `[[panes]]` entries.
|
||||
4. User selects the config from the `+` menu → `open_tab_config` is called.
|
||||
5. If params exist, the param-fill modal opens. Otherwise `open_tab_config_with_params` is called directly.
|
||||
6. `render_tab_config` builds param contexts, calls `resolve_pane_tree`, returns `(Option<String>, PaneTemplateType)`.
|
||||
7. Workspace calls `add_tab_with_pane_layout(PanesLayout::Template(pane_template), ...)`.
|
||||
8. `PaneGroup::pane_tree_from_template` recursively creates panes from the `PaneTemplateType` tree. For `PaneMode::Agent`, it creates a terminal session then enters agent mode. For `PaneMode::Cloud`, it creates an ambient agent pane via `create_ambient_agent_terminal`.
|
||||
9. If `tab_config.color` is set, the tab's `selected_color` is updated.
|
||||
|
||||
## Risks and mitigations
|
||||
|
||||
- **Flat pane list validation**: Invalid configs (missing refs, cycles) are caught at render time with descriptive error messages logged and a fallback to a single terminal pane. The user's tab config file is never modified.
|
||||
- **Skill generating invalid TOML**: The skill embeds validation rules and examples. The schema is simple enough (terminal-only, no type field) that generation errors are unlikely.
|
||||
|
||||
## Testing and validation
|
||||
|
||||
- Unit tests in `tab_config_tests.rs`:
|
||||
- Parse single flat pane.
|
||||
- Parse and render flat two-pane split.
|
||||
- Parse and render flat 2x2 grid.
|
||||
- Explicit `is_focused` honored.
|
||||
- Auto-focus first leaf when no explicit focus.
|
||||
- Invalid flat pane tree (missing child ref) returns error.
|
||||
- Duplicate IDs rejected.
|
||||
- Tab color deserialized correctly.
|
||||
- Manual: build and run Warp, create tab configs, verify pane layouts open correctly.
|
||||
- Manual: invoke the `tab-configs` skill, confirm it generates a working config.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Add non-terminal pane types (notebook, code, settings, etc.) with a `type` field discriminator.
|
||||
- Consider cycle detection in validation (currently not implemented — the recursive resolver will stack overflow on cycles, but configs are small enough that this is not a practical concern).
|
||||
- Consider orphan pane warnings (panes not referenced by any `children` and not the root).
|
||||
- Investigate whether the Oz skill should auto-open the created config in the user's editor.
|
||||
Reference in New Issue
Block a user