magus v0.3.0 is out. See what's new
¶ View markdown source · ✎ Suggest an edit
7 min read

magus-vcs

The --simple permutation is 31% smaller: 4527 of 6635 bytes.

Safe git operations in a magus workspace (any repo with magusfile.buzz at the root). Use IMMEDIATELY before git commit, git add, git stash, git reset, git checkout, or git clean, and when reading git status or a diff - especially one touching MAGUS.md, gen/ trees, lockfiles, or other generated files. Classifies every changed path as generated output vs source (magus describe file), gives the commit checklist, and settles merge conflicts in generated files by regenerating. Do NOT stash or reset the whole tree to verify a build; load this skill first.

Install it, rather than copying from this page:

magus agent install .claude/skills            # the full form below
magus agent install .claude/skills --simple   # the short form below

An installed copy carries a provenance stamp, so magus graph verify 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 graph verify 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 23
knowledge-schema-version 7
skill-content ace009cb3627
skill-variant full

The skill-content digest is shared by both permutations below, so they version together: a magus upgrade makes both stale at once, never one silently.

Full form

The default: the steps plus the rationale for each.

# VCS hygiene in a magus workspace

Targets declare their outputs: the file globs a target regenerates on every run
(`MAGUS.md`, `gen/` trees, lockfile-adjacent artifacts). magus uses those
declarations for caching, `magus clean`, and its VCS merge driver. Use the same
declarations to decide which changed files deserve your attention.

## Classify before you read

Feed every changed or conflicting path to magus in one call - it classifies
each against the workspace's declared globs:

```sh
magus describe file $(git diff --name-only) <other paths...>
```

MCP: `magus_describe_file` {paths}. Each path comes back with its owning
project and a role:

- `output` - matches a declared outputs glob: the file is GENERATED.
- `source` - matches a declared sources glob: it feeds cache keys and the
  affected set. This is the diff worth reading.
- `unclaimed` - no project declares it: it affects no target. Check the VCS
  ignore rules (`git check-ignore -v <path>`) - build residue should be
  ignored, and an unclaimed un-ignored file is at risk of being lost.

WRONG: reading a 3000-line diff of `docs/gen/` to understand a change.
CORRECT: note that `docs/gen/**` is a declared output of
`docs:generate`, skip the diff, and read the source change that caused it.

## Rules for generated files

- Never hand-edit one. Change the source of truth, then run the producing
  target (usually `magus run generate`).
- Do not investigate their diffs; regenerate and compare instead. If a generated
  file changed with no source change, that is the finding (stale or hand-edited
  output) - `magus run generate` should settle it.
- Distinguish real drift from environmental noise before you act. If regenerating
  reproduces the same diff while the target's declared inputs are unchanged, the
  drift is environmental (a tool-version bump, an embedded timestamp), not your
  change. Report the tool or version; never revert the working tree to chase it.
  Real drift traces to a source edit; environmental drift traces to the toolchain.
- Commit regenerated outputs together with the source change that produced
  them. CI typically runs the generate target as a drift gate: a source change
  whose outputs were not committed fails there.
- On merge conflicts, run `magus vcs resolve`. It settles every conflicted
  generated file at once, regenerates ONCE, and records the result, leaving only
  the conflicts magus cannot settle for you. Never merge generated hunks by
  hand. Do not reach for the merge driver instead: a VCS invokes a driver once per
  conflicted path and never invokes one at all for a file one side deleted, so the
  driver alone cannot finish the job.
- `magus clean` removes declared outputs when you want a provably fresh
  regeneration.

## Preparing a commit

`magus vcs add` does steps 1-2 and the staging in one call, and is the sanctioned
replacement for `git add -A`:

```sh
magus vcs add --dry-run   # classify the dirty tree, stage nothing
magus vcs add             # stage declared sources AND the outputs they produced
magus vcs add <path>...   # narrow it
```

It stages sources and generated outputs together (they belong in one commit) and
REPORTS every undeclared path instead of sweeping it in, which is the one thing
`git add -A` cannot do. Pass `--untracked` when one of those undeclared paths is
genuinely a new source file. Staging specific paths by hand stays fine; the long
form below is what it automates, and what to fall back to.

For a rare VCS fact that needs Magus's portable VCS module rather than porcelain,
use one inline Buzz evaluation:

```sh
magus buzz -e 'import "std"; import "vcs"; fun main() > void { std\print(vcs\branch() + " " + vcs\shortHash()); } main();'
```

Use `vcs\diff()` for the configured-base path set, `vcs\isDirty(["path"])` to
scope a cleanliness check, and the discrete accessors for revision state:
`vcs\hash()`, `vcs\shortHash()`, `vcs\branch()`, `vcs\commitDate()`,
`vcs\isDirty()`. Each returns a typed scalar.

Prefer those over `vcs\metadata()`, which returns the same five facts as an
untyped `map[string]any`. It is the one call in this module that gives up the
type, so a caller reads fields by string key and finds out at runtime when one
is missing or renamed - and it buys nothing, since the typed accessors already
cover the whole map.

The inline form is intentionally dense: it is an occasional capability query,
not another everyday CLI surface.

1. List the dirty tree with your VCS (`git status --porcelain`).
2. Classify every path with `magus describe file` as above. Untracked files
   that are neither ignored nor declared outputs are the ones at risk of being
   silently lost - stage them or ask about them, never leave them dangling.
3. Regenerate if any source of a generate target changed, and include the
   refreshed outputs in the same commit.
4. Review `git status` first, then stage deliberately with `git add -- <paths>`. `git add -A` stages every
   untracked file too, so a stray build artifact or scratch file rides along
   silently (this is how a compiled binary once slipped into a commit); use it
   only when `git status` shows nothing you do not intend, else stage the specific
   paths. Do not lean on an unreviewed hand-typed path list as your only safeguard either:
   `git add` aborts on the first pathspec that matches nothing (staging none of
   the rest), and a path you just moved or removed is gone at its old name.
   Whichever you use, confirm with `git diff --cached --stat`: every intended edit,
   renames included (`renamed:`), must be present. `git commit` records what `git
   diff --cached` shows and does not re-check that your edits landed.
5. Run `magus affected ci` before calling the work done: it runs the full
   pipeline over every project the diff reaches, including ones you never edited,
   and after committing confirms HEAD builds - a partial commit that drops a
   rename or an importer update leaves HEAD non-building.

Never `git stash`, `git reset`, `git checkout .`, or `git clean` to "verify a
build without committing." The working tree is ALREADY what you want to verify,
so run `magus run build` / `magus affected ci` in place; building does not
require committing first. A whole-tree revert also unrecoverably
destroys any untracked work a concurrent agent is writing. If you truly need a
pristine tree (e.g. to diff regenerated output), use a throwaway
`git worktree add`, never the live tree.

`magus_affected_explain` {project} answers why a specific project is in the
affected set (the changed files and dependency chains that pulled it in) when
the result surprises you.

Short form (--simple)

The same steps with the rationale withheld; the bar under the heading above shows by how much. Both are hand-authored from one source body; see Agents for when to prefer which.

Show the short form
# VCS hygiene in a magus workspace

Targets declare their outputs: the file globs a target regenerates on every run
(`MAGUS.md`, `gen/` trees, lockfile-adjacent artifacts). Use the same
declarations to decide which changed files deserve your attention.

## Classify before you read

Feed every changed or conflicting path to magus in one call:

```sh
magus describe file $(git diff --name-only) <other paths...>
```

MCP: `magus_describe_file` {paths}. Each path comes back with its owning
project and a role:

- `output` - matches a declared outputs glob: the file is GENERATED.
- `source` - matches a declared sources glob: it feeds cache keys and the
  affected set. This is the diff worth reading.
- `unclaimed` - no project declares it: it affects no target. Check the VCS
  ignore rules (`git check-ignore -v <path>`).

## Rules for generated files

- Never hand-edit one. Change the source of truth, then run the producing
  target (usually `magus run generate`).
- Do not investigate their diffs; regenerate and compare instead. If a generated
  file changed with no source change, that is the finding.
- Distinguish real drift from environmental noise before you act.
  Same diff on regenerate with inputs unchanged means environmental (tool
  version, timestamp). Report the tool; never revert the tree to chase it.
- Commit regenerated outputs together with the source change that produced
  them.
- On merge conflicts, run `magus vcs resolve`. It settles every conflicted
  generated file at once, regenerates ONCE, and records the result, leaving only
  the conflicts magus cannot settle for you.
- `magus clean` removes declared outputs when you want a provably fresh
  regeneration.

## Preparing a commit

`magus vcs add` does steps 1-2 and the staging in one call, and is the sanctioned
replacement for `git add -A`:

```sh
magus vcs add --dry-run   # classify the dirty tree, stage nothing
magus vcs add             # stage declared sources AND the outputs they produced
magus vcs add <path>...   # narrow it
```

It stages sources and generated outputs together (they belong in one commit) and
REPORTS every undeclared path instead of sweeping it in. Pass `--untracked` when one of those undeclared paths is
genuinely a new source file. Staging specific paths by hand stays fine; the long
form below is what it automates, and what to fall back to.

For a rare VCS fact that needs Magus's portable VCS module rather than porcelain,
use one inline Buzz evaluation:

```sh
magus buzz -e 'import "std"; import "vcs"; fun main() > void { std\print(vcs\branch() + " " + vcs\shortHash()); } main();'
```

Use `vcs\diff()` for the configured-base path set, `vcs\isDirty(["path"])` to
scope a cleanliness check, and the discrete accessors for revision state:
`vcs\hash()`, `vcs\shortHash()`, `vcs\branch()`, `vcs\commitDate()`,
`vcs\isDirty()`. Each returns a typed scalar.

Prefer those over `vcs\metadata()`, which returns the same five facts as an
untyped `map[string]any`. It is the one call in this module that gives up the
type, so a caller reads fields by string key and finds out at runtime when one
is missing or renamed - and it buys nothing, since the typed accessors already
cover the whole map.

The inline form is intentionally dense: it is an occasional capability query,
not another everyday CLI surface.

1. List the dirty tree with your VCS (`git status --porcelain`).
2. Classify every path with `magus describe file` as above. Untracked files
   that are neither ignored nor declared outputs are the ones at risk of being
   silently lost - stage them or ask about them, never leave them dangling.
3. Regenerate if any source of a generate target changed, and include the
   refreshed outputs in the same commit.
4. Review `git status` first, then stage deliberately with `git add -- <paths>`. Avoid staging
   everything (stray artifacts ride along); a hand-typed path list is not safer,
   since the first non-matching pathspec aborts the whole call. Confirm with
   `git diff --cached --stat`: every intended edit, renames included.
5. Run `magus affected ci` before calling the work done.

Never `git stash`, `git reset`, `git checkout .`, or `git clean` to "verify a
build without committing." Build in place; a
whole-tree revert destroys a concurrent agent's untracked work. If you truly need a
pristine tree (e.g. to diff regenerated output), use a throwaway
`git worktree add`, never the live tree.

`magus_affected_explain` {project} answers why a specific project is in the
affected set.
agentsskillsmagus-vcs
Last updated (a103255f)
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.

Operation

A single tool-native command a target composes; the middle of the work hierarchy (Spell to Operation to Target). See operations.

Module

A magus stdlib namespace a magusfile imports for host capabilities: filesystem, exec, vcs, and more. See the module reference.

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.

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.

Trace

OpenTelemetry's name for one whole magus invocation; every target it runs is a span beneath it. See telemetry.

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.

Conventions

This page uses none of the site's convention markers. The full set is on the conventions page.