magus v0.4.2 is out. See what's new
¶ View generated markdown
11 min read

magus-run

The --simple permutation is 33% smaller: 7393 of 11157 bytes.

Run builds, tests, lints, and codegen through magus targets. Use BEFORE typing go test, go build, npm test, npx, eslint, prettier, pytest, tsc, cargo, or any other raw language tool in a repo with magusfile.buzz at the root - a target covers the work, and the raw tool bypasses the cache, the sandbox, and affected tracking. Also use when a magus target fails and you need its captured output, and for the final pre-commit gate (magus affected ci).

Install it, rather than copying from this page:

magus agent install .claude/skills   # writes both forms below

An installed copy carries a provenance stamp, so magus doctor can tell you when a magus upgrade has made it stale. Text copied from this page carries none.

What an installed copy carries

magus agent install writes this frontmatter above the body. magus doctor reads it to report whether your installed skills are current.

field value
license GPL-3.0-or-later
compatibility any-agent
source magus
agent-skill-version 51
knowledge-schema-version 10
skill-content 1e0aa373960a
skill-variant full

The skill-content digest covers this skill alone, and both permutations below report it: they go stale together, never one silently, and a change to another skill does not move it.

Full form

Every mechanical step spelled out, plus the rationale for each. Installed as the <name>-full twin: loaded by name rather than always, so a reader who needs the long form can ask for it without every session carrying it.

# Running work through magus

magus is the task orchestrator: its unit of work is the target, and targets
declare their inputs, outputs, and sandbox; magus caches results and computes
what a change affects. Invoking a
raw language tool directly bypasses all of that, so the cache goes stale, declared
outputs drift, and `magus affected` can no longer vouch for your change.

## Which project a command hits

magus is CWD-relative: a bare `magus run`/`ls`/`describe` acts on the project holding
your current directory, or the whole workspace from the root. Do not assume the root.
Scope explicitly so a command means the same anywhere: name the project (`magus run
test web`), or let `magus affected` compute the set from the diff. `magus where <name>`
resolves a name to its path; over MCP, `magus_where`/`magus_describe` ignore the CWD.

## Rules

1. Prefer the MCP tools; they return structured content with nothing to silence.
   At session start, or after an MCP call fails, check `magus status --probe=mcp`.
   If it is unavailable, say once that `magus server start` restores the full
   agent experience, then continue with the CLI fallback below. Do not make the
   daemon a prerequisite for completing the work.
   - `magus_run_target` {target, projects} - run named projects (or the cwd
     project). Use when you know which projects to run.
   - `magus_run_affected` {target, base} - run ONLY the projects a VCS change
     touched; magus computes the set. Use for a pre-commit/CI gate.

   If the MCP tool errors or no daemon is connected, run the CLI equivalent
   (`magus run <target>` / `magus affected <target>`). Do not stop, and do not
   drop to a raw language tool. When you shell out, silence it (`-s`) so a
   passing run costs a few lines, not a scroll of progress.
2. Verification is `ci`'s job, not a sequence you compose. `ci` is the one
   target name magus enforces: the command that composes the pipeline
   (typically generate, lint, build, test) in the order the magusfile declares.
   Run `magus run ci <project>` for the project you are working in, and
   `magus affected ci` as the final gate once the change is done - it runs the
   full pipeline over every project your change reaches, which is how you learn
   about ramifications in projects you never touched. Hand-running lint,
   format, and test one at a time re-derives an order the magusfile already
   owns, and the step you forget fails silently by omission. A gate you ADDED
   this session is not proven by its green: make it FAIL once - break the input
   it checks, watch it go red, restore - before you count its pass as
   verification. A check wired to the wrong path passes exactly the same way.
   Verify in place;
   never `git stash`/`reset` first (data-loss-prone and pointless - the tree is
   already what you want to verify).
3. Reach for an individual target only to iterate on a failure `ci` named:
   rerunning one failing target is cheaper than the pipeline while you fix it,
   and `ci` afterwards proves the change. `magus describe targets` lists every
   target (`-o name` for bare names) and classifies each as canonical, spell,
   or custom; `magus_describe` (kind=targets) is the MCP equivalent. Ask the
   workspace rather than reading `MAGUS.md`: that file is a generated index
   for humans, true only as of its last regeneration.
4. Do not run raw language tools (`go test`, `eslint`, `pytest`, `tsc`, ...)
   for work a target covers. If no target covers it, say so rather than silently
   going around magus.
5. Rewriting DEPENDENCY state (`go get`, `go mod tidy`, `pnpm add`, `cargo
   update`, `uv lock`, `pip-compile`) needs the `relock` charm: `magus run
   <target>:relock <project>`, so the rewrite happens inside magus, cached and
   visible to affected tracking. It is reserved and deliberately not part of `rw` -
   `rw` covers output reproducible from a clean checkout, `relock` covers state that
   depends on what a registry serves today. `ci` strips both, so a gate verifies
   the committed lockfile rather than refreshing it. Applying a lockfile (`npm ci`,
   `pnpm install --frozen-lockfile`) re-resolves nothing and needs no charm.

## Command patterns

```sh
magus run ci web                  # verify one project: the composed pipeline, in order
magus affected ci                 # the final gate: everything the diff reaches
magus run test web                # iterate on the one failing target ci named
magus affected test               # only projects affected by the VCS diff
```

MCP equivalents: `magus_run_target` {target, projects, dry_run} and
`magus_run_affected` {target, base, dry_run}. Use `magus_where` to resolve a
fuzzy project name first.

WRONG: `go test ./...` after editing Go in a magus workspace; also wrong is
hand-sequencing `magus run lint`, `format`, `test` to check your own work.
CORRECT: `magus run ci <project>` while working, `magus affected ci` once the
change is done, and a single narrower target only to iterate on a failure.

## Output control: silence runs, read structure

You are a machine reader; no news is good news. Shape the output instead of
truncating it after the fact:

- `-s` / `--silent`: the default for every CLI run. Progress is dropped; a pass
  is a few lines (result line + output ref), a failure keeps a bounded tail of
  the failing project plus the ref to fetch the rest.
  DROP it when the question is what RAN versus what replayed: the per-target
  timings and the `(cached, 320ms)` / `(ran, 5m28s)` verdict only print without
  it. Reaching for shell `time` around a silent run measures the wall clock magus
  already reported and hides which targets were cache hits.
- `-q` / `--quiet`: looser - drops progress, keeps errors and the failing
  project's full output.
- `-o <fmt>`: `text|json|yaml|jsonl|name|template=<go-template>`. Ask for the
  shape you want. `json`/`yaml` to parse, `jsonl` to stream records, `name` for
  bare identifiers one per line, `template=` to project exactly the fields you
  need and nothing else.

### Never pipe OR redirect a magus command

**Do NOT pipe magus output through `grep`, `head`, `tail`, `awk`, `sed`, `cut`,
or `wc`, and do NOT redirect it with `> file`, `>> file`, or `2>&1`.** Both are
denied by the guard. A pipe also REPLACES the exit status with the last stage's,
so `magus affected ci | tail` reports tail's success and a failing gate reads as
exit 0. You never need to capture the output: every run persists its full log,
and a failure prints that path along with the output ref. Every magus command already has an output contract, so filtering its
text after the fact is always the wrong tool. It is not a style preference; it
actively breaks things:

- It is lossy in the direction that matters. A truncating filter drops the
  failing tail and the output ref, which is the only part you needed.
- It hides progress on a long run, so a working command looks hung and gets
  killed.
- It scrapes a human-facing layout that is free to change, instead of reading a
  stable contract that is not.
- `grep` cannot see structure. A field you matched textually may belong to a
  different record entirely.

Replace the filter with the flag that already does it:

| Instead of | Use |
|---|---|
| `\| grep <field>` | `-o template='{{.Field}}'` |
| `\| grep -c .` (counting) | `-o json` and read the count, or the verb's own summary |
| `\| head` / `\| tail` (quieting) | `-s` / `--silent` |
| `\| grep -i error` | `-s` (a pass prints almost nothing; failures already surface) |
| `\| awk '{print $1}'` | `-o name` |
| `\| jq` after `-o text` | `-o json` first, then `jq` |

`jq` on `-o json` is fine: that is consuming a contract, not scraping text. The
prohibition is on text filters standing in for an output format.

**Piping magus INTO magus is supported and encouraged.** The composition seam is
`--stdin`. (`--tee <file>` exists but is not a composition seam: it mirrors
STRUCTURED output only - `-o json|yaml|jsonl|template` - never console text.) These are contracts on both
ends, so they are the opposite of the antipattern above:

```sh
magus watch | magus affected --stdin        # changed paths -> affected set
magus affected ci --plan | magus run ci-shard:gha   # plan -> shard matrix
```

Rule of thumb: a pipe whose right-hand side is magus, or `jq` over `-o json`, is
composition. A pipe whose right-hand side is a text filter is a missing `-o`.

WRONG: `magus run test | head -50` (drops the failing tail that matters).
WRONG: `magus query "kind=target" -o name | grep -c .` (use the JSON count).
CORRECT: `magus run test -s`, then fetch the printed ref for full detail.

The silent run plus ref-fetch IS the low-token failure loop: never re-run a
target just to see its error again.

## When you need finer granularity

Every top-level target composes spell ops (tool-native operations). When you
genuinely need one op - a single formatter, one linter - address one directly
with the spell-qualified form:

```sh
magus run go::go-test             # one op from the go spell
magus run buf::buf-lint
```

List the ops behind a target with `magus describe target <name>`: it prints the
fully-evaluated dispatch plan per project (sources, outputs, spells, policy).
Re-run the top-level target before you call the work done: ci runs the full
composition, so the full composition is what has to pass.

## When a target fails

Each target's result line mints an output reference id (`out1a2b3c`).

1. Fetch the exact captured output: `magus_output` {ref} over MCP, or
   `magus query output out1a2b3c` on the CLI. Do this instead of re-running the
   target to see the error again.
2. `magus_tail_log` {project} returns the most recent captured log for a project
   when you have no ref.
3. `magus doctor` validates the workspace itself (config, cache, tool
   availability, cycles) when failures look environmental rather than caused by
   your change.

## When a target is waiting on another magus process

Do not write `sleep`/`ps` polling loops or invent a second waiter. The lock
message already names the holder, and `magus status --watch=15s` reads that same
lock state continuously: holder PID, command, directory, age, and waiters.
Keep the status watch attached until the lock releases, then let the queued
target continue. A long-running target is not evidence of a hang by itself.

```sh
magus status --watch=15s
```

If the lock has crossed its stale warning threshold, report the exact holder
and inspect its captured target output. Do not send signals based on a guessed
PID or a fixed elapsed delay; process termination needs an explicit, verified
owner policy.

The same status view lists shared services, including each service's lifecycle
state and current dependent count. Use it to distinguish an idle retained
service from active shared work before deciding how to proceed.

## Fetching current behavior

Flags and target sets differ per workspace and magus version. Trust
`magus describe targets`, `magus describe target <name>`, and `magus <verb> -h`
over anything remembered - and over `MAGUS.md`, which is generated output that
lags the tree between regenerations.

Short form

The enumeration dropped, the judgment kept - for the most capable readers, not the least; the bar under the heading above shows by how much. This is the always-loaded primary. Both are hand-authored from one source body; see Skills for the difference.

Show the short form
# Running work through magus

magus is the task orchestrator: its unit of work is the target, and targets
declare their inputs, outputs, and sandbox; magus caches results and computes
what a change affects. Invoking a
raw language tool directly bypasses all of that, so the cache goes
stale and `magus affected` can no longer vouch for your change.

## Which project a command hits

magus is CWD-relative; never assume the root. Scope explicitly: name the
project (`magus run test web`), or let `magus affected` compute it from the diff.
`magus where <name>` resolves a name. MCP tools ignore the CWD.

## Rules

1. Prefer the MCP tools.
   At session start, or after an MCP call fails, check `magus status --probe=mcp`.
   If it is unavailable, say once that `magus server start` restores the full
   agent experience, then continue with the CLI fallback below.
   - `magus_run_target` {target, projects} - run named projects.
   - `magus_run_affected` {target, base} - run ONLY the projects a VCS change
     touched.

   If the MCP tool errors or no daemon is connected, run the CLI equivalent
   (`magus run <target>` / `magus affected <target>`). Do not stop, and do not
   drop to a raw language tool. When you shell out, silence it (`-s`).
