See what your AI agents are actually doing.
Run multiple Claude Code sessions. Watch every file change in real time. One orchestrator to coordinate them all.
The Problem Β· How It Works Β· Orchestrator Β· Getting Started Β· Architecture
You run Claude Code in a terminal. It edits files, runs commands, builds features. But you can't see what it's doing. You're staring at a terminal scrolling past, and the only way to know what changed is to git diff after it's done.
Now multiply that by three or four repos β a frontend, a backend, a shared library. You have multiple terminal windows open, agents running in each, and zero visibility into what code is actually being written across any of them.
Every other tool out there gives you a chat window. None of them show you the code changes as they happen, let you browse the file tree, or give you a diff view while the agent is still working.
That's what Commander solves.
graph LR
subgraph Commander["Claude Code Commander"]
direction TB
SB["Sidebar<br/>All your projects"]
TERM["Tabbed Terminals<br/>Claude + shell tabs"]
DIFF["Diff View<br/>Every change, live"]
TREE["File Explorer<br/>What changed, what's new"]
ENV["Env Variables<br/>Per-project secrets"]
EDIT["File Editor<br/>Edit & save in-app"]
end
YOU([You]) --> SB
SB --> TERM
SB --> DIFF
SB --> TREE
SB --> ENV
SB --> EDIT
style Commander fill:#0d1117,stroke:#30363d,color:#e6edf3
style YOU fill:#3fb950,stroke:#3fb950,color:#fff
Register any git repository from the sidebar. Add as many as you want β your frontend, backend, infra, libraries, monorepo packages. Each project gets its own independent workspace.
Click a project, hit Start Session, and a real Claude Code CLI session launches in that directory. This isn't a chat wrapper β it's a full PTY terminal with scrollback, ANSI colors, clickable links, and keyboard input. Talk to your agent, give it tasks, ask it questions. Everything you can do in a terminal, you can do here.
This is the core of Commander. While the agent works, you see:
- Live file tree β which files were added, modified, or deleted, updating in real time with status badges
- Diff view β unified or side-by-side diffs with syntax highlighting, refreshing as the agent writes code
- File editor β click any file to read and edit it with line numbers, dirty indicator, and Cmd+S to save
- One-click revert β undo changes per file or revert the entire codebase
You don't have to wait for the agent to finish. You don't have to run git diff. You see every change as it happens.
Click the Env button in the top bar to open a Vercel-style key-value editor. Set secrets, API keys, or config per project. Values are masked by default with an eye toggle.
- Stored in
~/.commander-central/envs/β never in the repo, nothing to accidentally commit - Automatically injected into Claude sessions and shell terminals at spawn time
.env*files also show up in the file tree so you can edit them directly if you prefer
Each project gets a tabbed terminal area. The Claude tab is always present, and you can spawn as many shell tabs as you need β run dev servers, builds, tests, linters, anything.
- Click + in the terminal tab bar to spawn a new shell
- Each shell runs in the project directory with your env vars injected
- Close a tab (x) to kill the process, or
exitto auto-remove it - All terminals stay mounted when switching tabs β no lost state
The sidebar shows every project with a live status indicator:
π’ Active β agent is generating output
π‘ Waiting β agent needs your input
π΅ Starting β session is booting up
βͺ Idle β ready for the next prompt
π΄ Error β session crashed
Switch between projects instantly. Each one keeps its own terminal history, diff state, and file tree. Toggle auto-accept per session to let agents run fully autonomously, or keep manual approval on.
Once you're running multiple sessions, you'll want one agent that can see everything. The orchestrator is a dedicated Claude Code session with MCP tools that give it control over every other session.
graph LR
You([You]) -->|talk to| Orch[Orchestrator Agent]
Orch -->|start/stop<br/>send commands<br/>read output| S1[Agent: Frontend]
Orch -->|start/stop<br/>send commands<br/>read output| S2[Agent: Backend]
Orch -->|start/stop<br/>send commands<br/>read output| S3[Agent: Infra]
Orch -->|read files<br/>view diffs| Any[Any Codebase]
style Orch fill:#58a6ff,stroke:#58a6ff,color:#fff
style You fill:#3fb950,stroke:#3fb950,color:#fff
Click the orchestrator icon at the top of the sidebar. It launches with --dangerously-skip-permissions so it can act without interruption.
"Start sessions in all repos and run their test suites"
"The backend agent is stuck β check its output and help it"
"Read the API types from the frontend repo and send them to the backend agent"
"Which repos have uncommitted changes? Commit them all with good messages"
| Tool | Description |
|---|---|
list_codebases |
List all registered repos with IDs, names, paths |
get_all_statuses |
Session status for every codebase at once |
get_session_output |
Read the last N lines of terminal output from any session |
send_to_session |
Send text input to any running agent |
start_session |
Spin up a Claude Code session in any repo |
stop_session |
Kill a running session |
get_diff |
Get the full git diff from any codebase |
read_file |
Read any file from any registered codebase |
git clone https://github.com/Dominien/claude-code-commander.git
cd claude-code-commander
npm install
npm run devPrerequisites
- Node.js 20+
- Claude Code CLI installed and in your PATH
- Git
graph TB
subgraph Electron["<b>Electron Main Process</b>"]
direction TB
CM["<b>CodebaseManager</b><br/>Lifecycle orchestration"]
CM --> SC1["SessionController<br/><i>Repo A</i>"]
CM --> SC2["SessionController<br/><i>Repo B</i>"]
CM --> SC3["SessionController<br/><i>Repo N...</i>"]
CM --> ORC["SessionController<br/><i>Orchestrator</i>"]
CM --> API["McpServer<br/><i>HTTP API on localhost</i>"]
SC1 --- PTY1["node-pty β claude CLI"]
SC1 --- GIT1["GitManager<br/>Diffs Β· File tree Β· Edit Β· Revert"]
SC1 --- FW1["FileWatcher<br/>Polling Β· No EMFILE"]
SC1 --- SH1["ShellManager<br/>Multiple shell PTYs"]
CM --- ENV["EnvStore<br/>Per-project env vars<br/><i>~/.commander-central/envs/</i>"]
SC2 --- PTY2["node-pty β claude CLI"]
SC3 --- PTY3["node-pty β claude CLI"]
ORC --- PTY4["node-pty β claude CLI<br/><i>with MCP tools</i>"]
end
subgraph MCP["<b>MCP Bridge (stdio β HTTP)</b>"]
BRG["mcp-bridge.cjs"]
end
PTY4 <-->|"stdin/stdout<br/>(MCP protocol)"| BRG
BRG <-->|"HTTP<br/>localhost"| API
subgraph UI["<b>Renderer Process</b>"]
direction TB
APP["React 19 Β· Zustand Β· Tailwind CSS 4"]
APP --- SB["Sidebar<br/>Codebase list Β· Status dots"]
APP --- CV["CodebaseView<br/>File tree Β· Diff Β· Terminal"]
APP --- OV["OrchestratorView<br/>Dashboard Β· Terminal"]
end
Electron <-->|"Electron IPC<br/>Preload bridge"| UI
style Electron fill:#0d1117,stroke:#30363d,color:#e6edf3
style UI fill:#0d1117,stroke:#30363d,color:#e6edf3
style MCP fill:#0d1117,stroke:#30363d,color:#e6edf3
Claude Code's MCP implementation only supports servers spawned via command/args (stdio transport). It doesn't support connecting to HTTP/SSE endpoints. So the orchestrator's MCP tools work through a bridge:
sequenceDiagram
participant CC as Orchestrator<br/>(Claude Code)
participant Bridge as mcp-bridge.cjs
participant API as McpServer<br/>(Electron main)
participant Session as Target Session
CC->>Bridge: tool call via stdio
Bridge->>API: HTTP POST /api/call
API->>Session: Execute (read output, send input, etc.)
Session-->>API: Result
API-->>Bridge: JSON response
Bridge-->>CC: tool result via stdio
The bridge script is generated at runtime with the correct port and NODE_PATH baked in.
| Runtime | Electron 33 Β· node-pty |
| Frontend | React 19 Β· TypeScript 5.6 Β· Tailwind CSS 4 Β· Zustand 5 |
| Terminal | xterm.js 5.5 (FitAddon, WebLinksAddon) |
| Git | simple-git Β· diff2html Β· highlight.js |
| MCP | @modelcontextprotocol/sdk (StdioServerTransport) |
| Storage | electron-store |
| Build | electron-vite 5 Β· electron-builder 25 |
src/
βββ main/ # Electron main process
β βββ CodebaseManager.ts # Codebase + orchestrator lifecycle
β βββ SessionController.ts # PTY session management per codebase
β βββ ProcessManager.ts # Spawns claude CLI via node-pty
β βββ GitManager.ts # Diffs, file trees, file editing, revert
β βββ FileWatcher.ts # Polling-based (avoids EMFILE on large repos)
β βββ EnvStore.ts # Per-project env var persistence (JSON)
β βββ ShellManager.ts # Multiple shell PTYs per codebase
β βββ ipc-handlers.ts # All IPC handler registrations
β βββ store.ts # Persistent codebase storage
β βββ mcp/
β βββ McpServer.ts # HTTP JSON API for tool calls
β βββ mcp-config.ts # Generates bridge script + .mcp.json
β
βββ renderer/ # React frontend
β βββ App.tsx # Root β routing between views
β βββ components/
β β βββ Sidebar.tsx # Codebase list + orchestrator button
β β βββ CodebaseView.tsx # Main workspace (explorer + diff + tabbed terminals)
β β βββ OrchestratorView.tsx # Orchestrator dashboard + terminal
β β βββ Terminal.tsx # xterm.js with PTY integration (Claude sessions)
β β βββ ShellTerminal.tsx # xterm.js wrapper for shell PTYs
β β βββ DiffView.tsx # Unified/split diff with syntax highlighting
β β βββ FileTree.tsx # Recursive git-aware file explorer
β β βββ FilePreview.tsx # File editor with line numbers + Cmd+S save
β β βββ EnvPanel.tsx # Vercel-style env var key-value editor
β β βββ StatusIndicator.tsx # Animated status dots
β β βββ AddCodebaseDialog.tsx
β β βββ EmptyState.tsx
β βββ hooks/
β β βββ useSession.ts # Session start/stop/state
β β βββ useDiff.ts # Git diff fetching
β β βββ useFileTree.ts # File tree fetching
β β βββ useIPC.ts # Real-time IPC event subscriptions
β βββ stores/appStore.ts # Zustand β all UI state
β βββ styles/globals.css # Dark theme + xterm + diff2html overrides
β
βββ shared/types.ts # TypeScript interfaces shared across processes
βββ preload/index.ts # Secure IPC bridge (context isolation)
npm run dev # Dev server with hot reload
npm run build # Production build
npm run package # DMG (macOS) / AppImage (Linux)
npm run rebuild # Rebuild node-pty for your platformPRs are welcome. The codebase is small enough to read in an afternoon.
If you're adding a new MCP tool for the orchestrator:
- Add the tool definition to
TOOLSarray insrc/main/mcp/McpServer.ts - Add the handler in the
handleToolCallswitch statement - That's it β the bridge script picks up tools dynamically