Documentation

Coding agents

One control surface over the agent CLIs you already use, with live status, isolated logins, and a queue that works through tasks for you.

Supported agent CLIs

23 branded adapters ship, plus a generic shell adapter.

Login is who holds the credential. Account means you bind an AI account in Muster and Muster puts its key into the agent's environment when the task starts. CLI signs itself in means the CLI runs its own login flow (copilot login, auggie login, Droid's browser flow, Kiro's device code, acli's auth) and writes the credential into the profile's isolated home — Muster holds no key for it, and the adapter's screen-detection rules surface the "not signed in" state instead. Those CLIs still need their own subscription or account.

Session resume is what the app's Resume action actually launches. For Claude Code and Codex, Muster discovers the CLI's own session id — the newest session the CLI recorded for the task's directory, read from the profile's isolated config dir, never your real HOME — and resumes that exact conversation by id. If the saved session has since been deleted, Resume falls back to the id-less form and says so rather than erroring. The other five rows naming a form resume id-less: a session picker the CLI presents, or its most recent session for that directory. Only the seven rows naming one of those can be resumed; on the rest, Resume is not offered.

AgentCommandLoginSession resume
Claude CodeclaudeAccountBy session id
CodexcodexAccountBy session id
Cursor Agentcursor-agentAccount—
Gemini CLIgeminiAccount—
OpenCodeopencodeAccount—
AmpampAccount—
AideraiderAccount—
Kimi CLIkimiAccountMost recent session
Qwen CodeqwenAccountSession picker
GitHub Copilot CLIcopilotCLI signs itself in—
ClineclineAccount—
Continue CLIcnAccountMost recent session
Goosegoose sessionAccountSession picker
Grok CLIgrokAccount—
Kilo CodekiloAccount—
Mistral VibevibeAccountSession picker
GLM CLI (z.ai)zaiAccount—
PipiAccount—
oh-my-piompAccount—
AuggieauggieCLI signs itself in—
DroiddroidCLI signs itself in—
Kiro CLIkiro-cliCLI signs itself in—
Rovo Devacli rovodev runCLI signs itself in—
Shell Agentsh——

Installed state is probed against your PATH inside each profile's environment, so a CLI installed under only one profile shows correctly.

Adapters are configuration

Each adapter is a small TOML file describing how to launch the CLI, how to detect its status, and how to resume a session. Nothing about an agent is compiled in, so:

  • A CLI that is not built in can be added as a file — no release required.
  • An adapter can be corrected locally when a vendor changes a flag.
  • The generic Shell Agent runs any command as a task's agent, with heuristic status detection.
  • Settings can override an agent's model, extra arguments and environment per agent. The model reaches the CLI for the 16 agents that accept one at launch, each wired from that vendor's own documentation; for the rest — where the model is chosen in a config file or an in-session command instead — the card says so rather than accepting a value it would drop.

Adding your own

Drop a .toml file in the adapters directory beside your config.toml — ~/Library/Application Support/dev.muster.muster/adapters on macOS, ~/.config/muster/adapters on Linux, %APPDATA%\muster\muster\config\adapters on Windows. Provider descriptors work the same way, in a sibling providers directory.

  • Your file is read everywhere an agent is resolved: the app, the muster CLI, the MCP server, and the spawn path itself — not just the picker.
  • Giving your adapter the same id as a built-in replaces it, which is how you correct a shipped flag without waiting for a release.
  • One bad file cannot break the others: each is parsed and validated on its own, the rest still load, and Settings → Agents lists the ones that were rejected and why. A malformed adapter is never silently missing.
  • If you add or change a file by hand while the app is running, muster reload-config makes the running app re-read its adapters (it re-reads the config too).

Importing a shared adapter

