MCPcopy Index your code
hub / github.com/asheshgoplani/agent-deck

github.com/asheshgoplani/agent-deck @v1.9.73

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.9.73 ↗ · + Follow
13,356 symbols 74,936 edges 1,343 files 7,362 documented · 55%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Agent Deck Logo

Agent Deck

Your AI agent command center

GitHub Stars Downloads Go Version License Platform Latest Release Discord

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

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

Fleet topology: phone → conductor → child sessions, with watchers on the side

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 f for quick fork, F to 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 with codex-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 m to open, Space to toggle, Tab to 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 s to 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.toml and materializes into .claude/skills
  • Type-to-jump is supported in the dialog (same pattern as MCP Manager)

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

  1. CLAUDE_CONFIG_DIR env var
  2. [conductors.<name>.claude] (when the session is a conductor session, i.e. Title starts with conductor-)
  3. [groups."<group>".claude] (PR #578)
  4. [profiles.<profile>.claude]
  5. [claude] (global)
  6. ~/.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

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.

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 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 19 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+1Alt+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 16 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-branch creates a session in a new worktree
  • agent-deck add . --worktree feature/b -b --location subdirectory places the worktree under .worktrees/ inside the repo
  • agent-deck worktree finish "My Session" merges the branch, removes the worktree, and deletes the session
  • agent-deck worktree cleanup finds 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.

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

Extension points exported contracts — how you extend this code

ToolOptions (Interface)
ToolOptions is the interface for tool-specific launch options Each AI tool (claude, codex, gemini, etc.) can have its ow [6 …
internal/session/tooloptions.go
WatcherAdapter (Interface)
WatcherAdapter is the interface that all event source adapters must implement. Adapters normalize raw events from extern [7 …
internal/watcher/adapter.go
ComposerGuardTarget (Interface)
ComposerGuardTarget is the minimal pane surface GuardComposerDraft needs to hold an automated send while an operator dra [6 …
internal/send/guard.go
MenuDataLoader (Interface)
MenuDataLoader provides menu snapshots for web APIs and push notifications. [8 implementers]
internal/web/server.go
KeySender (Interface)
KeySender pushes keystrokes to a tmux pane over a persistent connection, amortizing the per-call fork+exec cost of `tmux [5 …
internal/tmux/keysender.go
Parser (Interface)
Parser parses tool output into cost events. [4 implementers]
internal/costs/collector.go
Backend (Interface)
Backend abstracts version control operations scoped to a repository. [3 implementers]
internal/vcs/vcs.go
EventSink (Interface)
EventSink is the durable audit destination. The default is an append-only NDJSON file; the operational-KG ingestion path [3 …
internal/selfheal/event.go

Core symbols most depended-on inside this repo

Fatalf
called by 7121
internal/integration/poll.go
Errorf
called by 5207
internal/testutil/profilefixture/profilefixture.go
Now
called by 1414
internal/watcher/triage.go
Run
called by 844
cmd/agent-deck/main.go
String
called by 825
internal/web/server.go
Add
called by 706
internal/session/notifications.go
Error
called by 649
internal/session/mutators.go
Helper
called by 488
internal/integration/poll.go

Shape

Function 9,002
Method 3,322
Struct 821
Class 103
Interface 51
TypeAlias 44
Route 7
FuncType 6

Languages

Go87%
TypeScript10%
Python4%

Modules by API surface

internal/web/static/chart.umd.min.js953 symbols
internal/ui/home.go407 symbols
internal/session/instance.go260 symbols
internal/session/userconfig.go215 symbols
internal/tmux/tmux.go184 symbols
internal/ui/home_test.go142 symbols
internal/session/instance_test.go142 symbols
internal/ui/newdialog_test.go110 symbols
internal/session/conductor_test.go109 symbols
internal/session/conductor.go104 symbols
internal/tmux/tmux_test.go103 symbols
internal/ui/newdialog.go96 symbols

For agents

$ claude mcp add agent-deck \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact