magus-run
Short form: 7924 bytes, 45% smaller than the full form's 14551.
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). Do NOT use to query the graph (magus-query) or to write Buzz (magus-buzz-lang).
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 |
147 |
knowledge-schema-version |
24 |
skill-content |
aa637217b358 |
skill-variant |
full |
The skill-content digest covers this skill alone, and both forms below report it: they go stale together, never one silently, and a change to another skill does not move it.
The two forms
Both are hand-authored from one source body. The short form is the always-loaded primary - the enumeration dropped, the judgment kept, for the most capable readers rather than the least. The full form is its <name>-full twin, loaded by name when a reader wants the rationale. The bar above shows how much shorter the primary is; switch between them here to see exactly what it gave up. See Skills for how to choose.
magus agent install --tar | tar -xO -f - magus-run/SKILL.md
# Running work through magus
magus: task orchestrator; unit of work: target.
Targets declare inputs, outputs, sandbox; magus caches results, computes what change affects.
Raw language tool bypasses all that: cache goes stale, `magus affected` cannot vouch for change.
## Project scope
magus is CWD-relative -> never assume root. Scope explicitly:
- Name project: `magus run test web`.
- Or `magus affected` computes set from diff.
`magus where <name>`: name -> path. MCP tools ignore CWD.
`--root <path>` (or `-C`): where walk STARTS: any directory, not workspace or checkout.
Where it lands is separate: nearest `magus.yaml` wins, else outermost contiguous run of `magusfiles/`, `magusfile.buzz` or `go.mod`.
Binary run by absolute path does NOT set working directory: walks up from cwd -> pass `--root` when you mean elsewhere.
## How to run work
1. Prefer MCP tools; call exposed tool directly. If missing or call fails -> CLI fallback below.
- Do not gate that choice on `magus status --probe=mcp`: tests loopback HTTP; host may use stdio or server Unix socket.
- `magus status --probe=readiness`: checks workspace loaded on server socket; does not test host MCP registration.
- Hosts manage own connection; never start server for agent.
- `client` (`magus\run`): run named projects, same arguments as `magus run`.
- `client` (`magus\affected`): projects VCS change touched; returns set, does not run it.
`client` bounded at 10 minutes when called directly; host supporting MCP tasks can run it as task without bound.
Long run (full `ci`, gate) -> CLI unless host runs `client` as task.
If MCP tool errors or absent -> CLI equivalent:
- `magus run <target>`: run target.
- `magus affected list`: set; `magus affected <target>`: run it.
- Silence with `-s`. Do not stop; do not drop to raw language tool.
2. Verification is `ci`'s job, not sequence you compose; `ci` is only target name magus enforces.
- `magus run ci <project>` for project you work in.
- `magus affected ci`: final gate once change done.
- Never hand-run lint, format, test one at a time: re-derives order magusfile owns; forgotten step fails silently by omission.
- Gate you ADDED this session not proven by its green. Make it FAIL once (break input it checks, watch red, restore) before counting its pass; check wired to wrong path passes same way.
- Verify in place; never `git stash`/`reset` first: destroys concurrent agent's untracked work, and tree already is what you verify.
3. Individual target only to iterate on failure `ci` named: narrow it as "When a target fails" says; `ci` afterwards proves change. `magus describe targets` lists every target (`-o name` for bare names). Ask workspace; do not read `MAGUS.md`.
4. Never raw language tools (`go test`, `eslint`, `pytest`, `tsc`, ...) for work target covers. If no target covers it, say so; never silently go around magus.
5. Rewriting DEPENDENCY state needs `update` charm: `magus run <target>:update <project>`; covers `go get`, `go mod tidy`, `pnpm add`, `cargo update`, `uv lock`, `pip-compile`.
- `update` reserved, not part of `rw`. `rw`: output reproducible from clean checkout; `update`: what registry serves today.
- Applying lockfile (`npm ci`, `pnpm install --frozen-lockfile`) re-resolves nothing, 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 run test web -- -k 'name' # rerun only the failing tests (pytest filter shown)
magus affected test # only projects affected by the VCS diff
```
Wrong: `go test ./...` after editing Go; hand-sequencing `magus run lint`, `format`, `test` to check own work.
Right: `magus run ci <project>` while working; `magus affected ci` once done.
## Output control
- `-s` / `--silent`: default for every CLI run. Pass: one `ref` line; failure adds bounded tail. DROP it when question is what RAN versus replayed: per-target timings and `(cached, 320ms)` / `(ran, 5m28s)` verdict print only without it.
- `-q` / `--quiet`: looser; drops progress, keeps errors and failing project's full output.
- `-o <fmt>`: `text|json|yaml|jsonl|name|template=<go-template>`.
### Never pipe or redirect magus
Never pipe magus output through `grep`, `head`, `tail`, `awk`, `sed`, `cut`, `wc`. Never redirect with `> file`, `>> file`, `2>&1`. Guard denies both.
- Pipe REPLACES exit status with last stage's: `magus affected ci | tail` reports tail's success -> failing gate reads as exit 0.
- Never need to capture output: every run persists full log; failure prints path with output ref.
Flag instead:
- `-o template='{{.Field}}'`: field.
- `-o name`: bare identifiers; `-o json`: parse.
- `-s`: quieten.
`jq` over `-o json` fine: contract, not scraped text.
Piping magus INTO magus supported, encouraged; composition seam: `--stdin`.
`--tee <file>` not composition seam: 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 --stdin # plan -> run its shards
```
Pipe into magus, or `jq` over `-o json`: composition. Pipe into text filter: missing `-o`.
Backgrounded run's capture is magus output too: grepping host's task file hits `capture-filter` guard rule. Background as `-o jsonl --tee <file>` -> contract you can `jq`; otherwise read file whole.
## When you need finer granularity
Every top-level target composes spell ops (tool-native operations); address one op with spell-qualified form:
```sh
magus run go::go-test # one op from the go spell
magus run buf::buf-lint
```
Ops behind target: `magus describe target <name>`.
Re-run top-level target before calling work done.
## When target fails
Each target's result line mints output reference id (`out1a2b3c`).
1. Fetch exact captured output: `client` (`magus\output`) over MCP, or `magus query output out1a2b3c` on CLI. Never re-run to see error again.
2. No ref -> find it in minting run: every `magus run` prints one per target; `magus session` lists recent invocations with targets they ran.
3. `magus doctor` validates workspace itself (config, cache, tool availability, cycles).
Fix a failed full run by narrowing, not by repeating it:
1. Read the failure from its ref and list the failing tests.
2. Rerun only those with the test runner's own filter, passed after `--`, until they
pass: `magus run test <project> -- <filter>`. Examples by runner:
- Go (go test): `-- -run 'TestA|TestB'`
- pytest: `-- -k 'name'`
- Jest or Vitest: `-- -t 'name'`
- cargo test: `-- name`
3. Run the full target ONCE more. A full run after a failed full run, with nothing
narrowed between them, reports nothing new.
A test known to fail for an outside reason is named once and left out of every rerun.
Run generators before the full test run, so a drift test does not fail for nothing.
## When another magus process holds project
Run whose project lock or machine budget another magus invocation holds: exits 75 at once, naming holder.
- Never write `sleep`/`ps`/`pgrep` polling loops; guard denies `pgrep`, `pidof`, `ps`.
- `magus status --watch=15s`: reads lock state continuously: holder PID, command, directory, age. Re-run once lock releases.
- Long-running holder alone: not evidence of hang.
```sh
magus status --watch=15s
```
If lock crossed stale warning threshold -> report exact holder, inspect its captured target output.
Never signal guessed PID or act on fixed elapsed delay; process termination needs explicit, verified owner policy.
## Current behavior
Trust `magus describe targets`, `magus describe target <name>`, `magus <verb> -h` over memory and `MAGUS.md`.
magus agent install --tar | tar -xO -f - magus-run-full/SKILL.md
# Running work through magus
magus is the task orchestrator, and its unit of work is the target. Targets declare
their inputs, outputs and sandbox. magus caches results and computes what a change
affects. A raw language tool bypasses all of that, so the cache goes stale, declared
outputs drift, and `magus affected` can no longer vouch for your change.
## Contents
- Which project a command hits
- How to run work
- Command patterns
- Output control: silence runs, read structure
- When you need finer granularity
- When a target fails
- When another magus process holds the project
- Fetching current behavior
## 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, `client` (`magus\where`, the project that contains a directory) ignores the CWD.
`--root <path>`, or `-C` after make's idiom, sets where that walk STARTS. Its argument
is a plain path: any directory, holding one file or none, nested or not. It is not a
workspace and not a checkout; calling it either leads a reader to think it must be
one.
What the walk FINDS is separate:
1. The nearest `magus.yaml` wins.
2. Absent any, the outermost CONTIGUOUS run of `magusfiles/`, `magusfile.buzz` or
`go.mod` wins.
It can resolve somewhere other than the path you passed, or resolve nothing.
Two consequences worth knowing before you debug one. Running a binary by
absolute path does NOT set its working directory, so `/elsewhere/magus run build .`
still walks up from YOUR cwd and can act on a tree you never named. And nearest-wins
means a directory holding its own `magus.yaml` inside a larger checkout resolves to
itself, so where a command lands is a question about markers on disk, never about the
VCS.
## How to run work
1. Prefer the MCP tools; they return structured content with nothing to silence.
Call an exposed MCP tool directly. If it is missing or its call fails, use the
CLI fallback below.
- Do not gate that choice on `magus status --probe=mcp`. It tests loopback HTTP,
while a host may use stdio or the server's Unix socket.
- `magus status --probe=readiness` checks that this workspace is loaded on the
server socket. It does not test the host's MCP registration.
- Hosts manage their own connection; never start a server for an agent.
Do not make the connection a prerequisite for completing the work.
- `client` (`magus\run`): run named projects, with the same arguments as `magus run` (or the cwd
project). Use when you know which projects to run.
- `client` (`magus\affected`): the projects a VCS change touched. It
returns the set and does not run it. The gate is `magus affected ci`.
`client` is bounded at 10 minutes when called directly. A host that
supports MCP tasks can run it as a task without that bound. Send a long run (a
full `ci`, a gate) to the CLI unless your host runs `client` as a task.
If the MCP tool errors or is absent, run the CLI equivalent: `magus run
<target>`, `magus affected list` for the set, `magus affected <target>` to run
it. 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.
- Run `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.
- Never hand-run lint, format, and test one at a time. That re-derives an order
the magusfile 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 counting its
pass. A check wired to the wrong path passes 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.
Narrow it as "When a target fails" below says; `ci` afterwards proves the
change. `magus describe targets` lists every target (`-o name` for
bare names) and classifies each as canonical, spell,
or custom; `client` (`magus\describe.target`) is the MCP equivalent. Ask the
workspace; do not read `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; never silently go around
magus.
5. Rewriting DEPENDENCY state needs the `update` charm: `magus run
<target>:update <project>`, so the rewrite happens inside magus, cached and
visible to affected tracking. That covers `go get`, `go mod tidy`, `pnpm add`,
`cargo update`, `uv lock` and `pip-compile`.
- `update` is reserved and not part of `rw`. `rw` covers output reproducible
from a clean checkout; `update` covers 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 run test web -- -k 'name' # rerun only the failing tests (pytest filter shown)
magus affected test # only projects affected by the VCS diff
```
MCP equivalents: `client` (`magus\run`) with the arguments of `magus run`.
`magus\affected` returns the affected project set and does not run it. `magus\impact` is why each project is in that set. `magus\where` answers which project contains a directory.
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.
To prove a command on Linux without opening a pull request, magus's own repository
runs it on a GitHub Actions runner (`magus buzz hack/remote/on-actions.buzz --
<command>`) or in a local Podman container (`magus buzz hack/remote/on-linux.buzz --
<command>`).
## 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
prints one line, `ref <output ref>`, and a failure keeps a bounded tail of
the failing project plus the ref to fetch the rest. With `--tee <file>` a
structured record goes to the file alone.
DROP it when the question is what RAN versus what replayed. The per-target
timings and the `(cached, 320ms)` / `(ran, 5m28s)` verdict print only 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`. Do NOT redirect it with `> file`, `>> file`, or `2>&1`.** The guard denies
both.
- A pipe REPLACES the exit status with the last stage's. `magus affected ci | tail`
reports tail's success, so 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 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>` 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 --stdin # plan -> run its shards
```
A pipe into magus, or `jq` over `-o json`, is composition. A pipe into a text filter
is a missing `-o`.
A backgrounded run's capture is magus output too: grepping the task file your host
wrote hits the `capture-filter` guard rule, since a grep drops the `output:` and `inspect:` lines
under the `cause:` you matched. Background it as `-o jsonl --tee <file>` to get a
contract you can `jq`; otherwise read the file whole.
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: `client` (`magus\output`) over MCP, or
`magus query output out1a2b3c` on the CLI. Do this instead of re-running the
target to see the error again.
2. With no ref in hand, find it in the run that minted it. Every `magus run` prints
one per target. `magus session` lists recent invocations with the targets
they ran. There is no tool that fetches "the latest log for a
project", because a second door onto the same bytes only makes an agent holding a
ref pick between two.
3. `magus doctor` validates the workspace itself (config, cache, tool availability,
cycles) when failures look environmental rather than caused by
your change.
Fix a failed full run by narrowing, not by repeating it:
1. Read the failure from its ref and list the failing tests.
2. Rerun only those with the test runner's own filter, passed after `--`, until they
pass: `magus run test <project> -- <filter>`. Examples by runner:
- Go (go test): `-- -run 'TestA|TestB'`
- pytest: `-- -k 'name'`
- Jest or Vitest: `-- -t 'name'`
- cargo test: `-- name`
3. Run the full target ONCE more. A full run after a failed full run, with nothing
narrowed between them, reports nothing new and costs the whole suite again.
A test known to fail for an outside reason is named once and left out of every rerun.
Run generators before the full test run, so a drift test does not fail for nothing.
## When another magus process holds the project
A run whose project lock or machine budget another magus invocation holds exits 75
at once, naming the holder.
- Never write `sleep`/`ps`/`pgrep` polling loops. The guard denies `pgrep`,
`pidof`, and `ps` for this reason.
- `magus status --watch=15s` reads that lock state continuously: holder PID,
command, directory, and age. Re-run once the lock releases.
- A long-running holder is not, by itself, evidence of a hang.
```sh
magus status --watch=15s
```
If the lock has crossed its stale warning threshold, report the exact holder and
inspect its captured target output. Never signal a guessed PID or act on a fixed
elapsed delay. Process termination needs an explicit, verified owner policy.
The same view lists shared services, each with its lifecycle state and dependent
count. Use it to tell 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.