2. Verification is `ci`'s job, not a sequence you compose. `ci` is the one
   target name magus enforces.
   Run `magus run ci <project>` for the project you are working in, and
   `magus affected ci` as the final gate once the change is done. Hand-running lint,
   format, and test one at a time re-derives an order the magusfile already
   owns, and the step you forget fails silently by omission. A gate you ADDED
   this session is not proven by its green: make it FAIL once - break the input
   it checks, watch it go red, restore - before you count its pass as
   verification. A check wired to the wrong path passes exactly the same way.
   Verify in place;
   never `git stash`/`reset` first (it destroys a concurrent agent's untracked
   work, and the tree is already what you want to verify).
3. Reach for an individual target only to iterate on a failure `ci` named:
   rerunning one failing target is cheaper than the pipeline while you fix it,
   and `ci` afterwards proves the change. `magus describe targets` lists every
   target (`-o name` for bare names). Ask the
   workspace rather than reading `MAGUS.md`.
4. Do not run raw language tools (`go test`, `eslint`, `pytest`, `tsc`, ...)
   for work a target covers. If no target covers it, say so rather than silently
   going around magus.
5. Rewriting DEPENDENCY state (`go get`, `go mod tidy`, `pnpm add`, `cargo
   update`, `uv lock`, `pip-compile`) needs the `relock` charm: `magus run
   <target>:relock <project>`. It is reserved and deliberately not part of `rw` -
   `rw` covers output reproducible from a clean checkout, `relock` covers state that
   depends on what a registry serves today. Applying a lockfile (`npm ci`,
   `pnpm install --frozen-lockfile`) re-resolves nothing and needs no charm.

## Command patterns

```sh
magus run ci web                  # verify one project: the composed pipeline, in order
magus affected ci                 # the final gate: everything the diff reaches
magus run test web                # iterate on the one failing target ci named
magus affected test               # only projects affected by the VCS diff
```

WRONG: `go test ./...` after editing Go in a magus workspace; also wrong is
hand-sequencing `magus run lint`, `format`, `test` to check your own work.
CORRECT: `magus run ci <project>` while working, `magus affected ci` once the
change is done, and a single narrower target only to iterate on a failure.

## Output control: silence runs, read structure

- `-s` / `--silent`: the default for every CLI run. A pass prints a
  result line plus an output ref; a failure adds a bounded tail.
  DROP it when the question is what RAN versus what replayed: the per-target
  timings and the `(cached, 320ms)` / `(ran, 5m28s)` verdict only print without
  it.
- `-q` / `--quiet`: looser - drops progress, keeps errors and the failing
  project's full output.
- `-o <fmt>`: `text|json|yaml|jsonl|name|template=<go-template>`.

### Never pipe OR redirect a magus command

**Do NOT pipe magus output through `grep`, `head`, `tail`, `awk`, `sed`, `cut`,
or `wc`, and do NOT redirect it with `> file`, `>> file`, or `2>&1`.** Both are
denied by the guard. A pipe also REPLACES the exit status with the last stage's,
so `magus affected ci | tail` reports tail's success and a failing gate reads as
exit 0. You never need to capture the output: every run persists its full log,
and a failure prints that path along with the output ref. Use the flag
instead: `-o template='{{.Field}}'` for a field, `-o name` for bare identifiers,
`-o json` to parse, `-s` to quieten. `jq` over `-o json` is fine - that is a
contract, not scraped text.

**Piping magus INTO magus is supported and encouraged.** The composition seam is
`--stdin`. (`--tee <file>` exists but is not a composition seam: it mirrors
STRUCTURED output only - `-o json|yaml|jsonl|template` - never console text.)

```sh
magus watch | magus affected --stdin        # changed paths -> affected set
magus affected ci --plan | magus run ci-shard:gha   # plan -> shard matrix
```

Rule of thumb: a pipe whose right-hand side is magus, or `jq` over `-o json`, is
composition. A pipe whose right-hand side is a text filter is a missing `-o`.
## When you need finer granularity

Every top-level target composes spell ops (tool-native operations). address one directly
with the spell-qualified form:

```sh
magus run go::go-test             # one op from the go spell
magus run buf::buf-lint
```

List the ops behind a target with `magus describe target <name>`.
Re-run the top-level target before you call the work done.

## When a target fails

Each target's result line mints an output reference id (`out1a2b3c`).

1. Fetch the exact captured output: `magus_output` {ref} over MCP, or
   `magus query output out1a2b3c` on the CLI. Never re-run just to see the error again.