Adapters are meant to be shared: they are plain TOML, carry no credentials, and anyone's file works in your app. Settings → Agents → Import an adapter brings one in without opening the config directory:

  • Import from file… picks a .toml from your disk.
  • Import from URL fetches one over https only, with a short timeout and a 64 KiB size cap.
  • The descriptor is validated before anything is written — a malformed file is refused with the same message Settings would show for a hand-dropped one, and the same size cap applies to a picked file as to a fetched one.
  • If the adapter's id already exists — built-in or one of yours — nothing is written until you explicitly choose Replace. Replacing a built-in is the documented override path; replacing one of your own updates it in place.
  • The import lands in the adapters directory and is live immediately: the agent picker, the launch path and the muster CLI see it with no restart.

The descriptor format

An adapter is one TOML document. The four required keys are id, label, vendor and program, plus the [status] table; everything else is optional and defaults to the safe/absent value.

KeyTypeMeaning
idstring, requiredStable identifier — the registry key. A user file whose id matches a built-in replaces it. Stick to letters, digits, -, _ and .: imports are written as <id>.toml.
labelstring, requiredThe display name shown in the picker and on the Settings card.
vendorstring, requiredVendor key. When providers is empty, the provider this agent binds to is derived from it.
programstring, requiredThe CLI binary, resolved on PATH inside the profile's environment. Drives the installed/not-installed badge.
argsstring listArguments passed to program on every launch (default: none).
requires_accountboolWhen true, a task with this agent is refused until the profile has a bound account (default: false).
config_dir_envstringEnv var Muster sets to point the CLI's config/auth directory at the profile — what keeps two subscriptions from mixing.
providersstring listProvider ids this runner can drive. ["*"] means provider-agnostic (the account is chosen at bind time). Empty derives the provider from vendor.
kindstringpty (default; a TUI in a pane), api_oneshot or chat_repl (headless runners).
model_argtableHow a chosen model is passed: { flag = "--model" } appends --model <model>; { env = "SOME_VAR" } sets an env var. Absent ⇒ no model selector, and the Settings card says so.
TableKeysMeaning
[caps]agentic, interactive_pty, needs_workdir, tool_useCapability flags (all default false): edits files autonomously, runs as a TUI, operates on the task worktree, does function/tool calling.
[status]mechanism (required), idle_states, busy_states, input_statesHow status arrives: hook (the CLI POSTs its state to Muster) or heuristic (inferred from output activity). The state lists map the CLI's raw state strings to Muster's vocabulary — a raw state may appear in exactly one list, and validation rejects an overlap.
[hooks]installNamed hook-installer routine that wires the CLI to emit status events. Only meaningful with mechanism = "hook"; the routine itself is built into Muster, so user adapters normally use heuristic.
[install]cmd, args, docs_url, verifiedThe one-click CLI installer on the Settings card. Only a verified = true command is ever run — anything else makes the card open docs_url instead. Multi-step installs go through cmd = "sh", args = ["-c", "…"] as a single spawn.
[resume]args, session_dirHow to resume the CLI's own prior session: args with the literal {session} token replaced by the session id (["--resume", "{session}"]), and session_dir, the subdirectory of the config dir where the CLI writes its sessions (where Muster discovers the id). Absent ⇒ Resume is not offered.
[[detection.rules]]substring or regex, state, detail, case_insensitiveOrdered, first-match-wins rules that read the pane's screen output into a rich state: idle, working, blocked or done, with an optional human-readable detail. Exactly one of substring/regex per rule; regexes are compiled once at load and an invalid one rejects the adapter with a named error.

A complete example

A fictional CLI, fixit, exercising every part of the schema — launch, model flag, verified install, by-id resume, and screen detection:

# adapters/fixit.toml — an adapter for the fictional Fixit CLI.
id = "fixit"
label = "Fixit"
vendor = "fixit"
program = "fixit"                  # resolved on PATH inside the profile env
args = ["--tui"]
requires_account = true
config_dir_env = "FIXIT_HOME"      # profile isolation for its credentials
providers = ["fixit"]              # or ["*"] for a provider-agnostic CLI
kind = "pty"
model_arg = { flag = "--model" }

