# Extending and automating

Take Muse Code past a single interactive session: distribute work across parallel agents, package reusable workflows as skills, wire your own commands into the lifecycle with hooks, connect external tools through MCP, and run the agent non-interactively in CI.

For structured orchestration with parallel groups, dependent stages, monitoring, and reusable JavaScript definitions, see [workflows](https://dev.meta.ai/docs/muse-code/workflows). To coordinate independent live sessions, use [session messaging](https://dev.meta.ai/docs/muse-code/session-messaging).

## Subagents and multi-agent

Distribute a large job across a team of agents that work in parallel, and steer them from one place. A lead session spawns child agents, hands each a bounded task, and keeps managing the group while they run.

A **subagent** is a child agent that the lead spawns for one bounded task. Children share the lead's checkout unless the lead requests worktree isolation for that child. Ask for isolated worktrees when parallel children may write, and keep read-only children in the shared checkout.

An isolated child gets a Muse Code-managed Git worktree. The request can be rejected when the current profile, workspace, provider, or Git state cannot support isolation. It never silently falls back to the shared checkout.

The `--subagent-worktree-isolation` launch flag remains accepted for compatibility. It does not force every child into a worktree; isolation is still selected per child.

Use subagents when a job splits into tasks that are each bounded, independently verifiable, and would otherwise contend for the same files. Keep the work on one agent when the steps are strictly sequential.

**Steer the agents.** Run `/subagents` to view running and past subagents. Run `/tasks` to manage direct subagent tasks and use the actions available for the selected row. The lead also manages children through its native subagent tools.

A few properties worth knowing:

- One agent tree can execute eight agents at once by default, including the root agent. Set `agents.execution_capacity` from 1 through 64 in `settings.json` to change the limit. An unconfigured `ultra` root uses 64.
- A spawn attempted when the tree is full is rejected. An accepted child can still wait for a host scheduler slot before it starts.
- Children can spawn grandchildren. Every descendant shares the same root-tree capacity.
- Cancellation is cooperative: a cancelled child that never reaches a checkpoint keeps running, and one mid-write finishes that write.
- The runtime journals every spawn, status change, and control action, so you can answer "which child did what, and when" after the run. A child commits changes only when its task explicitly asks it to.

### Background observer agents

Alongside the main session, Muse Code runs a team of background observer agents. Each one watches a single axis of quality, and can insert a short advisory into the main agent's next turn without an interruption. An observer never answers for you: it proposes, a reconciler decides, and only an accepted proposal reaches the main agent.

- **Memory recall**: surface a note from local project [memory](https://dev.meta.ai/docs/muse-code/configuration#local-memory) relevant to the next reply.
- **Skill recall**: surface a project [skill](https://dev.meta.ai/docs/muse-code/extending#skills) the task should load first.
- **Goal tracking**: hold the agent to a declared [goal](https://dev.meta.ai/docs/muse-code/interactive#goals-loops) and decline to close the turn until the work is done.
- **Verification**: check that the agent ran the work it claims it finished.

All four observers, including verification, are on by default. Rollout gates and your [settings file](https://dev.meta.ai/docs/muse-code/configuration#settings-file) can still disable them.

> **NOTE: Observers add token usage**
>
> Each enabled observer makes its own model calls, so the default set of four adds token usage in addition to the main session.

## Skills

A skill packages a repeatable workflow the agent can load on demand: a set of instructions, and optionally tools and files, that turn "explain how we do X" into a single invocation. Muse Code ships built-in skills, and you can add your own or import them from other agents.

Skills load from four sources:

- **Built-in**: skills that ship with Muse Code.
- **User**: your account-wide skills in `$XDG_CONFIG_HOME/muse/skills` and `~/.agents/skills`, available in every project. Muse Code also discovers `~/.claude/skills` and `$CODEX_HOME/skills` by default, falling back to `~/.codex/skills` when `CODEX_HOME` is unset. A user preference and rollout gate can disable these foreign personal skill roots.
- **Project**: skills committed to a repo under `<repo>/.agents/skills/<skill-id>/SKILL.md`, shared with anyone who clones it. Muse Code also scans repo-local `.codex/skills` and `.claude/skills`.
- **Plugin**: skills contributed by enabled plugin bundles.

Manage and invoke skills:

```bash
muse skills list                    # every skill, all sources
muse skills inspect <skill-id>
muse skills enable <skill-id> --scope project
muse skills install ./my-skill --scope user
muse skills validate ./my-skill     # check it before installing
muse skills import --from claude    # or: --from codex
```

In an interactive session, invoke a skill with its slash shortcut. Built-in skills include `/plan` (turn a task into a grounded, decision-complete plan, then stop for approval), `/grill` (stress-test a plan or design before you build, recording each settled decision and a written scope contract in your project docs), `/taste` (a design-quality gate for frontend work), and `/threejs` (references for building Three.js scenes). The agent can also load a relevant skill when a [background observer](https://dev.meta.ai/docs/muse-code/extending#observer-agents) surfaces one.

The bundled `migrate` skill imports your Claude Code or Codex memory notes and MCP servers into Muse Code. Invoke it with `/migrate`. It complements `muse skills import`, which brings in skills from those agents.

## Hooks

Wire your own shell commands into Muse Code's lifecycle. A hook binds a shell command to a lifecycle event. When the event fires, Muse Code runs the command and acts on its result: enforce a check, format code, or block an action before it happens, without a change to the agent itself.

Hooks come from three sources:

- **Project**: committed to the repo at `<project-root>/.muse/hooks.json`.
- **User**: your machine-wide hooks, defined in your [settings](https://dev.meta.ai/docs/muse-code/configuration#settings-file).
- **Managed**: a file that the `managed_hooks_path` setting points to, for centrally administered hooks.

Project hooks run only after you trust the project folder. User hooks run from your own settings without a separate hook-level trust step. Managed hooks also run without a project-trust step, so whoever controls the managed hooks file controls what executes.

> **WARNING: Hooks run outside the sandbox**
>
> Only add hooks whose commands you've read. A hook's command runs directly through your shell, **outside** the [sandbox and approval](https://dev.meta.ai/docs/muse-code/permissions) that govern the agent's own tools. The only hardening is a cleared environment with a small allowlist.

### Lifecycle events

A hook binds to exactly one event. The available events are `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PermissionRequest`, `PostToolUse`, `PostToolUseFailure`, `PreLLMCall`, `PostLLMCall`, `PreCompact`, `PostCompact`, `SubagentStart`, `SubagentStop`, `Notification`, `Stop`, and `SessionEnd`. `PostToolUseFailure` runs when a tool call fails or crashes. `Notification` fires when the agent needs your approval, so a hook can alert you. `SessionEnd` runs during orderly session termination. It is observational: its output cannot block termination, inject context for a later request, or stop the session.

Muse Code discovers and validates hooks at session startup. A malformed project or managed hook file contributes no handlers from that source and produces a startup warning. A malformed user settings file fails settings validation. Unsupported events, matchers, or handlers skip the affected entry and produce a source-specific warning.

There is no active `muse hooks` command family or per-hook trust command. Fix the reported configuration and start a new session to reload it.

## MCP servers

Connect external tools through the Model Context Protocol (MCP). Declare servers in the `mcp_servers` block of your [settings file](https://dev.meta.ai/docs/muse-code/configuration#settings-file). Each server takes a `transport`: either `stdio` (with `command`, `args`, and `env`) or `streamable_http` (with `url` and `headers`). Every server also takes `enabled` and `mode`. For `stdio`, the optional `framing` setting controls message framing. A non-default `framing` value on `streamable_http` fails validation.

```json
{ "mcp_servers": {
    "my-tools": { "transport": "stdio", "command": "my-mcp-server", "args": [] }
} }
```

A server's `mode` defaults to `required`. If a required server fails to start, the whole run aborts. Set `mode` to `optional` for a server that Muse Code should skip with a warning when it's unavailable.

Server configs support `${VAR}` environment-variable interpolation, and Muse Code passes `MUSE_SESSION_ID` to `stdio` servers. A tool whose server declares it read-only runs without an approval prompt under [on-request approvals](https://dev.meta.ai/docs/muse-code/permissions#approval-modes). Run `/mcp` in an interactive session to see a live inventory of connected servers and their tools.

> **WARNING: MCP tools aren't sandboxed**
>
> Only connect servers you trust. **MCP tools are not sandboxed.** Unlike shell commands, an MCP server runs as an ordinary child process (stdio) or a direct network connection, outside the filesystem and network [sandbox](https://dev.meta.ai/docs/muse-code/permissions#sandbox). Approval still applies, but containment does not.

### Sign in to remote MCP servers

A remote server can require an OAuth 2.1 sign-in. Authenticate in the browser or headless, and Muse Code keeps and refreshes the tokens for you:

```bash
muse mcp login <server>
muse mcp logout <server>
```

A sign-in done in another terminal is picked up without a restart, and a startup or mid-session 401 tells you the exact `muse mcp login` command to run. To turn off automatic client registration, set `"mcp_oauth_dynamic_client_registration": false` in your [settings file](https://dev.meta.ai/docs/muse-code/configuration#settings-file).

## Headless and CI

Run Muse Code without a terminal UI. `muse exec` takes one prompt, runs it to completion, and exits, so you can drive the agent from a script, a job, or a CI pipeline:

```bash
muse exec "Update the changelog for the latest release and run the tests."
muse exec --prompt-file ./task.txt
muse exec --json "Refactor the auth module and run the tests."   # JSONL events on stdout
```

`muse exec` prints the agent's output to stdout and returns a process exit code that reflects **how the run ended, not whether the work is correct**: `0` when the turn completes, `1` when it fails or is cancelled (including a `--max-model-steps` limit), `2` for a usage error, and `130` or `143` on SIGINT or SIGTERM. An agent can finish its turn (exit `0`) and still report failing tests, so gate on your own test command, not on the exit code alone.

**Control approvals for automation.** A non-interactive run has no one to answer an approval prompt, so choose a posture in advance:

- **`--disable-approval`**: skip approval prompts, but keep the [sandbox](https://dev.meta.ai/docs/muse-code/permissions#sandbox) on to contain what runs.
- **`--yolo`**: disable approval and the sandbox for a fully unattended run. It also trusts the workspace, so use it only on trusted code in a disposable, isolated container. See [run without guardrails](https://dev.meta.ai/docs/muse-code/permissions#run-without-guardrails).

Cap a run's work with `--max-model-steps` so a stuck task can't loop indefinitely.

> **NOTE: CI sandbox requirements**
>
> The [sandbox](https://dev.meta.ai/docs/muse-code/permissions#sandbox) must be able to run on the CI runner, which on Linux needs a working bubblewrap and a non-musl build. Without it, every sandboxed shell command aborts as an environment failure.

**Resume and audit non-interactively.** Headless runs are [sessions](https://dev.meta.ai/docs/muse-code/interactive#session-model) like any other. To continue an interrupted job non-interactively, use `exec` with the session id. `muse resume` opens the interactive UI and is not a headless surface:

```bash
muse exec --session-id <uuid> "Continue the task."
muse export --session <uuid> --out run.json
```

Muse Code refuses a workspace mismatch unless you pass `--allow-workspace-switch`. The export document embeds the CLI version that produced it, so pin the version if you gate on its hash.

## Next steps

- Keep the whole team inside the same [permissions and sandbox boundary](https://dev.meta.ai/docs/muse-code/permissions).
- Build repeatable multi-agent runs with [workflows](https://dev.meta.ai/docs/muse-code/workflows).
- Give skills and subagents the project facts they rely on in [configuration and context](https://dev.meta.ai/docs/muse-code/configuration).
- Connect external agent tooling to the model from the [coding agents](https://dev.meta.ai/docs/coding-agents) guide.