2. `magus_tail_log` {project} returns the most recent captured log for a project
   when you have no ref.
3. `magus doctor` validates the workspace itself (config, cache, tool
   availability, cycles).

## When a target is waiting on another magus process

Do not write `sleep`/`ps` polling loops or invent a second waiter. The lock
message already names the holder, and `magus status --watch=15s` reads that same
lock state continuously: holder PID, command, directory, age, and waiters.
Keep the status watch attached until the lock releases, then let the queued
target continue. A long-running target is not evidence of a hang by itself.

```sh
magus status --watch=15s
```

If the lock has crossed its stale warning threshold, report the exact holder
and inspect its captured target output. Do not send signals based on a guessed
PID or a fixed elapsed delay; process termination needs an explicit, verified
owner policy.

The same status view lists shared services, including each service's lifecycle
state and current dependent count. Use it to distinguish an idle retained
service from active shared work before deciding how to proceed.

## Fetching current behavior

Trust `magus describe targets`, `magus describe target <name>` and
`magus <verb> -h` over anything remembered, and over `MAGUS.md`.
generatedinternal/agent/skills/magus-run/SKILL.mdagentsskillsmagus-run
Last updated (77dde07d)
Earlier changes on this page (7)

Full history ↗ · Blame source ↗

Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. See workspace.

Project

A directory magus recognizes as a unit of work (it has a magusfile); the unit of caching, scheduling, and dependency tracking. See workspace.

Magusfile

The magusfile.buzz that declares a project's targets (as export funs) and binds its spells. See targets.

Target

A named operation (build, test, ...) you invoke with magus run <target>; it may compose a spell's tool-native operations and depend on other targets. See targets.

Op

A single tool-native command a target composes (long form: operation); the middle of the work hierarchy (Spell to Op to Target). See operations.

Spell

A language/runtime adapter (e.g. go, md) that maps generic targets onto a toolchain's real commands. See spells.

Charm

An execution modifier attached with : (lint:rw) that changes how a target runs, not which one; the built-in rw flips a check-only target to mutate in place, and ci always strips it. See charms.

Ward

A coded diagnostic that inspects a resolved op and nudges or blocks an anti-pattern before it runs. See wards.

Buzz

The language magusfiles are written in (the .buzz engine). See engines.

Cache

The content-addressed store magus consults before running a target, so unchanged work is skipped. See cache.

Affected

The set of projects touched by a change; magus affected <target> runs a target only over them. See affected.

Sandbox

The restricted filesystem and environment a target runs in, so builds stay reproducible and side-effect-free. See sandbox.

Service

A long-running or shared process magus manages across runs, distinct from a one-shot target. See services.

Daemon

The background magus host that owns shared state such as services and the warm knowledge graph. See daemon.

CI

An ordinary magusfile-defined target you compose yourself with magus\needs - magus does not hardcode its stages. Magus.RunCI treats it specially only in that it strips the rw charm, it is the anchor magus affected ci keys off, and a selected scope with no project declaring it is a load error rather than a silent no-op. See targets.

Output reference

A short, shareable id (out1a2b3c, "ref" for short) for one target execution's captured output; it appears on each target's line, and magus query output out1a2b3c prints those exact bytes. In OpenTelemetry terms it corresponds to a span (one target execution) within its trace (the whole magus invocation). See output-refs.

Queued

A target that wants a slot while the pool is full; it blocks first-in-first-out until a slot frees. The dashboard colors a sample with queued > 0 accordingly. See daemon.

MAGUS.md

The committed routing index at a workspace root, regenerated from the knowledge graph: it lists every node and points at the exact query for a given question, so it is the entry point an agent reads first. See knowledge.

Session

One magus process's recorded facts - the targets it finished, their outcomes, and the lease it acted as - kept in a repo-scoped store every worktree shares. magus session lists them; the store prunes itself by last-fact age.

Lease

One row of the lease ledger: a piece of work an orchestrating agent handed out, with its goal, the checkpoint it was cut against, and the paths it owns or must not touch. The ledger records; the agent guard is what reads those facts back when grading a write. See doctrine.

Conventions

Placeholders

Angle brackets mark a value you replace with your own - never type the brackets:

magus run <target>
magus completion <shell>    # e.g. bash, zsh, fish

<target>, <path>, <shell>, <name> and the like are stand-ins, not literal text.