Skip to main content

Launch each project's AI coding agent in its own terminal, auto-tiled across every monitor

Project description

multideck

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.

PyPI version PyPI downloads License: AGPL-3.0 Python 3.10+ Minimal Dependencies

Windows macOS Linux


      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

Quick Start

Available once v1.0.0 is published to PyPI. Until then, install from source.

pip install multideck          # or: uv tool install multideck
multideck

On 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.

Supported Tools

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).

Happy (mobile/web access)

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.

psmux (persistent sessions for SSH access)

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.

Mobile image upload (over Tailscale)

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.

Usage

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.

Platform support

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 returns True only in platform/windows.py. On macOS/Linux the daemon prints window badges/flash aren't supported on this OS and those renderers stay off. Toast additionally uses the Windows-only winotify ([toast] extra). ntfy push is cross-platform — it is stdlib urllib over 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 raise NotImplementedError and importing hotkey raises ImportError.
  • 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.

Where agent states come from

multideck watch, multideck attention, and multideck status --json do not poll your agents directly. They read per-session state recordsworking, 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 setup

The 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.

Configuration

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).

Project fields

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.

Multi-window sessions

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.

Remote projects

{ "host": "deploy@server", "path": "/srv/api", "tool": "claude" }

CLI agents run over SSH. VS Code/Cursor projects open via Remote-SSH.

Custom tools

"tools": {
  "claude": "claude --continue",
  "codex": "codex",
  "cursor-agent": "cursor-agent",
  "agy": "agy",
  "aider": "aider --model sonnet",
  "shell": "bash"
}

Testing

Job Live status Platforms What it verifies
Unit CI Windows / macOS / Linux
Python 3.10 -- 3.14
Config parsing, grid computation, title generation, session resume, discovery, grouping (15 matrix jobs)
Platform CI Windows / macOS / Linux Real monitor detection (ctypes/Swift/xrandr), real window find+move, real terminal launch, DPI scaling
E2E CI Windows / macOS / Linux Full CLI dry-run, config loading, group filtering, SSH project handling, vscode/cursor tool alias, multi-window
Packaging CI Windows / macOS / Linux Build wheel, install into a pristine no-extras venv, drive the real installed multideck entry point: version/help, dev-dep import sweep, virgin first-run, socket-real serve, optional-extra degradation, and a real window spawn (win32)

Run it yourself

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/ coverage

A 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.

Cross-platform support

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

Install from source

git clone https://github.com/DevinoSolutions/multideck-ai-agent.git
cd multideck-ai-agent
pip install -e .

Contributing

Contributions are welcome. Please open an issue first to discuss what you'd like to change.

License

AGPL-3.0 -- Copyright (c) 2026 DevinoSolutions

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multideck-1.0.0.tar.gz (351.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multideck-1.0.0-py3-none-any.whl (146.8 kB view details)

Uploaded Python 3

File details

Details for the file multideck-1.0.0.tar.gz.

File metadata

  • Download URL: multideck-1.0.0.tar.gz
  • Upload date:
  • Size: 351.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for multideck-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ab9637cc384ffae073522da25bb0922baafbf9b10fe2d35c4bb1e5e0d4f4c863
MD5 b80185f77ef2b68ed4d21ceb55faf052
BLAKE2b-256 22ec7a114c0c8b24d8f23acbd094dc9fd0da190f1984b85a04ed72906abfe75e

See more details on using hashes here.

Provenance

The following attestation bundles were made for multideck-1.0.0.tar.gz:

Publisher: release.yml on DevinoSolutions/multideck-ai-agents-manager

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file multideck-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: multideck-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 146.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for multideck-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e36992476609a2d8d42c71a734ab280742f36bb1eb34ce52906511704d201988
MD5 90cdfeba2825fd9adbe5cb91e4f6a6e8
BLAKE2b-256 6fa6e293aca39da47d1de0c0f7fb2c52cb4ebf2570ff6e4c1aa4b98d94fc1a67

See more details on using hashes here.

Provenance

The following attestation bundles were made for multideck-1.0.0-py3-none-any.whl:

Publisher: release.yml on DevinoSolutions/multideck-ai-agents-manager

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page