Skip to main content
Glama

Muster

license

Launch coding agents on your machine, under containment you chose, and get back an address you can actually reach.

Muster starts Claude Code, Codex and OpenCode sessions on your behalf. You say what the agent may do; Muster arranges it, verifies the session is genuinely alive, and hands you a durable address for it. If a session never becomes reachable, you get a diagnosis naming what stopped it — not a process that looks fine and isn't.

It is the launching half of a small family: Muster starts agents, tincan lets them message each other, birddog watches what they do.

What it's for

Running more than one agent, deliberately. One session reviewing while another builds; a task that runs once and captures its output; an agent launched under a separate account so its work never touches your own configuration. Muster is the part that makes those launches repeatable, contained and addressable instead of a terminal tab you have to remember.

A session returns an address only after its runtime is reachable. A task runs once, captures output, and never advertises a peer address.

Related MCP server: LightsOut

What makes it different

  • Containment is two separate questions, and both are answered. Whether the agent stops to ask you, and what it may touch — the second enforced by the OS, not by asking nicely. Every launch records which of the two it actually got.

  • A session is only reported ready when it is reachable. Muster asks each runtime in its own language — a session record, an RPC call, an HTTP endpoint — and does not confuse "the process started" with "the agent is listening".

  • It refuses instead of guessing. An unrecognised flag, a contradictory pair of options, an identity belonging to a different runtime: all errors, before anything is started. Nothing half-launched is left behind.

  • Other machines can ask, within limits you set. An enrolled caller launches inside a profile's ceiling — the directories it may use, the strongest containment it may request. Configuration is the grant; the request never widens it.

  • Every claim here was measured. Runtime behaviour is established by driving the real programs and recording what they did — see Verification. Where a finding later proved wrong, the correction is in the release notes rather than quietly edited away.

Claude requires a directory already trusted by the operator, or --options auto-approve-path. The automated suite uses fake runtimes, not real models; behaviour against real ones is verified by hand and recorded in RELEASE_NOTES.md.

Quick start

# Allow the install scripts: muster's postinstall builds node-pty, and npm
# skips install scripts by default — silently, so the pty host fails later.
npm install -g --allow-scripts=@brutalsystems/muster,node-pty @brutalsystems/muster

# A session: an agent you can reach, addressed once it is genuinely alive.
muster run claude --prompt 'Review this project' --cwd .

# A task: runs once, captures output, advertises nothing.
muster run codex --kind task --prompt 'Summarise the failing tests' --read-only
muster output <id>

# Knowing it has finished: block on it, or have muster run a command then.
muster wait <id> --timeout 30m
muster run codex --kind task --prompt 'Review' --on-exit 'notify "$MUSTER_STATE"'

# What is running, and stopping it.
muster list --format human
muster stop <id>

# Show a session in a terminal: terminal, iterm2, ghostty, or one you define
# under [open.apps] in config.toml (see docs/launching.md).
muster run claude --prompt 'Review this project' --open kitty

A Claude launch with no containment flag opens exactly as you would open it by hand in that profile and folder. It gets your rules and CLAUDE.md, your permissions, hooks, status line, plugins, MCP servers and settings env. Muster adds nothing and replaces nothing. The one thing it refuses is a profile whose default permission mode is bypass. Codex and OpenCode stay read-only by default.

When you want muster's guarantee instead, seal the launch. A sealed launch runs on muster's own settings in place of the profile's, so it loads no rules or CLAUDE.md:

Flag

The agent asks before acting

What it may touch

--read-only

always

nothing on disk

--write-here

no

its cwd, except ~/.muster

--unrestricted

no

everything

--unrestricted removes the sandbox and needs allow_dangerous_flags in config. --level read|work|open is the older spelling of the same three and still works.

Claude asks to trust a directory the first time. That is a one-time review you do yourself — or --options auto-approve-path, which records it for you after checking the directory ships no hooks. See Claude workspace trust.

Requirements

Node 22.12+ (tested on 24.16), and a POSIX host with ps and lsof. Terminals use tmux or node-pty. The OS sandbox is seatbelt, so kernel-enforced containment is macOS only; everywhere else enforcement reports what was actually applied rather than pretending.

Then whichever agents you mean to launch, installed and logged in. Verified against Claude Code 2.1.274, Codex 0.155.1 and OpenCode 1.18.31 or newer — a newer OpenCode must keep the CLI and loopback HTTP API Muster uses. What that verification covers is in Verification.

