maestro
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@maestro Orchestrate this with Maestro: split into workers, review at end, close sessions."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Maestro
Run a dozen Claude Code sessions at once, and let one of them conduct the rest.
Each agent is a full Claude Code process in a terminal of its own — not a subagent, not an API call. Maestro launches them, reads their screens to know what they are doing, carries messages between them, and draws the whole fleet on a live panel.
Real recording: eight agents auditing this repository. Each wire lights up when a message crosses it, the mark pulses as a new agent joins, and the ticker carries what they just reported.
What it does
Claude Code can spawn subagents, but a subagent shares your context window and dies with your turn. Maestro runs real sessions instead: separate processes, separate context, separate conversation, all alive at the same time. You keep working in your editor while eight of them build eight parts of your project.
The orchestrator can be Claude itself. Point Claude Code at the maestro MCP server and it can launch workers, hand them briefs, poll their status, read their answers, answer their questions and close them — from the session you are already talking to. Or drive it by hand with maestro status and the CLI.
Knowing what an agent is doing is the hard part, and Maestro does it the way a person would: it reads the rendered terminal. A spinner means working, an option list means it is waiting for an answer, a finished response means the turn is done. No log parsing, no hooks, no cooperation needed from the agent.
Related MCP server: Claude Team MCP Server
Features
Full sessions, not subagents — one Claude Code process per worker, in its own terminal, with its own context and its own conversation
Agents that delegate — every session gets an MCP bridge:
assigna worker without waiting,handoffand block for the answer,send_messageto reply to whoever called youUnstick a worker without touching the keyboard —
answer_promptanswers the question it is blocked on,interruptstops a turn that is going in circles,restart_terminalgives it a fresh Claude with the same id, directory and queueIsolated git worktrees —
use_worktreeputs a worker on its own branch in its own checkout, so ten agents on one repository never trample each other; merge with plain git when they are done, and nothing uncommitted is ever thrown awayLive panel — the fleet as a ring of agents around the conductor, wires that light up when a message crosses, a ticker of what just happened, and the state of every agent in its glyph. Installs as a desktop app (PWA); works offline
One project at a time — running two projects at once no longer piles every agent onto a single ring. Each working directory gets the field to itself; drag the field sideways like a slider (or scroll sideways, or press the arrow keys) and the next project's page slides in. The projects you are not watching wait at the edges as breathing arrowheads, one each, warming to orange when a worker there needs an answer and to red when one has failed
Demo mode (
?demo), three projects: drag to the next one and back, then the two hovers.It tells you when it needs you — system notifications when an agent asks a question, dies, or freezes for ten minutes with nothing changing on screen
Progress you can trust — agents report their own percentage (
report_progress); hover a worker to read it, hover the mark for the fleet's mean. No report, no invented numberSurvives a restart — on Linux and macOS the server re-adopts the tmux sessions that are still alive; everywhere it keeps a note of worktrees whose agent is gone so their work can still be merged
Agents that can reach further —
maestro mcp importshares the MCP servers from your own Claude Code with every agent, so a worker can drive a browser or read an issue instead of only editing files. They run with--strict-mcp-config, so they get exactly what you share and nothing elseStays out of your way — agents run below normal CPU priority, so a fleet at full tilt never takes your editor with it; starts are staggered; the fleet lives on a tmux server of its own, out of reach of a stray
tmux kill-serverSmall enough to read — under 4,000 lines of Python, two dependencies (four on Windows), no database, no web framework
Installation / Usage
Windows — one click
Download MaestroSetup.exe and run it. Nothing to type, no administrator rights, no restart, no WSL: Maestro runs natively on Windows. The installer sets up what is missing and skips what you already have:
Git for Windows (per user, checksum-verified) — Claude Code needs its Bash.
uv, which brings its own Python.
Claude Code, from Anthropic's own installer.
Maestro, with its profiles, the skill and the MCP server, so Claude Code in VS Code or the terminal can use it straight away.
Your Claude account — a window opens and your browser signs you in.
The panel opens in a window of its own; the Start menu entry Maestro reopens it.
The setup file itself is about 2 MB. On a machine with nothing installed it downloads about 200 MB in total (Git, Python and Claude Code); on one that already has them, a few MB.
The installer is not code-signed yet, so Windows may show "Windows protected your PC": click More info → Run anyway. Uninstall it from Settings → Apps like anything else; Git, uv and Claude Code stay, since other tools may use them.
macOS and Linux — one line
curl -fsSL https://raw.githubusercontent.com/daniel-madrid-07/Maestro/main/install.sh | bashInstalls tmux (through your package manager or Homebrew), uv, Claude Code and Maestro, signs you in to Claude if needed, and starts the panel. Run it again at any time: it only does what is missing.
By hand
uv tool install git+https://github.com/daniel-madrid-07/Maestro
maestro init # config, profiles, the skill, and the MCP server in Claude Code
maestro doctor # checks the terminals, claude, sign-in, the port and the registration
maestro up # starts the server and opens the panelThe same four lines work in PowerShell on Windows.
Using it
In any project, tell Claude Code what you want built:
Orchestrate this with Maestro: split it into as many workers as it genuinely divides into, review at the end, and close the sessions when you are done.
Claude launches the fleet, and you watch it on http://127.0.0.1:9889.
Commands
| start the server, open the panel ( |
| every session and terminal, with status, progress and branch ( |
| what is missing and how to fix it |
| open the panel (on Windows, in a window of its own) |
| stop the server; with tmux the sessions stay up, on Windows they end with it |
| set up |
| the MCP servers every agent gets, taken from your own Claude Code if you like |
Requirements
Python | 3.11 or newer |
Claude Code | installed and signed in ( |
OS | Windows 10 1809 or newer, macOS, or Linux |
Terminals | Windows: nothing to install (each agent gets a ConPTY, Windows' own pseudo-console). macOS and Linux: tmux 3.0 or newer |
Profiles
An agent profile is a Markdown file with YAML front matter: model, effort, MCP servers and the system prompt appended to Claude's own. Three ship with Maestro — worker (delegates lookups to a cheap scout subagent), reviewer, and code_supervisor (runs its own workers). Copies land in ~/.maestro/profiles/, and a file you edit there wins over the packaged one.
Architecture
maestro-server— the HTTP API. Owns the terminals (tmux sessions, or ConPTYs on Windows), starts Claude in each one, reads every screen once a second to classify its state, delivers queued messages when an agent is free, streams events over SSE, and serves the panel.maestro-ops— the MCP server the outside orchestrator (Claude Code in your editor) talks to, registered asmaestro:fleet_status(everything at once, plus who needs answering),wait_for(blocks until a worker finishes, asks or dies, instead of polling),launch_sessions(a whole fleet in one parallel call),launch_session,broadcast_message,get_usage,send_session_message,read_session_output,get_terminal_status,get_terminal_output,answer_prompt,interrupt,restart_terminal,list_sessions,get_session_info,list_profiles,get_profile_details,list_worktrees,remove_worktree,shutdown_session.maestro-agent— the MCP server every launched session gets, so agents can build their own sub-fleets:assign,handoff,send_message,report_progress,list_terminals,get_terminal_status,get_terminal_output,answer_prompt,interrupt,restart_terminal,delete_terminal.The panel — a single HTML file served by the server: canvas for the field and the wires, DOM for the labels, SSE for the traffic.
State lives in ~/.maestro/ (config, profiles, logs, worktrees, state.json). Nothing leaves your machine except Claude Code's own traffic.
The API binds loopback and has no authentication, because it is a local tool. It sends no CORS headers and refuses any request carrying a foreign Origin, so a page you happen to have open in your browser cannot reach it. Do not expose the port.
Tech stack
Python 3.11 (standard library — http.server, subprocess, threading), tmux on Linux and macOS, pywinpty and pyte on Windows, Claude Code, the MCP Python SDK, PyYAML, and plain HTML/Canvas for the panel.
License
MIT — see LICENSE. The terminal-state heuristics are adapted from awslabs/cli-agent-orchestrator (Apache-2.0); see NOTICE.
Available Tools
20 toolsanswer_promptA
Answer the question a terminal is blocked on. Only valid while its status is waiting_user_answer.
answer is a key (Enter, Escape, Up, Down, Tab, Space), a single digit
(in an option dialog it selects and submits that option: "2" = the
second one), or one line of text, typed and followed by Enter — only where
a text field has focus (an option list treats letters as hotkeys). Escape
cancels the question and ends the turn with no answer.
Inputs: answer (required), terminal_id (required). Returns: object
broadcast_messageA
Queue one message for many terminals at once (the whole fleet when none is named).
For the things you say to everyone: a change of plan, "commit what you have and report", a constraint you forgot. Each terminal receives it when it is next idle, exactly as send_session_message does.
Inputs: message (required), terminal_ids, session_names. Returns: object
fleet_statusA
The whole fleet in one call: every session, every terminal, and who needs you.
Prefer this over list_sessions plus a get_session_info per session: it is
one call and one block of context instead of one per session. Each terminal
carries status, progress, stuck, model, profile, working directory,
worktree and pending_messages. needs_attention is the part to act on --
terminals that are waiting on an answer, stuck, or failed. totals counts
them by status.
Inputs: no named parameters. Returns: object
get_profile_detailsB
Return a profile's full system prompt and settings.
Inputs: profile_name (required). Returns: object
get_session_infoC
A session and every terminal in it, with live statuses (oldest terminal first).
Inputs: session_name (required). Returns: object
get_terminal_outputB
Read a terminal's output. last = Claude's final answer; full = the rendered scrollback.
Inputs: terminal_id (required), mode. Returns: object
get_terminal_statusB
Live status of one terminal: idle, processing, completed, waiting_user_answer, error.
Inputs: terminal_id (required). Returns: object
get_usageA
How much of the Claude subscription is left: the 5-hour and weekly windows.
Worth a look before opening a large fleet, and when deciding whether to run
the stronger model everywhere. Percentages are utilisation, so 100 means
spent; resets_at says when the window rolls over. Unavailable (no local
credentials, or the endpoint refused) comes back as ok: false rather than a
made-up number.
Inputs: no named parameters. Returns: object
interruptA
Stop a terminal's current turn (Escape), e.g. when a worker is going in circles.
Only while its status is processing or waiting_user_answer (an idle prompt has nothing to interrupt and is refused). Returns the status observed ~2 s later (normally idle or completed); queued messages are then delivered as usual.
Inputs: terminal_id (required). Returns: object
launch_sessionA
Start a new session: one full Claude Code process in its own tmux window.
Blocks until Claude shows its input box (up to ~90 s) so a failed start is
reported here rather than discovered later. working_directory must be a
Linux path (/mnt/c/... for a Windows folder). model overrides the
profile's model (opus / sonnet). initial_message is delivered as the
first task once the session is ready. provider is accepted for
compatibility; only claude_code exists.
use_worktree runs the session in its own git worktree (under
MAESTRO_HOME) on a new branch mx/<terminal_id> made from the repo's
HEAD, so parallel workers on one repository never trample each other; the
result's worktree gives its path and branch. The worker is told to
commit there. Merge it yourself with plain git afterwards
(git -C <repo> merge mx/<terminal_id>). Deleting the terminal removes
the checkout after committing anything left uncommitted on the branch; the
branch is kept when it has commits the repo's HEAD lacks.
Inputs: agent_profile (required), model, provider, session_name, +3 more. Returns: object
launch_sessionsA
Launch several sessions at once, in parallel. One call for a whole fleet.
Each entry takes the same fields as launch_session: agent_profile,
session_name, working_directory, model, initial_message,
use_worktree. Every launch still blocks until its Claude is ready, so a
failure is reported against its own entry and the rest still start;
max_parallel (1-8) caps how many start at the same time.
Ten sessions launched one by one cost ten calls and several minutes of waiting; this is one call and about as long as the slowest one.
Inputs: sessions (required), max_parallel. Returns: object
list_profilesA
List the agent profiles a session can be launched with (name, role, model, effort).
Inputs: no named parameters. Returns: object
list_sessionsB
All running sessions with their terminal counts.
Inputs: no named parameters. Returns: object
list_worktreesA
Every live terminal that runs in its own git worktree: what there is to merge.
Each entry has terminal_id, status, repo, path and branch. Merge a finished
one with git -C <repo> merge <branch>; deleting the terminal commits any
leftovers on the branch, removes the checkout and keeps the branch when it
has commits the repo's HEAD lacks.
orphaned lists checkouts whose terminal died with an earlier server;
they are never removed on their own — merge what you want, then
remove_worktree.
Inputs: no named parameters. Returns: object
read_session_outputB
Read output by terminal id, or by session name when the session has one terminal.
max_chars keeps only the tail of the output.
Inputs: mode, max_chars, terminal_id, session_name. Returns: object
remove_worktreeA
Remove an orphaned checkout listed by list_worktrees (leftovers are committed first; the branch stays if unmerged).
Inputs: terminal_id (required). Returns: object
restart_terminalA
Replace a terminal's Claude with a fresh one: same id, profile, model, directory and inbox.
Use when its status is error (Claude exited) or it stays unresponsive
after interrupt. The conversation is lost. Blocks until the new Claude
is ready (up to ~90 s).
Inputs: terminal_id (required). Returns: object
send_session_messageB
Queue a message for a terminal; it is pasted as soon as the terminal is idle.
Inputs: message (required), terminal_id (required). Returns: object
shutdown_sessionB
Close every terminal of a session and the session itself.
Inputs: session_name (required). Returns: object
wait_forA
Block until a terminal finishes, asks something or dies -- instead of polling.
This holds your conversation until it returns. From Claude Code, prefer a
background watch on GET /events (see the maestro skill) so the user can
keep talking to you; use this for scripts, or with a short timeout.
Returns as soon as one watched terminal reaches one of states
(default: completed, waiting_user_answer, error -- stuck is also
available), or when timeout_seconds runs out (max 900). With
require_all it waits for every watched terminal instead of the first.
terminal_ids defaults to the whole fleet. A terminal with a message
still queued counts as busy, not finished.
This is the loop to use while a fleet runs: wait, act on what came back (read its output, answer its question, restart it), wait again. Polling get_terminal_status in a loop costs a call and a turn every few seconds and tells you nothing in between.
Inputs: states, require_all, terminal_ids, timeout_seconds. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Several tools overlap: get_terminal_output and read_session_output both read terminal output, get_terminal_status/list_sessions/get_session_info/fleet_status all report status, and send_session_message vs broadcast_message differ only in cardinality. The descriptions do a good job steering the agent toward the aggregate tools (fleet_status, wait_for, launch_sessions), which mitigates but does not eliminate the ambiguity.
Mostly consistent verb_noun snake_case (list_profiles, launch_session, send_session_message, shutdown_session, remove_worktree). A few outliers break the pattern: interrupt, wait_for, and fleet_status are not verb_noun, but naming remains readable and predictable overall.
20 tools for an agent-fleet orchestration server is on the heavy side but justified by the breadth of the domain (profiles, launch, messaging, monitoring, worktrees, usage). Aggregate tools like launch_sessions, broadcast_message, and fleet_status absorb many one-off calls, so the count is mostly earned.
The surface covers the full lifecycle: profile discovery, session/terminal launch, messaging, monitoring, interruption, restart, shutdown, worktree management, and usage. Minor gaps like an explicit kill/delete-terminal tool (only shutdown_session exists) and worktree merge automation are workable around with plain git.
Maintenance
Related MCP Connectors
Work on your own computers from Claude or ChatGPT: run commands, edit and search files.
Command center for developers coordinating AI coding agents across projects.
Your AI apps as one team: hand work to Codex or Claude Code on your Mac, with a shared logbook.
Shared workspace where Claude, ChatGPT, Codex and Grok share files, tasks, decisions and handoffs.
Related MCP Servers
- AlicenseAqualityDmaintenanceOrchestrates multiple Claude Code agents across iTerm2 sessions with process-level isolation, enabling collaborative AI development workflows on multiple codebases with task-based inter-agent communication and persistent state management.71MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude Code to orchestrate a team of independent Claude Code sessions within iTerm2 for parallel task execution and isolated git worktree management. It provides tools to spawn, monitor, and message worker sessions while maintaining full visibility and control over their terminal windows.48MIT
- AlicenseCqualityDmaintenanceManages multiple AI CLI instances (Claude Code, Codex, Gemini, Cursor) in tmux sessions for parallel task execution, with optional git worktree support.90MIT
- AlicenseAqualityDmaintenanceEnables orchestration of multiple Claude Code sessions for complex multi-task coding projects with HEAD/SUB coordination and dependency-based task execution.17 npmMIT