# Tab Configs

> Reference the Warp tab config schema, validation rules, and examples. Use when creating or updating Warp tab config TOML files or when another tab-config skill needs the canonical schema details.

- Skill: `liueggy/tab-configs` (Agent Skill)
- Install (CLI): `npx skillmds@latest add liueggy/tab-configs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/liueggy/tab-configs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: liueggy (https://skillmd.com/u/liueggy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/liueggy/tab-configs

---


# tab-configs

This skill is the canonical reference for Warp tab config TOML files.

Tab configs live under `~/.warp/tab_configs/` for standard Warp builds. Non-stable builds (e.g. Preview or pre-release channels) use a channel-specific variant such as `~/.warp-<channel>/tab_configs/`. Do NOT use `~/Library/Application Support/` — that is the wrong location.

To find the active data directory, inspect which `~/.warp*` directories exist on the user's machine. Each `.toml` file defines a single tab layout that appears in the `+` menu. When the user selects one, Warp opens a new tab with the configured pane layout and runs any specified commands.

Use this skill as shared context:
- `create-tab-config` should use it when authoring a new config.
- `update-tab-config` should use it when modifying an existing config.
- If this skill is invoked directly for a creation or editing task, follow the same guidance below.

## Guidance before writing or editing

- If the request is missing important details, use the `ask_user_question` tool instead of guessing. Clarify things like:
  - whether the user wants a new config or wants to edit an existing one
  - the desired pane layout
  - directories, commands, and which pane should be focused
  - whether parameters are needed
- Use descriptive pane IDs such as `"editor"`, `"server"`, or `"top_left"` instead of generic names like `"pane1"`.
- Use snake_case file names for new configs.
- When creating or locating tab configs, use the correct tab config directory for the user's current Warp build/channel rather than hardcoding a single base directory.
- If updating an existing config, read the file first and preserve user structure where possible.

## Schema Reference

### Top-level fields

- `name` (required, string): Display name shown in the `+` menu.
- `title` (optional, string): Custom tab title. Supports `{{param}}` template variables.
- `color` (optional, string): Tab color. One of: `"black"`, `"red"`, `"green"`, `"yellow"`, `"blue"`, `"magenta"`, `"cyan"`, `"white"`.

### Pane list

All panes are defined in a flat `[[panes]]` array of tables. The **first entry is the root**. Each entry is either a **split node** (branch) or a **leaf node**.

#### Leaf node fields

- `id` (required, string): Unique identifier.
- `type` (required, string): `"terminal"` (standard shell), `"agent"` (opens in Agent Mode), or `"cloud"` (cloud mode pane, no local shell).
- `directory` (optional, string): Initial working directory. Supports `~` expansion. Applies to `terminal` and `agent` types.
- `commands` (optional, array of strings): Commands to run in sequence on open. Applies to `terminal` and `agent` types.
- `is_focused` (optional, bool): Set `true` on at most one pane to give it initial focus.
- `shell` (optional, string): Shell executable to open this pane in (e.g. `"pwsh"`, `"zsh"`, `"bash"`, `"fish"`). Only applies to `terminal` and `agent` types. If omitted or the shell is not installed, the user's default shell is used.

#### Split node fields

- `id` (required, string): Unique identifier for this node.
- `split` (required, string): `"horizontal"` (children arranged left-to-right) or `"vertical"` (children arranged top-to-bottom).
- `children` (required, array of strings): Ordered list of child pane IDs. Must have 2+ entries. Order = visual order.

```toml
[[panes]]
id = "server"
type = "terminal"
directory = "~/code/backend"
commands = ["cargo watch -x run"]
```

### Sizing

All children within a split are equally sized. There are no flex or proportion values.

### Parameters

Parameters let users fill in values at open time via a modal UI. Declare them with `[params.<name>]` tables. Reference them in `directory`, `commands`, and `title` with `{{name}}` syntax.

`{{autogenerated_branch_name}}` is a special-cased reserved template variable: if a tab config references it, Warp generates a unique worktree branch name on each open instead of prompting the user for that value.

Each parameter has:
- `type` (optional, string): `"text"` (default), `"branch"` (git branch picker), or `"repo"` (repo picker).
- `description` (optional, string): Shown in the fill-in UI.
- `default` (optional, string): Default value.

```toml
[params.project_dir]
type = "repo"
description = "Project directory"

