Panes and agent CLIs
DeckSpace ships no model. It runs the agent CLIs already installed on your machine, side by side, as peers — and those CLIs do not accept the same flags.
A pane is a terminal. A pane running an agent is the same terminal with an agent CLI as its process. That is the whole mechanism: DeckSpace resolves the command on your login-shell PATH, launches it, and appends the flags that CLI publishes for the toggles you set. Your existing auth, config and subscriptions come along, because it is your CLI running.
The consequence is the thing to understand before you set anything up: a toggle in the DeckSpace UI is not a DeckSpace feature. It is a flag lookup. Where a CLI has no such flag, the toggle is a silent no-op for that pane.
The pane grid
Panes belong to a workspace, not to the app. Switching workspaces swaps the whole set of terminals; each workspace’s grid stays mounted while hidden, so its shells and running agents survive the switch.
| Limit | Value | Where it is set |
|---|---|---|
| Panes per workspace | 16 | MAX_PANES |
| Layout presets in the command palette | 1, 2, 4, 6, 8, 12 | plus Add pane for anything else |
| Layout presets in the setup wizard | 1, 2, 4, 6, 8, 10, 12 | tiles on the workspace step |
| Grid shape | fixed per count | 16 panes tile 4×4; 12 tile 4×3; 9 tile 3×3 |
Two per-pane split buttons in the pane header add one pane at a time: split right puts a new column beside it, split down stacks one below it inside the same column. Both are disabled once the workspace holds 16 panes. Column and row splits are draggable and remembered per grid shape, so a 3×2 layout keeps its proportions across restarts.
Closing a pane kills its shell and any agent in it. Closing the last pane in a workspace does not empty the workspace — it replaces the dead shell with one fresh pane.
What happens at 16
The cap is enforced at every launch path, but each one handles it differently. None of them silently drop work.
| Launcher | Behaviour at the cap |
|---|---|
| Launch into a new pane | Falls back to launching into the active pane. |
| Split buttons | Disabled. |
| Orchestrator | Logs “Pane limit reached — waiting for a task to finish before launching more” and waits. |
| Maestro | Errors: the grid is full — close panes, then resume. |
| Handoff | Aborts the handoff with the grid-full reason. |
| Voice | Errors back to you: the grid is full, 16 panes is the max. |
The registry
Twelve CLIs are built in. Eleven are current; one is retired and kept only so old workspaces still resolve. Each entry is a key, a display name, the command DeckSpace looks for, and how a prompt is handed to it.
| Key | Display name | Binary | How the prompt is passed |
|---|---|---|---|
claude | Claude Code | claude | positional |
codex | Codex | codex | positional |
aider | Aider | aider | --message |
agy | Antigravity | agy | -p |
gemini | Gemini (legacy CLI) | gemini | -p — retired, see below |
opencode | OpenCode | opencode | --prompt |
cursor | Cursor Agent | cursor-agent | positional |
droid | Droid | droid | exec |
copilot | Copilot CLI | copilot | -p |
grok | Grok CLI | grok | positional |
amp | Amp | amp | positional |
qwen | Qwen Code | qwen | -p |
Two entries carry a hard-coded exception, because getting them wrong breaks the pane rather than degrading it. Grok’s prompt is always positional — passing it through a -p-style flag makes the CLI print one reply and exit instead of opening its interface. OpenCode’s positional argument is a project path, not a task, so a prompt always goes through --prompt.
Which toggles each CLI actually supports
This is the table to read before choosing a CLI for a job. A blank cell is a real capability gap: the flag does not exist, so DeckSpace appends nothing and the toggle does nothing for that pane.
| CLI | Fast | Plan | Walk-away | Auto-edit | Model pin |
|---|---|---|---|---|---|
| Claude Code | --model haiku | --permission-mode plan | --dangerously-skip-permissions | --permission-mode acceptEdits | --model |
| Antigravity | --model "Gemini 3.5 Flash (Low)" | --mode plan | --dangerously-skip-permissions | --mode accept-edits | --model |
| Grok CLI | — | --permission-mode plan | --always-approve | --permission-mode acceptEdits | -m |
| Codex | — | — | --dangerously-bypass-approvals-and-sandbox | --ask-for-approval never | -m |
| Qwen Code | — | — | --yolo | --approval-mode auto_edit | — |
| OpenCode | — | — | --auto | — | -m |
| Aider | — | — | — | — | — |
| Droid | — | — | — | — | — |
| Copilot CLI | — | — | — | — | — |
| Cursor Agent | — | — | — | — | — |
| Amp | — | — | — | — | — |
| Gemini (legacy) | -m gemini-2.5-flash | — | --yolo | --approval-mode auto_edit | -m |
Counting the eleven current CLIs: 2 support Fast, 3 support Plan, 6 support walk-away, 5 support auto-edit, 5 support a model pin. Exactly two — Claude Code and Antigravity — support all five. Five of them — Aider, Droid, Copilot CLI, Cursor Agent and Amp — support none of the five, so their launch is the command plus the prompt and nothing more, whatever you have switched on.
Nothing in the pane tells you a flag was skipped. If you set Fast Mode and launch Aider, the toggle stays lit and the launch is unchanged. Check this table, not the switch.
Flag order and precedence
When more than one toggle is on, DeckSpace resolves the conflicts before building the command, in this fixed order.
- Model pin first, if you pinned one and the CLI has a model flag. The value is single-quoted, because it is typed into a shell and some model names contain spaces and parentheses.
- Fast — skipped entirely if a model is pinned. For Claude Code both drive the same
--modelflag, and emitting it twice breaks the launch. - Plan.
- Walk-away.
- Auto-edit — skipped if either plan or walk-away is on, for the same duplicate-flag reason.
Reasoning effort is not a CLI flag. For Claude Code panes it is exported as MAX_THINKING_TOKENS before the command runs; for every other CLI it does nothing.
The Gemini entry is retired
The gemini CLI stopped serving requests on 18 June 2026. Its registry entry is still present so saved workspaces, presets and stored pane state keep resolving rather than erroring, but it is superseded by agy (Antigravity).
Launching the gemini key from a pane redirects to agy. The redirect in the pane-launch path is unconditional — it does not check what you have installed — so on a machine that still has a working gemini but no agy, that launch fails with a not-on-PATH error naming agy. Headless launches (background jobs and workflows) resolve differently: they keep the original binary while it is installed, and redirect only when it is absent and the replacement is present.
Install agy and use the Antigravity entry directly. The install hint stored against the gemini key is not an install command for it — it is a comment saying the CLI is retired, followed by the Antigravity installer.
Installing a CLI
DeckSpace does not install anything. Settings → AI providers runs a scan that checks your login-shell PATH for the known command names and asks each one for its version, with a three-second cap per CLI. Nothing is installed, nothing is changed, and nothing leaves the machine. The scan only ever runs when you click it.
For any CLI it did not find, the row shows a one-line install command with a Copy install button. These are the commands it copies.
| CLI | Install command |
|---|---|
| Claude Code | npm i -g @anthropic-ai/claude-code |
| Codex | npm i -g @openai/codex |
| Aider | python -m pip install aider-install && aider-install |
| Antigravity | curl -fsSL https://antigravity.google/cli/install.sh | bash |
| OpenCode | npm i -g opencode-ai |
| Cursor Agent | curl https://cursor.com/install -fsS | bash |
| Droid | curl -fsSL https://app.factory.ai/cli | sh |
| Copilot CLI | npm i -g @github/copilot |
| Grok CLI | curl -fsSL https://x.ai/cli/install.sh | bash |
| Amp | npm i -g @sourcegraph/amp |
| Qwen Code | npm i -g @qwen-code/qwen-code |
Run the command in a terminal yourself, then rescan. Custom agents you register get no install hint — their row reads “not found — install <command> and rescan” instead.
When a CLI is installed but the app cannot find it
This is the most common setup failure, and it is not specific to DeckSpace. An app launched from the Dock or Finder inherits a minimal PATH that is missing version-manager shims, so a claude that works in your terminal is invisible to the app.
DeckSpace works around it by asking your login shell for its real PATH once, with a 1.5-second cap so a hung shell profile cannot block the first pane, then merging in these directories under your home folder:
.local/bin, .grok/bin, .opencode/bin, .cargo/bin, .bun/bin, .npm-global/bin, .deno/bin, .volta/bin, .local/share/mise/shims, bin — plus /opt/homebrew/bin, /usr/local/bin, /usr/bin and /bin.
If your CLI lives somewhere else entirely, the scan will not see it. Register it as a custom agent with its absolute path, which is checked directly rather than searched for on PATH.
The same problem hits API keys exported from ~/.zshenv. DeckSpace reads your login shell’s environment once and passes through only the variables the app does not already have — PATH excluded, since it is handled separately. Anything the app itself sets wins, so this can supply a missing key but never quietly change one.
Two ways a pane starts an agent
Which one you get depends on how you launched, and it is worth knowing because the two behave differently.
| Typed into a shell | Run as the pane’s process | |
|---|---|---|
| What the pane runs | your login shell, with the agent command typed into it | the agent CLI itself, no shell in between |
| Used by | launching into an existing pane | launching into a new pane |
| Startup | waits for the shell to start first | starts the CLI directly |
| Your shell profile | sourced by the shell as usual | never sourced — the missing variables are injected instead |
Both paths arm the destructive-command guard on the pane. The shell path exports it before typing the command; the process path sets it in the spawn environment, because there is no shell to export into.
Registering a custom agent CLI
Any command on your PATH, or any absolute path, can be added to the registry. It then appears in every agent picker — palette, kanban, swarm, loop — alongside the built-ins, and is probed by the scan the same way.
Settings → AI providers → Custom agent CLIs. The form takes these fields.
| Field | Required | Rules |
|---|---|---|
| Key | yes | kebab-case, 2–24 characters of a–z, 0–9 or -. Auto-filled from the name until you edit it. |
| Name | no | Display name. Falls back to the command if left blank. |
| Command | yes | Bare name resolved on your login-shell PATH, or an absolute path. |
| Prompt flag | no | Blank means the prompt is passed positionally. |
| Fast flag | no | Blank means Fast Mode is a no-op for it. |
| Plan flag | no | Blank means Plan Mode is a no-op for it. |
| Walk-away flag | no | Blank means walk-away is a no-op for it. |
| Auto-edit flag | no | Blank means auto-accept-edits is a no-op for it. |
| Model flag | no | Blank means a pinned model is dropped for it. |
| Accent | no | Hex colour for its chips. Defaults to a neutral grey. |
A key that matches a built-in is rejected, and so is a duplicate of an existing custom key. Entries are stored as pretty-printed JSON in custom-agents.json in the app config directory, so you can read and version them outside the app.
The two positional-prompt exceptions are keyed to the built-in grok and opencode keys. A custom entry never gets that special handling. If you register a terminal-interface CLI and give it a -p-style prompt flag it does not support that way, the pane will print one reply and exit.
A malformed custom-agents.json is treated as empty. If you hand-edit the file and break the JSON, every custom agent disappears from the pickers with no error shown.
Removal is best-effort on disk. The entry leaves the list immediately, but if writing the file fails it comes back the next time the registry is read.
The plan, walk-away, auto-edit and model fields were added after the original custom-agent format, which carried only the prompt and fast flags. Files written before that parse unchanged, but any entry registered then has those four fields empty — and empty means the matching toggle silently does nothing. Re-open the entry and fill them in if you want those toggles to work.
Platform notes
| Platform | Login-shell PATH and environment probe |
|---|---|
| macOS | yes shell queried at startup |
| Linux | yes same path as macOS |
| Windows | not run the app’s own environment is used, with .exe, .cmd and .bat extensions checked when resolving a command |
The registry itself, the flag tables and the custom-agent form are identical on every platform. What differs is only how a command is found.