Documentation

How a launch runs

hosts, terminals, lifetimes, repeated requests

Configuration and permissions

containment, config file, remote callers

Agent identities

running as a named account

Claude workspace trust

the one-time dialog, and the two gates behind it

Command-line reference

output formats, runtime pass-through

MCP servers and plugins

tools for launched agents, and Muster's own MCP server

Verification

what is tested, what is checked by hand

Use with Claude Code

  1. Install the plugin. Its muster skill teaches a Claude session to use Muster well: choosing a kind and level, reaching and stopping what it launched, and the traps. It also brings Muster's MCP server, read-only (list, output), started with npx at the release the plugin came from. Both are versioned with Muster, so they describe and run the same release.

    claude plugin marketplace add BrutalSystems/muster
    claude plugin install muster@muster

    Or, inside a session, /plugin marketplace add BrutalSystems/muster and then /plugin install muster@muster.

    The plugin's server needs Node 22.12+ with npx on PATH. On macOS and Windows, node-pty loads a prebuilt binary. On Linux, npx builds node-pty from source the first time, which needs Python, make and a C++ compiler; without them, use the global install and step 2 instead.

  2. Or register the MCP server yourself, when you want launch authority or a server that runs your global muster:

    muster mcp install

    It is read-only by default too. muster mcp install --allow-launch adds run, stop, title and open, and every session in that profile can then launch and stop sessions. muster mcp status shows which you have. Use the plugin's server or this one, not both: see plugin or registration. Details: MCP installation.

  3. Restart Claude Code (or start a new session) to load it.

Keeping it up to date

Publishing a release does not touch an installed copy: muster --version keeps reporting the old version until you update it.

npm update -g @brutalsystems/muster

If which muster resolves to a version-manager shim (for example ~/.asdf/shims/muster), run that update under the Node the shim resolves to and reshim afterwards — asdf reshim nodejs — or the shim keeps pointing at the old binary.

The plugin, and the server it pins, update with the marketplace:

claude plugin marketplace update muster
claude plugin update muster@muster

An MCP server starts once at session startup, so an agent session that already has Muster loaded keeps running the old binary until that session restarts. Updating on disk is not enough; restart the session too.

Build and run locally

npm run check is the local gate: it builds, runs the suite, then packs and verifies the tarball — the same scripts/check-tarball.mjs the CI packing job runs, so the two cannot disagree about what "verified" means. npm test alone does not pack anything, so tarball drift is green locally and red on push.

It is not everything CI does: CI additionally runs the suite across the Node version matrix, and the contract suite runs only on release. Passing check is necessary rather than sufficient.

Beyond the runtime requirements above, building needs TypeScript 5. The terminal interface itself is platform-neutral; the macOS Terminal driver is an unavailable v1 stub.

npm ci
npm run build
node dist/muster.js run codex --prompt 'Review the authentication flow'
node dist/muster.js run claude --prompt 'Summarize the project' --host tmux
node dist/muster.js run opencode --prompt 'Review this project'
node dist/muster.js run opencode --prompt 'Build a plan' -- --model local-provider/qwen3-30b
node dist/muster.js run codex --kind task --prompt 'Explain the test layout'
node dist/muster.js run opencode --kind task --prompt 'Summarize the tests'
node dist/muster.js list
node dist/muster.js list --format human
node dist/muster.js list --kind task
node dist/muster.js output RUN_ID
node dist/muster.js stop THREAD_OR_SESSION_OR_RUN_ID

--prompt is required and cannot be blank. --cwd defaults to the current working directory. --kind defaults to session. All commands except output emit JSON; output prints the captured task output. stop also accepts an unambiguous peer name or canonical address, refusing ambiguity with candidates. Use the durable ID to stop a session whose runtime has renamed it.

License and releases

MIT © 2026 BrutalSystems. See LICENSE. Vendored Tin Can code retains source attribution and its MIT notice.

Publishing is tag-driven and runs in GitHub Actions over OIDC trusted publishing, with no stored npm token. A bare git push publishes nothing; a version tag is what triggers publish.yml. That workflow validates a RELEASE_NOTES.md section for the version being published, so write the notes under ## Unreleased as you do the work and commit them normally. Cutting the release is then one command:

