🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman
Terminal session manager for AI coding agents
Agent Deck gives you one terminal view for many agent sessions, so you can launch, search, fork, restart, and track them without juggling shells. It plugs into tools like Claude Code, Codex, and Gemini CLI, and adds session groups, worktrees, MCP attachment, skills, and a conductor that can supervise a fleet.
Builders who want one place to manage many agent sessions across several projects.
You can keep a fleet of coding agents organized, switch between them quickly, and see when each one needs attention.
What it does
Multi-agent session dashboard
Shows every session in one TUI, with status markers for running, waiting, idle, and error.
Session fork and resume
Lets you fork supported sessions, restart them, and send prompts to an existing session.
MCP manager
Attach and detach MCP servers per session or globally without editing config files by hand.
Skills manager
Attach Claude skills from a managed pool and write the project state into `.agent-deck/skills.toml` and `.claude/skills`.
Worktree support
Creates isolated git worktrees, runs optional setup and teardown scripts, and can clean up orphaned worktrees.
Conductor workflow
Sets up a supervising session with a bridge daemon and heartbeat so one agent can watch others and surface alerts.
Search and navigation
Fuzzy-search sessions, filter by status, and jump around the list with keyboard shortcuts.
Per-group Claude config
Supports group- and conductor-specific Claude config directories and environment files.
How to get it
- 1Works on: macOS, Linux, Windows (WSL)
curl -fsSL https://raw.githubusercontent.com/asheshgoplani/agent-deck/main/install.sh | bash
- 2Homebrew
brew install asheshgoplani/tap/agent-deck
- 3Go
go install github.com/asheshgoplani/agent-deck/cmd/agent-deck@latest
- 4From Source
git clone https://github.com/asheshgoplani/agent-deck.git && cd agent-deck && make install
- 5Run
agent-deck uninstall # Interactive uninstall agent-deck uninstall --keep-data # Remove binary only, keep sessions
- 6Five minutes from zero to a Telegram bot that watches every Claude session you have…
# 1. Create a Telegram bot via @BotFather, grab the token + your user ID from @userinfobot. # 2. Run the wizard — it sets up the conductor, bridge daemon, and heartbeat in one shot. agent-deck conductor setup work --description "Work fleet" agent-deck session start conductor-work # 3. Message your bot: /status
README
Agent Deck
Your AI agent command center
Install . Quick Start . Features . Conductor . Docs . Discord . FAQ
Agent Deck is mission control for your AI coding agents. Running Claude Code on ten projects, OpenCode on five more, another agent somewhere in the background? One terminal shows every session — running, waiting, or done — and one keystroke switches between them. Groups, search, forking, git worktrees, cost tracking, and a phone-controlled conductor keep a whole fleet manageable.
https://github.com/user-attachments/assets/e4f55917-435c-45ba-92cc-89737d0d1401
Maintainers & contributors wanted
agent-deck is actively maintained by Ashesh, and it welcomes both contributors and co-maintainers. PRs here don't sit: every incoming PR is validated (applied, built, tested) within about a day, and good ones merge in the next release batch. Recent releases have shipped dozens of community fixes.
Beyond one-off PRs, we're looking for 1-2 regular co-maintainers: people who want to own an area (a tool integration, the TUI, the web view, CI) and help triage and review. The validation pipeline does the heavy lifting; maintainers steer.
To get started:
- Read CONTRIBUTING.md for how the review pipeline works.
- Start at the pinned issue: Looking for contributors — start here (#1650).
- The agent-deck-contributor skill walks an AI agent (or you) through building, testing, and shaping a clean PR.
If you've had a couple of PRs land here and want to help steer, say so on #1650 or open an issue titled "maintainer: your area". We'd love the help.
Installation
Works on: macOS, Linux, Windows (WSL)
curl -fsSL https://raw.githubusercontent.com/asheshgoplani/agent-deck/main/install.sh | bash
Then run: agent-deck
Other install methods
Homebrew
brew install asheshgoplani/tap/agent-deck
Go
go install github.com/asheshgoplani/agent-deck/cmd/agent-deck@latest
From Source
git clone https://github.com/asheshgoplani/agent-deck.git && cd agent-deck && make install
Uninstalling
agent-deck uninstall # Interactive uninstall
agent-deck uninstall --keep-data # Remove binary only, keep sessions
See Troubleshooting for full details.
Quick Start
agent-deck # Launch TUI
agent-deck add . -c claude # Add current dir with Claude
agent-deck session fork my-proj # Fork a supported session
agent-deck session send my-proj --message-file task.md # Send a multiline prompt
agent-deck session remove my-proj # Remove stopped/errored session from registry (transcripts preserved)
agent-deck mcp attach my-proj exa # Attach MCP to session
agent-deck skill attach my-proj docs --source pool --restart # Attach skill + restart
agent-deck web # Start web UI on http://127.0.0.1:8420
⚠️ Changed in v1.9.55: in the new-session dialog (
n), Enter advances to the next field on the Name and Branch inputs instead of submitting — typing a name and hitting Enter no longer creates a session with all defaults. Ctrl+S creates the session from any field. The dialog also remembers your last-used tool. Restore the old behavior with[ui].new_session_enter_advances = false.
Key Shortcuts
| Key | Action |
|---|---|
Enter | Attach to session |
Ctrl+Q | Detach from session |
n | New session |
f / F | Fork (quick / dialog) |
A / Shift+U | Archive / unarchive session |
^ | Show archived sessions |
m | MCP Manager |
s | Skills Manager |
$ | Cost Dashboard |
M | Move session to group |
S | Settings |
/ / G | Search / Global search |
r / R | Rename / Restart session |
d | Delete |
b | Re-run worktree setup script |
E | Container shell (sandboxed sessions) |
? | Full help |
See TUI Reference for all shortcuts and CLI Reference for all commands.
Quickstart: orchestrate a fleet of AI agents
Five minutes from zero to a Telegram bot that watches every Claude session you have running.
# 1. Create a Telegram bot via @BotFather, grab the token + your user ID from @userinfobot.
# 2. Run the wizard — it sets up the conductor, bridge daemon, and heartbeat in one shot.
agent-deck conductor setup work --description "Work fleet"
agent-deck session start conductor-work
# 3. Message your bot: /status
That's it. From now on every other agent-deck session you run is supervised by a single
"conductor" session that answers routine questions, escalates the interesting ones to your
phone, and never lets a waiting worker rot.
Two short guides to read next:
docs/conductor/— two-minute local quickstart, architecture, state files, lifecycle, remote channel setup (Telegram/Slack/Discord), gotchas.docs/WATCHER-SETUP.md— add "doorbells" so the outside world (GitHub events, gmail, ntfy pushes, meetings) can wake the conductor up.
Features
Fork Sessions
Try different approaches without losing context. Fork Claude, OpenCode, Pi, and Codex sessions instantly. Each fork inherits the parent conversation history through the tool's native fork support.
- Press
ffor quick fork,Fto customize name/group - Fork your forks to explore as many branches as you need
- Codex forking requires a codex CLI with
codex fork <session-id>support (verified withcodex-cli 0.137.0)
MCP Manager
Attach MCP servers without touching config files. Need web search? Browser automation? Toggle them on per project or globally. Agent Deck handles the restart automatically.
- Press
mto open,Spaceto toggle,Tabto cycle scope (LOCAL/GLOBAL), type to jump - Define your MCPs once in
$XDG_CONFIG_HOME/agent-deck/config.toml(default~/.config/agent-deck/config.toml), then toggle per session — see Configuration Reference
Skills Manager
Attach/detach Claude skills per project with a managed pool workflow.
- Press
sto open Skills Manager for a Claude session - Available list is pool-only (
$XDG_CONFIG_HOME/agent-deck/skills/pool, default~/.config/agent-deck/skills/pool) to keep attach/detach deterministic - Apply writes project state to
.agent-deck/skills.tomland materializes into.claude/skills - Type-to-jump is supported in the dialog (same pattern as MCP Manager)
Declarative groups
Declare groups in config.toml so they exist on startup. Set create = true to ensure a group exists, and default_path to set the working directory for new sessions in it:
[groups."staging"]
create = true # ensure the group exists
[groups."projects/devops"]
create = true
default_path = "~/repos/devops" # working directory for new sessions
On startup each group with create = true is created if missing (along with any parent groups). default_path is written to the state DB for any group that exists — including groups created from your sessions — so create = true is optional when the group is already there. Reconciliation is additive: removing a group from config.toml leaves the group and its sessions in place, and omitting default_path keeps any value already set. Clear a default with agent-deck group update <name> --clear-default-path.
Per-group Claude config
Agent Deck supports per-group CLAUDE_CONFIG_DIR and env_file overrides. Useful when a single profile hosts groups that should authenticate against different Claude accounts — for example, a personal profile hosting a conductor group pinned to ~/.claude-team while other groups stay on ~/.claude.
Override any group by adding a [groups."<name>".claude] table to $XDG_CONFIG_HOME/agent-deck/config.toml (default ~/.config/agent-deck/config.toml):
[groups."conductor".claude]
config_dir = "~/.claude-team"
env_file = "~/git/work/.envrc"
Lookup priority: env > group > profile > global > default. The env_file is sourced into the tmux pane before claude (or the custom command) execs, so any exports it contains become part of the session environment.
Human-watchable verification: bash scripts/verify-per-group-claude-config.sh. The harness creates two throwaway groups, launches one normal and one custom-command session, and prints a pass/fail table.
Per-conductor Claude config (v1.5.4)
Conductors are first-class agent-deck entities (see agent-deck conductor setup). Each conductor can carry its own Claude config_dir and env_file via a top-level [conductors.<name>.claude] block:
[conductors.gsd-v154.claude]
config_dir = "~/.claude-team"
env_file = "~/git/work/.envrc"
The conductor name is the string you passed to agent-deck conductor setup <name> — it's the same name that appears in session titles (conductor-<name>).
Precedence chain (most-specific → least-specific):
CLAUDE_CONFIG_DIRenv var[conductors.<name>.claude](when the session is a conductor session, i.e. Title starts withconductor-)[groups."<group>".claude](PR #578)[profiles.<profile>.claude][claude](global)~/.claude(default)
This means a single [conductors.gsd-v154.claude] line replaces the need to duplicate the config into [groups."conductor".claude] — the conductor block scopes to exactly that conductor, not to every conductor that shares the conductor group.
Backward compat: sessions in the conductor group with NO matching [conductors.<name>.claude] block continue to resolve via [groups."conductor".claude] as they did in v1.5.4 Phase 1–3.
Closes issue #602.
Switch a session's account on the fly
For a new one-shot session, use agent-deck launch . -c claude --account <name>.
Run agent-deck accounts (or agent-deck accounts --json) to list named slots
configured under [profiles.<name>.claude].config_dir.
agent-deck session switch-account <session> <account> moves an existing session to another Claude account — conversation included. The session stops, its conversation file is migrated into the target account's config dir (copy-only, with a destination backup and size verification), the account is set, and the session restarts with --resume. session set <session> account <name> auto-migrates too.
The TUI exposes the same two moments. The New Session dialog's Claude options
carry an Account row (←/→ or Space to cycle, inherit = today's
conductor/group/env chain), so a session can be created straight onto the right
login. The Edit Session dialog (e) carries a Claude account row for a
session that already exists; committing it runs the same
migrate-and-resume flow as session switch-account, and the session card's
[account:"…"] badge follows. Both rows are hidden when no
[profiles.<name>.claude].config_dir blocks are configured.
Session naming
Titles and groups answer different questions — "what is this, at a glance?" versus "why do these sessions belong together?" — and each has its own controls.
Stable titles
By default, agent-deck syncs a session's displayed title from the tool's own session name (Claude's /rename, claude --name, etc.), which is useful for watching a list of live agents but means a title you set can later be overwritten. Pick the control that matches how stable you need the title to be:
| You want | Do this |
|---|---|
| This one session keeps the title I gave it | --title-lock (alias --no-title-sync) on agent-deck add / agent-deck launch, or agent-deck session set-title-lock <id> on at runtime |
| No session in this installation ever gets renamed by its agent | sync_title = false in config.toml |
| Claude should receive the exact deck title at startup | supported Claude launch/restart/resume commands get --name; push_title = false opts out. A deck rename takes effect on the next start, not immediately. |
| A throwaway session where the live task description matters more than a fixed name | agent-deck add --quick (-Q short flag) — the list shows the session's current Claude task in place of the generated handle |
An explicit -t/--title locks the title automatically, the same as passing --title-lock — there's no separate opt-in needed. There's also no create-time opt-out: if you want a session with an explicit title to still pick up the agent's renames, unlock it afterward with agent-deck session set-title-lock <id> off. A locked title is never silently overwritten by the sync path — it only changes via an explicit rename or session set-title-lock <id> off.
Groups vs. parent linkage
Groups carry real policy — max_concurrent (serial vs. bounded parallelism), default_path, and per-group Claude account/config (see Declarative groups and Per-group Claude config above). Treat that policy as the test for whether a new group is warranted:
- Don't encode dispatch relationships in a group name. A conductor fanning out workers doesn't need
work,work-infra,work-hygienesiblings to say "these came from the same orchestrator" — that's what parent linkage is for. Launch with--parent <id>(or letagent-deck launchauto-parent), and read the fleet back withagent-deck session children. - Create a new group when something policy-shaped differs from the parent group — a different concurrency cap, working directory, or Claude account. If nothing enforced differs, the thing you have is a topic, not a group; carry it in the title and parent linkage instead.
- Don't rely on titles or group names as machine keys. Both are user-editable; a script or agent matching on either is relying on something that can change under it.
There's no automated warning or enforcement for group sprawl yet — this is a documented convention, not a gate. See docs/design/2026-07-26-session-identity-and-group-purpose.md for the fuller design writeup (task-identity field, group --purpose, advisory sprawl warning) if you hit a concrete gap this section doesn't cover.
MCP Socket Pool
Running many sessions? Socket pooling shares MCP processes across all sessions via Unix sockets, reducing MCP memory usage by 85-90%. Connections auto-recover from MCP crashes in ~3 seconds via a reconnecting proxy. Enable with pool_all = true in config.toml.
Search
Press / to fuzzy-search across all sessions. Filter by status with ! (running), @ (waiting), # (idle), & (error). Press $ for the Cost Dashboard and G for global search across all Claude conversations.
Keyboard navigation (v1.7.60)
Two tiers of keybindings move the cursor around the session list. The global tier is unchanged from earlier versions; the Alt+ tier (added in v1.7.60) restricts movement to the current group only. Press ? in the TUI to see the full table in-app.
| Scope | Keys | What it does |
|---|---|---|
| Global (flat list) | j / k or ↓ / ↑ | Move cursor down / up through every item |
| Global | gg | Jump to top of list |
| Global | G | Open global search across all Claude conversations |
| Global | 1–9 | Jump to Nth root group header |
| Global | / | Open fuzzy search across all sessions |
| Group (current group only) | Alt+j / Alt+k | Next / previous session in current group (skips group boundaries) |
| Group | Alt+1–Alt+9 | Jump to Nth session within the current group |
| Group | Alt+g / Alt+G | First / last session in current group |
| Group | Alt+/ | Open fuzzy search filtered to the current group's sessions |
"Current group" is derived from the cursor position: on a session it's that session's group; on a group header it's that group; on a window it's the parent session's group. On a group boundary Alt+j / Alt+k no-op rather than spilling into the next group.
Status Detection
Smart polling detects what every agent is doing right now:
| Status | Symbol | What It Means |
|---|---|---|
| Running | ● green | Agent is actively working |
| Waiting | ◐ yellow | Needs your input |
| Idle | ○ gray | Ready for commands |
| Error | ✕ red | Something went wrong |
Notification Bar
Waiting sessions appear right in your tmux status bar. Press Ctrl+b, release, then press 1–6 to jump directly to them.
⚡ [1] frontend [2] api [3] backend
Git Worktrees
Multiple agents can work on the same repo without conflicts. Each worktree is an isolated working directory with its own branch.
agent-deck add . -c claude --worktree feature/a --new-branchcreates a session in a new worktreeagent-deck add . --worktree feature/b -b --location subdirectoryplaces the worktree under.worktrees/inside the repoagent-deck worktree finish "My Session"merges the branch, removes the worktree, and deletes the sessionagent-deck worktree cleanupfinds and removes orphaned worktrees
Configure the default worktree location in $XDG_CONFIG_HOME/agent-deck/config.toml (default ~/.config/agent-deck/config.toml):
[worktree]
default_location = "subdirectory" # "sibling" (default), "subdirectory", or a custom path
sibling creates worktrees next to the repo (repo-branch). subdirectory creates them inside it (repo/.worktrees/branch). A custom path like ~/worktrees or /tmp/worktrees creates repo-namespaced worktrees at <path>/<repo_name>/<branch>. The --location flag overrides the config per session.
Sparse Checkout (large monorepos)
If the session you create the worktree from uses sparse checkout, a new worktree normally checks out the whole repository first — minutes of I/O on a monorepo with hundreds of thousands of files. Opt into inheriting the sparse configuration instead:
[worktree]
sparse_checkout = "inherit" # "off" (default) keeps git's normal checkout
With inherit, agent-deck reads the sparse mode (cone / non-cone, sparse index) and patterns from the worktree you invoked from, creates the new worktree with --no-checkout, and materializes it directly with those patterns — the excluded tree is never written. .worktreeinclude and .agent-deck/worktree-setup.sh still run afterwards, so the setup script sees the same sparse paths the source session has.
A non-sparse source, or off/unset, keeps today's behavior exactly. Inheritance replays the patterns through git sparse-checkout set and pins the sparse-index setting explicitly, so it needs git 2.32 or newer; the default (off) has no version requirement.
Copying Gitignored Files (.worktreeinclude)
Gitignored files (.env, .mcp.json, etc.) aren't copied into new worktrees by default.
To declare which gitignored files should be copied automatically, create a .worktreeinclude file in your repo root:
# .worktreeinclude — gitignore-syntax patterns
.env
.env.local
.mcp.json
secrets/
Only files that are both pattern-matched AND gitignored get copied — tracked files are never duplicated. Directories are copied recursively and merged into existing destinations. Existing files in the worktree are not overwritten.
This works for both single-repo and multi-repo worktree sessions. Matches Claude Code Desktop semantics.
Worktree Setup Script
For imperative setup tasks (installing dependencies, running migrations, etc.), create a script at .agent-deck/worktree-setup.sh.
Agent-deck runs it automatically after creating a worktree and processing .worktreeinclude.
#!/bin/sh
npm install
The script receives two environment variables:
AGENT_DECK_REPO_ROOT— path to the main repositoryAGENT_DECK_WORKTREE_PATH— path to the new worktree
The script runs via sh -e with a 60-second timeout. If it fails, the worktree is still created — you'll see a warning but the session proceeds normally.
Worktree Destruction Script
For imperative teardown tasks (stopping containers, removing volumes, releasing ports, etc.), create a script at .agent-deck/worktree-destruction.sh.
Agent-deck runs it automatically just before removing a worktree, while the worktree still exists.
#!/bin/sh
docker compose -p "$(basename "$AGENT_DECK_WORKTREE_PATH")" down
It receives the same environment variables as the setup script (AGENT_DECK_REPO_ROOT, AGENT_DECK_WORKTREE_PATH) and runs with the same sh -e dispatch and 60-second timeout. If it fails, removal proceeds anyway — you'll see a warning. It does not run for sessions that reuse the main working tree (nothing is removed there).
Bare repositories and worktrees
Agent-deck supports two flavors of the bare-repo layout where every worktree is a peer (no "main" checkout). The two are distinguished by convention — the basename of the bare git dir.
Nested .bare/ layout
The bare git metadata sits inside a normal-looking project dir at .bare/:
project/
├── .bare/ # bare git repo (holds refs, objects, HEAD)
├── .agent-deck/
│ └── worktree-setup.sh # shared setup script (optional)
├── worktree-a/ # linked worktree on branch-a
│ └── .git # file: gitdir: ../.bare/worktrees/worktree-a
└── worktree-b/ # linked worktree on branch-b
└── .git
True-bare-at-root layout
The result of a plain git clone --bare repo.git: the directory itself is the bare repo and linked worktrees live as direct children alongside its internal files:
project.git/ # this dir IS the bare repo
├── HEAD, config, objects/, refs/, packed-refs, worktrees/, ...
├── .agen
Files in the repo
- .claude
- .claude-plugin
- .flox
- .github
- assets
- cmd
- conductor
- demos
- docs
- documentation
- internal
- sandbox
- scripts
- site
- skills
- tests
- tools
- .coderabbit.yaml
- .gitignore
- .golangci.yml
- .goreleaser.yml
- .lighthouserc.json
- CHANGELOG.md
- CODEOWNERS
- CONTRIBUTING.md
- go.mod
- go.sum
- install.sh
- lefthook.yml
- LICENSE
- llms-full.txt
- llms.txt
- Makefile
- PHASE1-PICKS.md
- README.md
- RESULTS.md
- SECURITY.md
- TELEMETRY.md
- uninstall.sh
Discussion (0)
Ask about usage, or say what you built with itSign in to join the discussion.
No comments yet. Be the first to say what this is good for.
More tools
The best-benchmarked open-source AI memory system. And it's free.
Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io
Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors
Compress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.