[caps]
agentic = true
interactive_pty = true
needs_workdir = true
tool_use = true

[status]
mechanism = "heuristic"            # no native status hook — infer from the screen
idle_states = ["ready"]
busy_states = ["working"]
input_states = ["awaiting_confirmation"]

[install]
cmd = "npm"
args = ["install", "-g", "@fixit/cli"]
docs_url = "https://fixit.example.com/docs/install"
verified = true                    # only a verified command is ever one-click run

[resume]
args = ["--resume", "{session}"]   # {session} is replaced by the discovered id
session_dir = "sessions"           # under FIXIT_HOME, where the id is discovered

# Screen detection, first match wins — put specific prompts before generic ones.
[[detection.rules]]
substring = "Apply these changes?"
state = "blocked"
detail = "waiting for your confirmation"

[[detection.rules]]
regex = "error|panic|traceback"
state = "blocked"
case_insensitive = true

[[detection.rules]]
substring = "All tasks complete"
state = "done"
detail = "reported finished"

Share the file itself — in a repo, a gist, a message. The recipient drops it in their adapters directory or imports it straight from the URL in Settings → Agents.

Profiles & isolation

A profile is an identity, and the reason work and personal accounts can share one machine without mixing. Each carries:

  • Its own agent config directories, so subscription logins never collide.
  • Its own git identity — name, email, signing key.
  • Its own default SSH key.
  • Its own environment overlay for spawned processes. For an agent bound to a single vendor (Claude Code, Codex, Cursor Agent, Gemini CLI, Amp and the rest), the overlay is the last word: an entry here outranks everything Muster sets itself, including the bound account's API key — so a profile can point that agent at a proxy or a scoped key without unbinding its account.
  • Optional pinned Node and Python versions, resolved against your nvm/pyenv installs.
One exception, and it runs the other way. The nine provider-agnostic agents — Aider, Cline, Continue CLI, Goose, Kilo Code, oh-my-pi, OpenCode, Pi and Qwen Code — take whichever AI account you bind to them, and that account's API key and base URL are written into the environment after the overlay is applied. For those agents an overlay entry naming the same variable is overwritten by the bound account. Unbind the account if the overlay is meant to win.

tool_isolation decides which tools get a private config directory per profile rather than sharing the host's. Account tokens live in your chosen secret backend, never in a config file.

Queue & templates

Rather than starting agents one at a time, enqueue the work:

  • Each entry has its own prompt, agent and profile — a mixed stack in one queue is fine.
  • Muster works entries in order: open the worktree, start the agent, feed the prompt, move the task to review when it finishes.
  • A failed entry can be retried with nothing retyped — it keeps the project, agent, profile, prompt, worktree flag and, deliberately, its permission policy.
  • Concurrency is bounded, so a queue cannot spawn twenty agents at once.
  • Templates turn a repeated setup into one click.

What the queue is, exactly

  • There is one queue, not one per project. A single position counter and a single concurrency cap cover everything, so a long-running task in another project can hold the slot your entry is waiting for.
  • Retry re-runs the work, not the row. The retry is appended at the tail with a new id and a fresh task; the failed row is then dropped. It does not resume the failed task — that task may have a dirty worktree — and it does not keep its old position.
  • done is a scheduler state, not a verdict. An entry retires when its task has been idle for a few seconds, or reached review or error. It says the slot is free, not that the agent did what you wanted. A task waiting on input is never retired, so a blocked agent holds its slot until you answer it.
  • “Clear finished” also clears failed. One delete removes done, failed and canceled rows — and a failed row's saved spec is the only thing Retry can re-run, so clearing throws away every retry. That is why it asks first.

The queue also runs headlessly — muster queue run works the same queue from a terminal with the app closed. Something must be working it: with neither the app open nor that command running, entries just sit at their position.

New here? Start the 7-day trial — every feature, card up front, $0 today, key on screen. Or buy outright: $39 once per device, no subscription.