git commit -am "<the change, including its notes under ## Unreleased>"
npm version patch -m "%s — <what changed>"

npm version runs the version hook, which stamps ## Unreleased into ## <version> — <date> and stages it, then bumps, commits and tags; the postversion hook pushes the commit and tag together. If there is no ## Unreleased section, or it is empty, the stamp refuses — before a tag exists, rather than in CI after one has been pushed.

RELEASING.md covers versioning, package inspection, publication, and release notes in full. Changes to the shared address format require an explicit contract update; Muster never independently fixes the frozen naming behavior.

Available Tools

2 tools
listList sessions and tasksB
Read-only

List Muster-owned sessions and tasks, including host capabilities.

NameRequiredDescriptionDefault
kindNo

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds useful scope by saying results are Muster-owned and include host capabilities. However, it does not describe ordering, pagination, or whether the list is exhaustive, leaving some behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence with no redundant phrasing. Every element, including the ownership scope and host-capability inclusion, adds useful information. There is no structural waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple list tool with one optional enum parameter and annotations covering safety. The description states the resource and scope, but it omits parameter behavior, return-shape detail, and sibling-tool guidance. It is minimally adequate but has clear gaps for an agent deciding exactly how to call it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description never mentions the 'kind' parameter. It does not explain that 'kind' filters between sessions and tasks, nor what happens when it is omitted. The enum values are self-explanatory, but the description does not compensate for the missing schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: listing Muster-owned sessions and tasks. It also adds that host capabilities are included, which clarifies scope. It does not explicitly distinguish this tool from the sibling 'output', but the resource is clear enough to identify the operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no guidance on when to use this tool versus the sibling 'output', nor does it state any exclusions or prerequisites. Usage is only implied by the verb 'List'. An agent must infer the appropriate context without help from the description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

outputRead task outputB
Read-only

Read captured output from a task run.

