> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mutagent.io/llms.txt
> Use this file to discover all available pages before exploring further.

# mutagent factory

> Register the agents, skills, workflows and multi-agent systems you manage, keep their agentspecs in sync with the platform, and record every lifecycle stage run against them.

The Factory is your workspace's record of everything you manage, wherever it runs: Mutagent Cloud, a
code repository, or another platform. Each thing it manages is a **Factory entry**: one agent, skill,
workflow or multi-agent system. For each entry the Factory keeps its agentspec versions, the builds
that implement them, and every lifecycle stage run against them, with the reports that are their
evidence.

This is the Agent Factory. The [Software Factory](https://docs.mutagent.io/factory/overview.md) (`factory.yaml`, board-driven
runs) is a different product with its own CLI, `architech factory`.

`mutagent factory` does four jobs: register entries, update their specs, record stage runs, and read
them back. Reports are pushed with [`mutagent reports push`](https://docs.mutagent.io/cli/commands/reports#mutagent-reports-push).

* An entry's **id** is its agentspec's `metadata.id`. Every command addresses the entry by that id:
  `mutagent factory show invoice-pricing`.
* The spec decides the rest: the entry's kind (`Agent`, `Skill`, `MultiAgent` or `Workflow`), its
  deployment targets (the spec's `targets[]`), and, for a multi-agent system, its components
  (`spec.multiAgent.members[]`). To change any of them, edit the spec and push it.
* A **spec version** is one recorded version of the agentspec: `1`, `2`, and so on.
* A **build** is one deployed package of an entry with a Mutagent Cloud target, linked to the spec
  version it implements. Other targets ship by pull request.
* A **stage run** is one run of one lifecycle stage against an entry, with an id that starts with
  `sr_`. The stages are `spec`, `build`, `evaluate`, `diagnose`, `optimize` and `ship`; the states are
  `started`, `succeeded`, `failed` and `cancelled`.

**Before you start:** [install the CLI](https://docs.mutagent.io/cli/installation.md), [sign in](https://docs.mutagent.io/cli/commands/login.md)
(`MUTAGENT_API_KEY=<key> mutagent login --json` for a coding agent), and select the workspace with
`mutagent workspaces use <workspace-name>`. Writes (`add`, `spec push`, `stage start`, `stage finish`,
`stage record`) need the editor or admin role. Every command takes `--json` and then prints one result
object on stdout.

Reads run freely. `add`, `spec push`, `stage start`, `stage finish` and `stage record` change shared
workspace data: a coding agent confirms with the person before it runs one. `delete` also needs
`--force`.

## A worked example

Register an agent from its spec, record an evaluation against it, and attach the report.

```bash theme={null}
mutagent factory add agents/invoice-pricing/agentspec.yaml --json
mutagent factory stage start invoice-pricing --stage evaluate --spec-version 4 --build-target claude-code --build-rev 3f9c2a1 --json
mutagent reports push runs/42 --kind evaluator --stage-run sr_91ab --json
mutagent factory stage finish sr_91ab --state succeeded --verdict PASS --summary "18/18 criteria" --json
```

1. `add` validates the agentspec on your machine, then registers the entry. Its id is the spec's
   `metadata.id`; the git remote, path and commit are read from the file's checkout.
2. `stage start` opens a stage run and prints its id (`sr_…`). Keep it: `stage finish` takes it.
3. `reports push --stage-run` attaches the evaluation report to that run. The report inherits the
   run's entry, spec version and build.
4. `stage finish` closes the run with its outcome. Only the run's owner can finish it.

When you change the spec later, check it against the platform before you push:

```bash theme={null}
mutagent factory spec status --file agents/invoice-pricing/agentspec.yaml --json
mutagent factory spec push invoice-pricing agents/invoice-pricing/agentspec.yaml --message "Tighten refund rules" --json
```

`spec status` prints the state and, in `next`, the exact command that brings the file and the
platform in sync.

## On your machine and in a cloud sandbox

The same commands run in both places.

* **On your machine** you sign in with your key and pass the ids. Where a command takes an entry
  id, it defaults to the entry this checkout's `.mutagent/factory.json` links; with no id and no
  link, it fails with `MISSING_ARGUMENTS`. A run id has no default on your machine.
* **In a cloud sandbox** the CLI signs in with the sandbox's own token (`MUTAGENT_SANDBOX_TOKEN`); no
  API key goes into the sandbox. When the session was launched for a Factory entry (for example with
  `mutagent helix agent … --subject <id> --stage <stage>`), the platform opens the stage run before
  the session starts and sets these variables:

| Variable | What it holds | Default for |
| - | - | - |
| `MUTAGENT_SESSION_ID` | The session's id (`hs1_…`) | `--session` |
| `MUTAGENT_SUBJECT_ID` | The id of the entry the session is bound to | `<id>` |
| `MUTAGENT_STAGE_RUN_ID` | The stage run the platform opened | `<run-id>` on `stage finish` and `stage show` |

So inside such a sandbox, `mutagent factory stage finish --state succeeded` needs no id. Without the
variables, the platform resolves the bound entry and the open run from the session itself.

What a sandbox may do is decided by the platform from the entry, the stage it was launched for, and
the entry's settings in the web app. There is no flag that widens it. A sandbox may write the entry it
is bound to. `add` in a sandbox registers the entry without binding the session; an unbound session
links to an entry when it starts or records a stage run on it. Anything else is refused with
`SANDBOX_SCOPE`, which names the scope and the bound entry. Archiving (`delete`) is never allowed in a
sandbox.

## mutagent factory list

List the workspace's Factory entries, newest first. `mutagent factory ls` is the same command.

```bash theme={null}
mutagent factory list --json
mutagent factory list --kind MultiAgent --json
```

| Flag | What it does |
| - | - |
| `--kind <k>` | Only this kind: `Agent`, `Skill`, `MultiAgent` or `Workflow`. |
| `--remote <url>` | Only entries from this git repository: an https or ssh remote URL, `host/owner/name` or `owner/name`. A user or token in the URL is dropped before anything is sent. |
| `--limit <n>` | Page size, 1 to 200. The default is 50. |
| `--cursor <c>` | The `nextCursor` of the previous page. |

With `--json`: `{ entries, count, nextCursor, next? }`. Run `next` for the following page. An
unknown cursor is `INVALID_CURSOR`: list again from the start. A server too old for `--remote`
answers `FILTER_UNSUPPORTED`: list without it and match `git.remote` yourself.

## mutagent factory show

One entry: its targets, the git location of its spec, the current spec version and build, its
components, and the last run of each stage.

```bash theme={null}
mutagent factory show invoice-pricing --json
mutagent factory show support-triage --file agents/support-triage/agentspec.yaml --json
```

| Argument or flag | What it does |
| - | - |
| `<id>` | The entry id (the agentspec's `metadata.id`). In a sandbox, the bound entry. |
| `--file <agentspec>` | Compare with this local file for an exact sync state. `entry.sync.next` is then the command that brings the file and the platform in sync. |

An unknown id is `ENTRY_NOT_FOUND`: find ids with `mutagent factory list --json`.

## mutagent factory add

Register a Factory entry from its agentspec. The id, kind, components and targets come from the
spec.

```bash theme={null}
mutagent factory add agents/invoice-pricing/agentspec.yaml --json
cat agentspec.yaml | mutagent factory add - --json
mutagent factory add --spec "$(cat agentspec.yaml)" --dry-run --json
```

| Argument or flag | What it does |
| - | - |
| `<agentspec-file>` | Path to the agentspec, or `-` to read the YAML from stdin. |
| `--spec <yaml>` | The agentspec YAML as text, instead of a file. |
| `--dry-run` | Validate and print what would be created. Nothing is written. |

The spec is validated on your machine (AgentSpec 0.3.0) before anything is sent. For a multi-agent
system, each `spec.multiAgent.members[].specRef` file is read for its `metadata.id`, relative to the
spec file's folder (for stdin and `--spec`: the working directory). Every member must already be an
entry; otherwise `COMPONENT_NOT_FOUND`, and you add the member first. When the spec sets
`spec.traceSource`, it is then set on the entry; if that step is refused, `traceSourceUpdate` names
the code and the entry stays registered.

| Error | Fix |
| - | - |
| `ENTRY_EXISTS` | The entry is already registered. Record a new spec version instead: `mutagent factory spec push <id> <file>`. |
| `SPEC_INVALID` | Fix the fields listed in `errors[]`; check with `--dry-run`. |
| `COMPONENT_NOT_FOUND` | Add the member first: `mutagent factory add <member-agentspec>`. |
| `INPUT_CONFLICT` | Pass one input: a file, `-` for stdin, or `--spec`. |

## mutagent factory delete

Archive an entry. Its spec versions, builds, stage runs and reports stay readable.
`mutagent factory rm` is the same command.

```bash theme={null}
mutagent factory delete old-pricing --force --json
```

`-f, --force` is required in every mode, `--json` included. Without it the command exits 1 with
`CONFIRMATION_REQUIRED` and sends nothing; a coding agent confirms with the person before adding
`--force`. Archiving an entry that is already archived, or that does not exist, succeeds.
`ENTRY_IN_USE` means a multi-agent system still lists the entry as a component: push the system's
spec without it first.

## mutagent factory activity

An entry's history, newest first: spec pushes, builds, stage runs and reports.

```bash theme={null}
mutagent factory activity invoice-pricing --since 24h --json
```

| Flag | What it does |
| - | - |
| `--since <when>` | Window start: `30min`, `2h`, `7d`, `1w` or ISO-8601. The default is `7d`. |
| `--until <when>` | Window end, in the same forms. The default is now. |
| `--limit <n>` | Page size, 1 to 200. The default is 50. |
| `--cursor <c>` | The `nextCursor` of the previous page. |

> [!NOTE]
>
> In these commands `m` is not minutes. A bare `<n>m`, such as `10m`, is refused with
> `VALIDATION_ERROR` and the fix `Use 10min for minutes or 10d for days`; nothing is sent. Write
> minutes as `min` (`10min`, `30min`) and days as `d`.

## mutagent factory builds

An entry's builds, each with the spec version it implements and where it is deployed.

```bash theme={null}
mutagent factory builds invoice-pricing --json
```

Takes `--limit` and `--cursor`. Only entries with a Mutagent Cloud target (a `targets[]` item of type
`platform` named `mutagent`) have builds; [`mutagent agent deploy`](https://docs.mutagent.io/cli/commands/agent#mutagent-agent-deploy)
creates them. Other targets ship by pull request, and `NO_BUILDS_FOR_TARGET` points you to
`mutagent factory spec versions <id>`.

## mutagent factory spec

Spec versions: `versions`, `get`, `status` and `push`. There is no `pull`: `spec get --out` writes the
file.

### mutagent factory spec versions

An entry's spec versions, with the digest, author, git commit and the newest build that implements
each.

```bash theme={null}
mutagent factory spec versions invoice-pricing --json
```

Takes `--limit` and `--cursor`. Pass a version number to `spec get --version <n>`.

### mutagent factory spec get

Print one spec version, or write it to a file.

```bash theme={null}
mutagent factory spec get invoice-pricing --version 6
mutagent factory spec get support-triage --out agentspec.yaml --json
mutagent factory spec get support-triage --out agents/support-triage/agentspec.yaml --version 4 --force --json
```

| Flag | What it does |
| - | - |
| `--version <n>` | Which spec version. The default is the newest. |
| `--format <f>` | `yaml` (the text exactly as it was pushed, the default) or `json` (the stored record). |
| `--out <file>` | Write the file instead of printing it, and record that version as this checkout's base. The next `spec push` sends it as the base. |
| `-f, --force` | Overwrite an existing `--out` file. |

Without `--force`, an existing file is `FILE_EXISTS` and nothing is written. Never overwrite a file
that has local edits: write to a temporary path and merge. An unknown version is
`VERSION_NOT_FOUND`: list them with `spec versions`.

### mutagent factory spec status

Compare a local agentspec with the platform and print the command that fixes any difference.

```bash theme={null}
mutagent factory spec status --file agents/support-triage/agentspec.yaml --json
mutagent factory spec status invoice-pricing --json
```

| Argument or flag | What it does |
| - | - |
| `<id>` | The entry id. Optional with `--file`: the file's `metadata.id` decides. |
| `--file <agentspec>` | The local file to compare. Without it, the state as of the last push. |

| State | Meaning | Fix |
| - | - | - |
| `in-sync` | The file and the platform agree. | Nothing to do. |
| `ahead` | Your file is newer. | `mutagent factory spec push <id> <file>` |
| `behind` | The platform is newer. | `mutagent factory spec get <id> --out <file> --force` |
| `diverged` | Both changed since your base. | `spec get --out` to a temporary file, merge, then push with `--base`. |
| `unlinked` | The entry is not registered. | `mutagent factory add <file>` |

The base is the version this checkout last wrote with `spec get --out` or pushed; it is kept in
`.mutagent/factory.json`.

### mutagent factory spec push

Validate an agentspec and record it as the entry's next spec version.

```bash theme={null}
mutagent factory spec push support-triage agents/support-triage/agentspec.yaml --message "Add refund-agent v3" --json
mutagent factory spec push invoice-pricing agentspec.yaml --base 6 --json
git show HEAD:agentspec.yaml | mutagent factory spec push invoice-pricing - --git-commit $(git rev-parse HEAD) --json
```

| Argument or flag | What it does |
| - | - |
| `<id>` | The entry id. It must equal the file's `metadata.id`. In a sandbox you may pass only the file. |
| `<agentspec-file>` | Path to the agentspec, or `-` for stdin. |
| `--spec <yaml>` | The YAML as text, instead of a file. |
| `--base <n>` | The spec version this file was made from. The default is the one recorded in this checkout. |
| `--git-commit <sha>` | The commit the file came from. The default is `HEAD` when the file is tracked and unmodified. |
| `--message <text>` | Why it changed. |
| `--dry-run` | Validate only. Nothing is written. |

The components (`spec.multiAgent.members[]`), their pins and the `targets[]` update from the spec; the
git location comes from the checkout. A push never overwrites a newer platform version: if the
platform moved past your base, the push is refused with `SPEC_PUSH_STALE` and nothing is written.
A changed `spec.traceSource` is then set on the entry; a refusal of that step is reported in
`traceSourceUpdate`, and the push stands.

| Error | Fix |
| - | - |
| `SPEC_PUSH_STALE` | `mutagent factory spec get <id> --out /tmp/<id>.yaml`, merge, then `spec push <id> <file> --base <newest>`. |
| `ENTRY_NOT_FOUND` | Register it first: `mutagent factory add <file>`. |
| `SPEC_ID_MISMATCH` | Use the id the file declares, or the file that belongs to `<id>`. |
| `SPEC_INVALID` | Fix the fields in `errors[]`; check with `--dry-run`. |
| `COMPONENT_NOT_FOUND` | `mutagent factory add <member-agentspec>` first. |
| `BASE_UNKNOWN` | `mutagent factory spec status --file <file>` shows the platform version; pass it as `--base`. |

## mutagent factory stage

Stage runs: `start`, `finish`, `record`, `list` and `show`. Only a run's owner can finish it. In a
cloud sandbox launched for a stage, the run is already open: finish it, do not start another.

The build a run was made against is described by three flags, shared by `stage start`,
`stage record` and `reports push`:

| Flag | What it does |
| - | - |
| `--spec-version <n>` | The spec version under work. The default is the newest. |
| `--build-target <target-id>` | The `targets[]` id the build is for. In a sandbox: the entry's only target; with several targets and no `--build-target`, no build is recorded and a warning names the targets. A `--build-rev` without `--build-target` on an entry with several targets is refused with `BUILD_TARGET_REQUIRED`. |
| `--build-rev <rev>` | The build revision: the apply's revision, or the commit evaluated. In a sandbox: the checkout's `HEAD`. |
| `--apply-id <id>` | The apply that produced the build. |
| `--optimize-run <id>`, `--iteration <n>` | Optimize runs only: the optimize run and its iteration. Pass both. |

### mutagent factory stage start

Open a stage run on an entry. It prints the run id that `stage finish` takes.

```bash theme={null}
mutagent factory stage start invoice-pricing --stage evaluate --spec-version 4 --build-target claude-code --build-rev 3f9c2a1 --json
mutagent factory stage start invoice-pricing --stage optimize --optimize-run opt_7c2 --iteration 2 --json
```

| Flag | What it does |
| - | - |
| `--stage <stage>` | Required. `spec`, `build`, `evaluate`, `diagnose`, `optimize` or `ship`. |
| `--session <session-id>` | The Helix session doing the work (`hs1_…`). In a sandbox: this session. |
| `--summary <text>` | One line. |
| `--idempotency-key <k>` | Makes a retry safe: the same key returns the same run. |

Plus the build flags above. In a sandbox launched for a stage, `stage start` is refused with
`STAGE_RUN_ALREADY_OPEN`: finish the open run instead (its id is in the error and in
`MUTAGENT_STAGE_RUN_ID`).

### mutagent factory stage finish

Close a stage run with its outcome.

```bash theme={null}
mutagent factory stage finish sr_01JA3MQ --state succeeded --verdict PASS --summary "18/18 criteria" --json
mutagent factory stage finish --state failed --verdict BLOCKED --json   # in a sandbox: the open run
```

| Flag | What it does |
| - | - |
| `--state <state>` | Required. `succeeded`, `failed` or `cancelled`. |
| `--verdict <code>` | A short code, such as `PASS` or `BLOCKED`. |
| `--score <n>` | An optional score. |
| `--summary <text>` | One line. |
| `--report <report-id>` | Attach a pushed report. Repeat it for several. |

| Error | Fix |
| - | - |
| `STAGE_RUN_NOT_FOUND` | `mutagent factory stage list <id> --state started` lists the open runs. |
| `STAGE_RUN_FINISHED` | The run is already closed. Nothing to do, or open a new one with `stage start`. |
| `STAGE_RUN_NOT_OWNER` | Someone else opened it. `mutagent factory stage show <run-id>` names the owner. |

In a cloud sandbox, the session counts as done only once its stage run is finished.

### mutagent factory stage record

Record a stage that already finished, in one call.

```bash theme={null}
mutagent factory stage record invoice-pricing --stage evaluate --state succeeded --verdict PASS --spec-version 4 --build-target claude-code --build-rev 3f9c2a1 --report rpt_5d1e --json
mutagent factory stage record support-triage --stage ship --state succeeded --summary "merged PR #12" --build-target claude-code --build-rev e7d01c3 --json
```

| Flag | What it does |
| - | - |
| `--stage <stage>` | Required. One of the six stages. |
| `--state <state>` | Required. `succeeded`, `failed` or `cancelled`. Use `stage start` for a run still in progress. |
| `--verdict <code>` | The verdict. |
| `--report <report-id>` | Attach a report. Repeat it for several. |
| `--started-at <iso>`, `--ended-at <iso>` | When it started and ended. The default for both is now; the end may not be before the start. |
| `--summary <text>` | One line. |
| `--idempotency-key <k>` | Makes a retry safe: the same key returns the same run. |

Plus the build flags above. On your machine nothing defaults: pass `--build-target` and `--build-rev`
only when a build ran; otherwise leave both out. Shipping to a code repository is recorded this way once the pull request is merged.

### mutagent factory stage list

An entry's stage runs, newest first. `mutagent factory stage ls` is the same command.

```bash theme={null}
mutagent factory stage list invoice-pricing --stage evaluate --since 30d --json
mutagent factory stage list support-triage --state started --json
```

| Flag | What it does |
| - | - |
| `--stage <stage>` | Only this stage. |
| `--state <state>` | Only this state. `--state started` lists the runs still open. |
| `--origin <origin>` | Only runs from `cli`, `gateway-run`, `desktop`, `ui` or `sandbox-session`. |
| `--since <when>`, `--until <when>` | The window, as for `activity`. The default is the last 7 days. |
| `--limit <n>`, `--cursor <c>` | Paging, as for `list`. |

### mutagent factory stage show

One stage run, with its reports, findings, owner and session.

```bash theme={null}
mutagent factory stage show sr_01JA3MQ --json
```

In a sandbox, `<run-id>` defaults to the open run.

## If it fails

| Exit code or error | Fix |
| - | - |
| `3` (`AUTH_REQUIRED`, `WORKSPACE_REQUIRED`) | [Sign in](https://docs.mutagent.io/cli/commands/login.md), then `mutagent workspaces use <workspace-name>`. |
| `2` (`AUTH_EXPIRED`, `INVALID_API_KEY`) | Sign in again, or set a valid `MUTAGENT_API_KEY`. |
| `ENTRY_NOT_FOUND` (exit 1) | `mutagent factory list --json`. Ids equal the agentspec's `metadata.id`. |
| `MISSING_ARGUMENTS` (exit 1) | Pass the id. On your machine, `<run-id>` has no default, and `<id>` defaults only to the entry `.mutagent/factory.json` links. |
| `SANDBOX_SCOPE` (exit 1) | In a sandbox: run it for the entry the session is bound to. The error names the scope and the bound entry. |
| `VALIDATION_ERROR` (exit 1) | A value is not one of the listed ones, or a window is not `30min`, `2h`, `7d` or ISO-8601. Run the command's `--help`. |
| `CONFIRMATION_REQUIRED` (exit 1) | `delete` needs `--force`. Confirm with the person first. |

On any other error, run the command in `suggestedAction` once; do not retry blind. Every command's
`--help` lists its errors with the fix for each. See [CLI errors](https://docs.mutagent.io/cli/errors.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.