Open every project in its own terminal, launch your AI agent, and auto-tile all windows across your screens.
One command. Every tool. Every monitor.
Monitor 1 (4K @ 250%) Monitor 2 (4K @ 250%) Monitor 3 (1080p @ 175%)
+------------+------------+ +------------+------------+ +---------+---------+
| api | web | | infra | docs | | ops | ... |
| [claude] | [claude] | | [codex] | [vscode] | | [claude]| |
+------------+------------+ +------------+------------+ +---------+---------+
columns x rows per screen -- true physical pixels on every monitor
Available once
v1.0.0is published to PyPI. Until then, install from source.
pip install multideck # or: uv tool install multideck
multideckOn first run, multideck scans your Claude, Codex, and VS Code history, finds your recent projects, and generates a config. Run it again to launch everything.
| Tool | Type | Launch command | Session resume | Multi-window |
|---|---|---|---|---|
| Claude Code | CLI agent | claude --continue |
Yes | Yes |
| Codex CLI | CLI agent | codex |
Yes | Yes |
| Cursor Agent | CLI agent | cursor-agent |
-- | -- |
| Antigravity (agy) | CLI agent | agy |
-- | -- |
| VS Code | IDE | code |
-- | -- |
| Cursor IDE | IDE | cursor |
-- | -- |
| Custom | Any | your command | -- | -- |
Add any tool by mapping a name to a shell command in settings.tools. CLI agents open in a terminal; IDE tools open via their native CLI (code, cursor).
Enable Happy to monitor and control all your AI sessions from your phone or browser with end-to-end encryption:
"settings": { "happy": true }Requires npm install -g happy. Supported agents: Claude, Codex. Per-project override with "happy": true/false.
Enable psmux (native Windows terminal multiplexer) so each project runs in a named session you can attach to from anywhere — SSH from your phone, another PC, or a second terminal:
"settings": { "psmux": true }Requires psmux installed (choco install psmux or download from GitHub). When enabled, multideck creates a detached psmux session per project and opens Windows Terminal attached to it. From any SSH client: psmux attach -t project-name.
Send screenshots from your phone straight into a project's agent session:
"settings": { "psmux": true, "uploadServer": true, "uploadPort": 8033 }multideck serve (or uploadServer: true during launch) starts a small HTTP server; multideck mobile prints the phone URL + a QR code you can install as a home-screen app (the QR code needs the optional qr extra: pip install multideck[qr]). Pick a project on the phone, upload an image, and its path is pasted into that project's session. The Alt+V hotkey (Windows) does the same for whatever md: session is focused.
This works over Tailscale: the server binds only the loopback and your machine's Tailscale IP — never the LAN wildcard — and attach/mobile/termius shell out to the tailscale CLI to resolve hosts. Devices must be on your tailnet; there is deliberately no auth token, since the bind set is the access control. To bind something else (e.g. LAN-wide), use the escape hatch: multideck serve --host 0.0.0.0.
Run multideck with no arguments for the interactive menu:
_ _ _ _ _
_ __ _ _| | |_(_)__| |___ __| |__
| ' \ || | | _| / _` / -_) _| / /
|_|_|_\_,_|_|\__|_\__,_\___\__|_\_\
v1.0.0 auto-tile your AI workspace
----------------------------------------
1 Launch & tile new windows (default)
2 Re-tile all open windows
3 Launch a group AUTOMATIONS | INTERNAL | LEAD-GEN
e Edit config
q Quit
Or skip the menu with flags:
| Command | What it does |
|---|---|
multideck |
Interactive menu. |
multideck --go |
Launch + tile new windows, no menu. |
multideck --retile-all |
Re-tile every matching window. |
multideck -g <name> |
Launch only projects in a group. |
multideck --init |
Re-scan sessions and regenerate config. |
multideck --init --base-dir <folder> |
Generate config from a folder of git repos. |
multideck --edit |
Open config in your default editor. |
multideck docs |
Print full config reference (Markdown). |
multideck doctor [--json] |
Diagnose the environment: config, env vars, agent tools on PATH, terminal, monitors, writable dirs, Tailscale, upload port. Exit 1 on any failure. |
multideck sessions |
List active psmux sessions, pick one to attach. |
multideck sessions <name> |
Attach directly to a psmux session by name. |
multideck up [--json] [-g <group>] |
Host side: ensure a persistent psmux session per project. |
multideck attach <host> |
From another PC: bring host sessions up over SSH, tile locally, Alt+V uploads. |
multideck watch |
Live table of every agent session, most-urgent first; press a row number to focus that window. |
multideck attention [-d] [--stop] |
Attention daemon: badges window titles with agent state, flashes the taskbar on needs-input/error, optional toast/ntfy push (settings.attention). Badges/flash/toast are Windows-only; ntfy push is cross-platform — see Platform support. |
multideck status [--json] |
Session + daemon health (incl. an agents state list in --json). Exit codes: 0 healthy, 1 config error, 3 degraded. |
multideck down [--all] [--server] |
Stop sessions; --all/--server also stop the upload server (and listener). |
multideck serve [--host <addr>] |
Run the mobile upload server (see below). |
multideck mobile |
Phone URL + QR code for installing the uploader as a home-screen app. |
multideck termius |
Generate an SSH config entry that opens the session picker. |
multideck hotkey |
Run the Alt+V clipboard-upload listener standalone (Windows). |
multideck config <subcommand> |
Edit config from the CLI — 14 subcommands incl. migrate; see multideck config --help. |
Launching, tiling, and the mobile/notification plumbing run on all three OSes. A few power-user features are Windows-only because they lean on Win32 primitives with no cross-platform equivalent wired up yet. This table is the honest contract — every cell is derived from the capability probes in src/multideck/platform/, not from aspiration.
| Feature | Windows | macOS | Linux |
|---|---|---|---|
| Launch + auto-tile across monitors | Yes | Yes | Yes |
watch live fleet table |
Yes | Yes | Yes |
attention title badges + taskbar flash |
Yes | No | No |
Desktop toast (settings.attention.toast) |
Yes | No | No |
ntfy phone push (settings.attention.ntfy) |
Yes | Yes | Yes |
Persistent psmux sessions (up / sessions / attach) |
Yes | No | No |
| Global Alt+V clipboard-image hotkey | Yes | No | No |
Mobile upload server (serve / mobile) |
Yes | Yes | Yes |
Notes:
- Badges, flash, and toast are gated on
Platform.supports_attention_signals(), which returnsTrueonly inplatform/windows.py. On macOS/Linux the daemon printswindow badges/flash aren't supported on this OSand those renderers stay off. Toast additionally uses the Windows-onlywinotify([toast]extra). ntfy push is cross-platform — it is stdliburllibover HTTP — so phone notifications work on every OS. - Persistent psmux sessions and the Alt+V hotkey are gated on
supports_psmux()/supports_hotkey()(also Windows-only). Off Windows the psmux entry points raiseNotImplementedErrorand importinghotkeyraisesImportError. - The mobile upload server itself (serving the PWA over loopback + Tailscale and receiving images) runs everywhere; auto-pasting the uploaded path into a live agent session uses psmux, so that last hop is Windows-only. Likewise,
watch's table renders on every OS but its press-a-number-to-focus action uses the same Windows-only window primitives.
multideck watch, multideck attention, and multideck status --json do not poll your agents directly. They read per-session state records — working, needs-input, done, error, idle — that your coding agent writes through its lifecycle hooks: Claude Code hooks and Codex's notify hook. Until those hooks are wired, the state store stays empty and multideck watch shows an empty table.
The companion ai-agent-notifier package (same authors) installs those hooks for you across Claude Code, Codex, and Cursor:
npx ai-agent-notifier setupThe setup wizard detects your installed agents and wires the hooks; restart your agents to activate. After that, multideck watch and multideck attention -d light up as your agents change state.
Config is stored at a platform-standard location:
- Windows:
%APPDATA%\multideck\config.json - macOS:
~/Library/Application Support/multideck/config.json - Linux:
~/.config/multideck/config.json
Or place multideck.config.json in your working directory (it is gitignored — your personal config never gets committed).
Start from the committed sample, multideck.config.example.json — it is generated from the config factory and exercises every surface (groups, remote host/remotePath, ssh, the full settings block):
{
"version": 1,
"baseDir": "C:/Users/you/projects",
"layout": { "columns": 2, "rows": 1 },
"settings": { "defaultTool": "claude", "...": "see the example file / multideck docs" },
"projects": [
{ "path": "backend/api", "group": "backend", "tool": "claude", "color": "#3b82f6" },
{ "path": "gpu-worker", "group": "infra", "host": "gpu-box.example.com", "remotePath": "/home/dev/worker", "tool": "codex" }
]
}Configs are versioned ("version": 1). A config without a current version still loads but prints a warning until you run multideck config migrate — loading never rewrites your file; migrate is the only writer (it also persists auto-assigned project colors; those are derived deterministically from each project's title/path, so they stay the same every run even before you migrate).
| Field | Default | Description |
|---|---|---|
path |
(required) | Absolute, or relative to baseDir. |
group |
none | Tag for group launches (-g). |
tool |
defaultTool |
claude, codex, cursor-agent, agy, vscode, cursor, or any custom tool. |
color |
derived | Terminal tab color (#rrggbb); auto-derived from the project title/path when unset. |
title |
folder name | Window title for matching. |
enabled |
true |
Set false to skip without deleting. |
happy |
inherit | Override global Happy setting for this project. |
host |
none | SSH target for remote projects. |
remotePath |
path |
Remote directory when different from path. |
windows |
none | List of window objects {"name", "tool", "command"} with per-window tool/command overrides. Legacy int / ["name1", "name2"] forms still parse. |
Open the same project in multiple windows. windows is a list of window objects, each with optional per-window tool/command overrides:
{
"path": "api",
"windows": [
{ "name": "api" },
{ "name": "api-2" },
{ "name": "api-codex", "tool": "codex" }
]
}name sets the window title; tool/command override the project's defaults for that window only. Windows without an override each resume the Nth most recent Claude/Codex session.
The legacy "windows": 3 and "windows": ["api", "api-2"] forms still parse and are normalized to window objects by multideck config migrate.
{ "host": "deploy@server", "path": "/srv/api", "tool": "claude" }CLI agents run over SSH. VS Code/Cursor projects open via Remote-SSH.
"tools": {
"claude": "claude --continue",
"codex": "codex",
"cursor-agent": "cursor-agent",
"agy": "agy",
"aider": "aider --model sonnet",
"shell": "bash"
}pip install -e ".[dev]"
pytest tests/unit/ -q # fast, safe anywhere
pytest tests/e2e/ -m "e2e and not needs_ssh" # subprocess dry-runs; no SSH server needed
pytest tests/platform/ -v -m platform # real monitors/terminals — CI-grade env only
pip install build && pytest tests/dist/ -m dist # wheel -> pristine venv -> real installed entry point
python scripts/check.py # the quality gate: ruff + custom lint + ty + compileall + vulture + pytest w/ coverageA bare pytest collects all tiers, including tests that enumerate real monitors, launch real terminals, and expect an SSH server — run those only in an environment set up like CI (.github/workflows/ci.yml). scripts/check.py is the repo's commit gate; it must pass before every commit.
| Feature | Windows | macOS | Linux |
|---|---|---|---|
| Monitor detection | ctypes Win32 | Swift/AppKit | xrandr |
| Window management | EnumWindows/MoveWindow | AppleScript | xdotool/wmctrl |
| Terminal | Windows Terminal | kitty/iTerm/Terminal.app | kitty/alacritty/gnome-terminal |
| DPI awareness | Per-Monitor V2 | Native Retina | xrandr DPI |
git clone https://github.com/DevinoSolutions/multideck-ai-agents-manager.git
cd multideck-ai-agents-manager
pip install -e .Contributions are welcome. Please open an issue first to discuss what you'd like to change.
AGPL-3.0 -- Copyright (c) 2026 DevinoSolutions