[params.branch]
type = "branch"
description = "Branch to check out"
```


### Validation rules

Ensure your output follows these rules:
- Every ID in a `children` array must reference an existing `[[panes]]` entry.
- No cycles in the pane tree.
- Leaf panes must NOT have `children` or `split`.
- Leaf panes must have a `type` field (`"terminal"`, `"agent"`, or `"cloud"`).
- Split panes (have `split`) must have `children` with at least 2 entries.
- At most one pane may have `is_focused = true`.
- All `id` values must be unique across the file.
- The first `[[panes]]` entry is the root of the tree.

## Examples

### Single pane

```toml
name = "Dev Server"

[[panes]]
id = "main"
type = "terminal"
directory = "~/code/my-app"
commands = ["npm run dev"]
```

### Two panes side by side

```toml
name = "Editor + Server"
color = "green"

[[panes]]
id = "root"
split = "horizontal"
children = ["editor", "server"]

[[panes]]
id = "editor"
type = "terminal"
directory = "~/code/my-app"
commands = ["nvim ."]
is_focused = true

[[panes]]
id = "server"
type = "terminal"
directory = "~/code/my-app"
commands = ["npm run dev"]
```

### 2x2 grid

```toml
name = "Full Stack"

[[panes]]
id = "root"
split = "horizontal"
children = ["left_col", "right_col"]

[[panes]]
id = "left_col"
split = "vertical"
children = ["frontend", "backend"]

[[panes]]
id = "frontend"
type = "terminal"
directory = "~/code/frontend"
commands = ["npm run dev"]
is_focused = true

[[panes]]
id = "backend"
type = "terminal"
directory = "~/code/backend"
commands = ["cargo watch -x run"]

[[panes]]
id = "right_col"
split = "vertical"
children = ["tests", "logs"]

[[panes]]
id = "tests"
type = "terminal"
directory = "~/code/backend"
commands = []

[[panes]]
id = "logs"
type = "terminal"
directory = "~/code/backend"
commands = ["tail -f logs/dev.log"]
```

### Three-pane layout (1 left, 2 stacked right)

```toml
name = "Main + Side Stack"

[[panes]]
id = "root"
split = "horizontal"
children = ["main", "side_stack"]

[[panes]]
id = "main"
type = "terminal"
directory = "~/code/project"
commands = []
is_focused = true

[[panes]]
id = "side_stack"
split = "vertical"
children = ["top_right", "bottom_right"]

[[panes]]
id = "top_right"
type = "terminal"
directory = "~/code/project"
commands = []

[[panes]]
id = "bottom_right"
type = "terminal"
directory = "~/code/project"
commands = []
```

### With parameters
Warp-generated worktree configs default to `~/.warp/worktrees/<repo-name>/<worktree-name>`. When writing a reusable config by hand, derive the repo-name segment at shell runtime with `$(basename {{repo}})`.

```toml
name = "New Worktree"
title = "{{branch_name}}"

[[panes]]
id = "main"
type = "terminal"
directory = "{{repo}}"
commands = [
  "git worktree add -b {{branch_name}} $HOME/.warp/worktrees/$(basename {{repo}})/{{branch_name}} {{base_branch}}",
  "cd $HOME/.warp/worktrees/$(basename {{repo}})/{{branch_name}}",
]

[params.repo]
type = "repo"
description = "Repository path"

[params.base_branch]
type = "branch"
description = "Base branch to branch from"

[params.branch_name]
type = "text"
description = "New branch name"
default = "my-feature"
```

## Common patterns

When the user says...                                    | Generate...
"single pane" / "simple tab"                             | One `[[panes]]` leaf entry
"split" / "side by side" / "two panes"                   | Horizontal split with 2 terminal children
"top and bottom" / "stacked"                             | Vertical split with 2 terminal children
"2x2" / "grid" / "four panes"                            | Horizontal split → 2 vertical splits → 4 terminals
"run X" / "auto-run X"                                   | Put `X` in the `commands` array
"with claude" / "running claude"                         | `commands = ["claude"]` in the relevant pane
"three panes" (no further detail)                        | Horizontal split: 1 terminal + 1 vertical split with 2 terminals

