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

Agents

magus knows more about a workspace than any agent can rediscover by reading files: the project DAG, every target's inputs and declared outputs, which files are generated, what a diff affects, where churn and coupling concentrate.

The agent surface exposes that through three artifacts, and one rule governs all of them. Every tool answers a question from declared sources; none of them decides, plans, or injects itself into the agent's context. Answering is the tool's job, deciding is the model's.

artifact answers freshness
MAGUS.md WHAT is in this workspace (targets, counts, anchors) regenerated with the workspace (magus describe graph -o markdown)
Skills HOW to use the magus tool surface ships with the binary; versioned, drift-checked
MCP daemon live answers (query, run, explain, logs) always current; magus server start

The split is deliberate: skills never mention workspace specifics, so they go stale only when the tool surface changes, and that staleness is detectable.

MAGUS.md is per-project as well as per-workspace. A nested project can commit its own, generated by its generate target and scoped to that project's targets, so an agent working inside one project gets a routing index sized to it.

Set up your host

A full setup is two steps: install the guidance where the host reads it, then wire the guard hook. Both are on your host's page.

host skills guard
Claude Code .claude/skills/ two PreToolUse hooks
Codex .agents/skills/ + AGENTS.md hooks.json (experimental)
Cursor AGENTS.md only one self-contained script
OpenCode .opencode/skills/ a TypeScript plugin
Any other host wherever it reads them your own few lines of config

What you wire is yours. magus ships the rules and the verdict; the host-shaped few lines that carry an event in and a reply back are a template you copy and own, so a host magus has never heard of works the same way and a host that changes next month is your edit rather than a magus release. Doctrine records that trade and what it costs you.

The shared reference pages sit behind those: Skills for the install surface, The guard for what is denied and why, Guard hook templates for the two files Claude Code and Codex run, Attention hooks for magus session notify, and Leases for the surface an agent uses when it fans work out across several.

Parity across hosts

Every host gets the same RULES - they come from one binary, and none of them is per-host. What differs is how much of a verdict a host's hook surface can carry.

command rules declared-output rule deny reaches the model advise reaches the model
Claude Code yes (verified) yes (verified) yes yes (additionalContext)
Codex yes (verified) yes, per OpenAI's docs (unverified here) yes no - rejects the key
Cursor yes (verified) yes, reported after the write (verified) yes (user_message + agent_message) no - collapses to allow
OpenCode yes (verified) yes (verified) yes (thrown) no - logged for the human

"Verified" means executed against this binary with a real event on stdin.

Everything else is additive. A host missing a file-write hook still gets every command rule, and adding one later changes no magus code, because the rules and the verdict already exist and only the wrapper is host-shaped.

Project references

A project reference is a workspace-relative path, written bare: pkg/api. That is the one spelling to read, to write, and to quote back. What a project arg prints is what a project arg takes, so a path out of any magus command pastes straight back into the next one.

Four spellings in, one reference outmagus accepts a workspace URL, a workspace-relative path, a dot-relative path or the bare root alias, and parses them all to one project reference. Human output prints the short path; machine output prints the workspace URL.AGENTSFour spellings in, one reference outACCEPTED AS INPUT, INTERCHANGEABLEPRINTED-O JSONworkspace://pkg/apipkg/api./pkg/apiworkspace://the root aliasSTEPparseOne referencepath: pkg/apiHuman outputpkg/apiMachine outputworkspace://pkg/apiONE CANONICAL FORM
form means
pkg/api that project, measured from the workspace root, from anywhere
./pkg/api, .. measured from the current directory
. the project the current directory is in
project:pkg/api the same project as a GRAPH NODE, for explain, query, path

Three rules cover the whole surface:

  • A bare path is absolute enough. It is measured from the workspace root, so it means the same project from any directory. Only the dot forms depend on where you are standing, and when you are standing outside the workspace entirely, --root <path> measures them from the workspace it names - so a command written once keeps working when it is run from somewhere else.
  • Never rewrite a path magus printed. Every surface prints the bare workspace-relative form - -o name, -o json, logs, error messages, Mermaid node labels - so it is already in the form the next command wants. Commands that take fuzzy search tokens rather than paths, such as magus where, take the same bare text.
  • Quoting a project back to a user: prefer whatever magus printed. The workspace root is the case that bites, because it is the one project whose path is a bare .; human output renders it as the repository's directory name, so a . never leaks into a sentence where it reads as punctuation.

The project: prefix in the last row is not a second path syntax. It is the kind-prefixed node grammar the graph commands use where kinds mix, alongside target:, spell:, and doc:; magus explain project:pkg/api disambiguates a name that could be either. Commands that only ever take a project - run, affected, ls, describe project - take the bare path.

Note

A workspace://pkg/api reference still parses and resolves to the same project, with a deprecation warning. It bought no reading the bare path did not already have, and it is not what magus teaches or prints any more. Drop the scheme wherever you find one written down.

Incremental review

Answer "I reviewed earlier - what changed since, and what do I need to look at now" without re-reading the whole workspace:

  1. At review time, record where you stopped: magus vcs checkpoint -o name prints the revision, or <revision>+<digest> when the tree was dirty - the digest says which dirty tree was reviewed, since the revision alone reads the same for every dirty tree built on it.
  2. Later, pipe the delta through the annotated view instead of reading a raw diff: git diff <revision> | magus diff - reports each changed file's reach, public-surface exposure, and referents - the surrounding code worth a second look, not just the literal hunks. magus diff refuses a git ref given positionally, on purpose - a swallowed ref once printed the reader's own edits as the answer - so the pipe form above is the only sanctioned spelling, and the refusal message says so.
  3. Reviewing through a diff session carries this further: per-hunk viewed marks key off content digest, not position, so a hunk that has not changed stays marked reviewed and one that has resurfaces on its own.

Leasing work across agents

The same checkpoint identifies a piece of work handed to another agent, and it is one leg of a wider surface: a declared lease ledger, a console Plan surface that draws it, and a spawn recorded but never judged. magus records what an orchestrating agent says it intends and enforces none of it - ownership is settled by diffing against the checkpoint each lease was handed. Leases covers that loop.

The MCP daemon

magus server start brings up the daemon, and the MCP server with it. Agents connected over MCP get the same verbs as the CLI plus run and log tools; magus describe mcp-tools lists all of them with parameters. See MCP for transport and token setup, and Knowledge graph for the graph the query tools read.

Skills prefer the MCP tools and fall back to the CLI, so they work in both connected and daemon-less sessions.

One tool carries state across sessions: magus_memory, a user-owned handoff journal of per-repository records, each pointing at something magus can reopen, kept in the user state directory outside the repo and shared across branches and worktrees. It is pull-based - nothing is injected into an agent's context - and also available through magus memory ls|get|put|delete|verify. Use verify to surface stale, malformed, or broken linked entries. Captured build output is addressed by output references.

The CLI works without it

The CLI still reads the workspace, runs targets, uses the cache, and answers graph queries with no daemon running. What it lacks is MCP tool discovery, the warm graph and background indexes, structured output retrieval, and MCP-only capabilities such as the handoff journal.

An agent must not turn that into a blocker. At task start, or after an MCP error, run magus status --probe=mcp; if it is unavailable, tell the user once to run magus server start, then use the CLI fallback. The next task picks up the full surface after the daemon is running and the client is restarted.

Why a daemon, not a wrapper

If an agent can already run magus query in a shell, what does an MCP server add? If the server only ran the CLI and handed back its stdout, the answer would be nothing, plus a round trip. The difference is the context the agent has to work with.

An agent working through a shell falls back on the habits it learned everywhere else: grep and cat over the files. Those return text matches. They do not return the project DAG, the declared outputs, the affected set, or the blast radius of a symbol, because none of that is written in the files - it lives in the graph the daemon keeps warm. So the agent reasons one layer below the structure it is trying to understand, and fills the gap by guessing: this file looks generated, these two packages probably change together. Those guesses are frequently wrong, and the agent has no way to check them.

The tools answer from what the workspace declares. Ask magus_describe_file about a path and it does not read the filename and infer; it checks the project's own globs and reports role: output with the note "generated: never hand-edit, regenerate." In one case an agent spent close to an hour working out whether a committed gen/ file was safe to edit - running generate repeatedly, planting sentinel writes, diffing timestamps - when one call to that tool would have answered it in a line.

So the server adds three things a shell-out leaves on the floor. Discovery: the tools arrive in the model's context with their descriptions and parameters, so the agent knows they exist without reading --help first. Shape: results come back structured and sized for a model, rather than a human-formatted table wrapped in color codes and pagination it has to scrape and pay for by the token. Ground truth: the daemon reports what the workspace declares, which the agent can rely on, rather than what a text pattern happened to match, which it cannot.

None of this comes from the protocol. A server that only shelled out would be a wrapper whether or not it spoke MCP. MCP is how the graph reaches the model; the value is in the graph and the curation.

agentsskillsagent installMCPMAGUS.mdAGENTS.mdhooksguardknowledge graphmemoryclaudecodexcursoropencode
Last updated (4f8cc295)
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.

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.

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.

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.

Knowledge graph

The queryable graph of a workspace's spells, targets, docs, and code relationships; query it with magus query/explain/path. See knowledge.

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.

Ownership

An insight lens: author concentration - the primary author and their share, the distinct-author count (the bus factor), and abandonment. See insight.

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.

Admonitions

Call-outs are rendered from GitHub-style alert blockquotes and carry a colored accent per type:

Note

Context worth knowing, but not a warning.

Warning

Something that can bite you if ignored.

The types are NOTE, TIP, IMPORTANT, WARNING, and CAUTION.