NameRequiredDescriptionDefault
idYes

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds that the output is 'captured' from a task run, clarifying that this reads stored output rather than streaming or live data. It does not explain truncation, permissions, or error behavior, but for a simple read-only tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence with no wasted words. It is appropriately sized for a simple read operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity read-only tool with annotations and one required parameter, the description is minimally viable. It is missing explicit id semantics and any note about the return format, but the tool name and title carry much of that meaning.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the single required parameter 'id' is undocumented. The description implies the id identifies a task run, but it never explicitly states what the id is, its format, or how to obtain it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Read') and resource ('captured output from a task run'), making the core purpose clear. It does not differentiate itself from the sibling tool 'list', but an agent can still understand what this tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus the sibling 'list', nor any prerequisites or exclusions. The usage is only implied by the verb 'Read'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv3.0.0
    • Removedrun
    • Removedstop
    • Removedtitle
  2. 2 tool updatesv1.2.0
    • Changedrun3 fields changed
      • changedInput schema / properties / idleTimeout / description
        Previous value: -"Stop this tmux session after the given inactivity, as 90s/30m/4h, or 'off'. Defaults to 30m. Refused for tasks and for pty or macos-terminal hosts, which do not outlive their parent."New value: +"Stop this tmux session after the given inactivity, as 90s/30m/4h, or 'off'. Off by default. Refused for tasks and for pty or macos-terminal hosts, which do not outlive their parent."
      • addedInput schema / properties / options
        Added value: +{
        +  "description": "Muster-side launch options. auto-approve-path records the launch directory as trusted in the profile the agent will use, so its one-time dialog does not block the launch; refused for a runtime with no trust gate, and refused if the directory ships hooks or MCP servers. accept-bypass-warning accepts Claude's one-time Bypass Permissions warning for a bypass launch (level open); refused for other runtimes and without bypass permissions. Not expressible remotely.",
        +  "items": {
        +    "enum": [
        +      "auto-approve-path",
        +      "accept-bypass-warning"
        +    ],
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "description": "Terminal title for this tmux session, shown by any terminal attached to it. Defaults to the session's name and runtime once it is reachable; the agent's own title is shown instead only with [session] title_from_agent. Control characters are stripped and it is capped at 100 characters. Refused for tasks and for pty or macos-terminal hosts.",
        +  "type": "string"
        +}
    • Addedtitle
  3. 1 tool updatev0.9.1
    • Changedrun2 fields changed
      • addedInput schema / properties / idleTimeout
        Added value: +{
        +  "description": "Stop this tmux session after the given inactivity, as 90s/30m/4h, or 'off'. Defaults to 30m. Refused for tasks and for pty or macos-terminal hosts, which do not outlive their parent.",
        +  "type": "string"
        +}
      • addedInput schema / properties / ttl
        Added value: +{
        +  "description": "Stop this tmux session the given duration after launch regardless of activity, as 90s/30m/4h, or 'off'. Off by default.",
        +  "type": "string"
        +}
  4. 1 tool updatev0.7.21
    • Changedrun1 field changed
      • changedInput schema / properties / model / description
        Previous value: -"PROVIDER/MODEL, overriding the configured [opencode] model. OpenCode only."New value: +"Model for the launch. A bare model id for claude and codex; PROVIDER/MODEL for opencode, where it overrides the configured [opencode] model. Recorded on the run and reported by `list`."
  5. 1 tool updatev0.7.14
    • Changedrun6 fields changed
      • addedInput schema / properties / identity
        Added value: +{
        +  "description": "A named identity created by `muster setup-identity`; the agent runs as that account instead of inheriting the ambient environment. A non-local requester is bounded by its profile's identities.",
        +  "pattern": "^[a-zA-Z0-9_-]+$",
        +  "type": "string"
        +}
      • addedInput schema / properties / level
        Added value: +{
        +  "description": "A spelling of a legal permissions/sandbox pair: read is deny + read-only, work is auto + workspace-write, open is bypass + full-access. Naming a level and either flag is an error.",
        +  "enum": [
        +    "read",
        +    "work",
        +    "open"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / model
        Added value: +{
        +  "description": "PROVIDER/MODEL, overriding the configured [opencode] model. OpenCode only.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / plugin
        Added value: +{
        +  "description": "Configured OpenCode plugin names. Omit for session defaults; [] disables all. OpenCode only.",
        +  "items": {
        +    "pattern": "^[a-zA-Z0-9_-]+$",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / project
        Added value: +{
        +  "description": "A project named in config.toml, used instead of cwd. Naming both is an error.",
        +  "pattern": "^[a-zA-Z0-9_-]+$",
        +  "type": "string"
        +}
      • addedInput schema / properties / requestKey
        Added value: +{
        +  "description": "Caller-owned identity for this launch. Repeating it returns the launch it already produced instead of starting another; repeating it with different parameters is refused.",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
  6. 1 tool updatev0.7.8
    • Changedrun4 fields changed
      • addedInput schema / properties / mcp
        Added value: +{
        +  "description": "Configured MCP server names. Omit for session defaults; [] disables all. Tasks have no defaults.",
        +  "items": {
        +    "pattern": "^[a-zA-Z0-9_-]+$",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedInput schema / properties / open
        Added value: +{
        +  "description": "Open the tmux session in a terminal viewer (macOS only).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / runtime / enum
        Previous value: -[
        -  "codex",
        -  "claude"
        -]New value: +[
        +  "codex",
        +  "claude",
        +  "opencode"
        +]
      • addedInput schema / properties / terminal
        Added value: +{
        +  "description": "Viewer app; requires open. Auto uses Terminal.app.",
        +  "enum": [
        +    "auto",
        +    "terminal",
        +    "iterm2",
        +    "ghostty"
        +  ],
        +  "type": "string"
        +}
  7. 4 tool updatesv0.3.0
    • First observedlist
    • First observedoutput
    • First observedrun
    • First observedstop

TDQS

B3.2/5.0

Scored across 2 tools

Disambiguation4/5

The two tools have distinct purposes: list enumerates sessions/tasks/host capabilities, while output reads captured output from a task run. There is little overlap, though the generic name 'list' is broad enough that an agent may need to inspect the description to know what it lists.

Naming Consistency4/5

Both tool names are single lowercase verbs, so the naming style is internally consistent. However, they are very generic and do not follow a descriptive verb_noun pattern, which reduces predictability.

Tool Count3/5

Two tools is thin for a server that appears to manage sessions, tasks, and task output. It sits at the borderline where the surface feels underpowered for the apparent domain.

Completeness2/5

The server exposes only listing and output-reading, with no tools for creating, starting, updating, or deleting tasks/sessions. These are significant gaps that will likely cause agents to hit dead ends in core workflows.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers