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

The host wiring is yours

magus owns the guard rules and the verdict. It does not own an integration with your agent host. The rules come from one binary and are identical everywhere; the part that knows your host (which event field carries the command, which reply channel reaches the model, what happens when the binary cannot be found) is a template you copy and edit. Adding a host is your change, not a magus release.

The contract is small enough to hold in your head. magus shell takes the thing to judge on stdin, either plain text or a payload keyed by FIELD (tool_input.command, file_path, prompt), never by a host name or a tool name. -o template= renders the verdict into whatever shape the host's reply takes.

A layer that made every host work with no friction is what is being traded away here, and it is worth being plain about the trade. Agent hosts change their event shapes and hook names on their own schedule. A workspace whose integration lives inside magus waits for a magus release to get unblocked; a workspace that owns fifteen lines of shell edits them that afternoon. The cost is charged up front and on purpose: you read your host's hook documentation once, and there is no zero-configuration path.

The second cost of such a layer is the one nobody sees until it matters. A guard you did not wire is a guard whose failure mode you do not know, and this one fails OPEN by design, so a hook that quietly stopped judging looks exactly like a session with nothing to deny. So a shipped template announces its fail-open arms rather than exiting quietly. One template is exempt, and the test declares it rather than leaving it to be discovered: the path template stays silent. An empty response from a file-write rule already means allow, a notice on every file edit was judged the worse noise, and hearing about it there is opt-in. Whoever runs the guard should be able to read what it does and repair it without us.

The same holds for credentials: the guard is a seatbelt, not a boundary against a process running as you, which can read any file magus can. So the guard refuses what an agent should not do, and magus separately enforces every layer it can prove, a planted token file that cannot grant more than a mint, a token that never mints a wider one, rather than claiming a sandbox it does not have (Tokens and grants).

Enforced by

  • The hostagnostic linter fails the build when a host's NAME appears in code anywhere but a path on disk.
  • The hostvocab linter fails the build when a host's word for a tool appears as a string literal in guard code at all, so a lookup table is no cheaper than a switch. The activity-event tool labels are magus's own vocabulary for that reason, chosen by which flag the wrapper passed.
  • The magus-guard-coverage: line each template carries feeds a parity gate that fails when a host was never asked about a decision the contract grew.
  • TestFailOpenArmsAnnounceThemselves fails the build when a template stops announcing a fail-open arm.

Good

The verdict is keyed by field, and the template owns the host's reply shape:

printf '%s' "$payload" | magus shell -o template='{{.decision}}: {{.reason}}'

Bad

switch tool {
case "Read", "Bash":
    return judgeShell(input)
}

A branch on one host's tool names is a per-host branch in everything but spelling. The name check cannot see it, and the next host that calls the tool something else is silently unjudged.

See also

designjudgmentagentshooks
Last updated (2df714e8)
Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. Workspace in full.

Op

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

Spell

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

Sandbox

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

CI

An ordinary target you compose yourself with ctx.needs; magus does not hardcode its stages. It is the anchor magus affected ci keys off, and ci strips the rw charm. CI in full.

Agent

A model working through an agent host such as Claude Code, Codex, Cursor or OpenCode. magus treats an agent as one more caller of its CLI, MCP tools and console, held to the same checks as a person. Agent in full.

Tool

An action a model can call through its host: a name, a description, a typed input and a result. magus serves its tools over MCP, each a read of the workspace model or a run of the CLI it already has. Tool in full.

Harness

The deterministic scaffolding around the work on a change, for a person or an agent: compiler errors, formatters, linters, checks, gates, leases and hooks, placed at points a person chose. Around an agent's loop, magus supplies one and keeps it outside. Harness in full.

Session

An agent host's conversation, by the id the host delivers to its hooks. magus never mints one: a record with no session is unattributed, and the OS user it carries says whose account ran it. Session in full.

Run

One target executing under one magus invocation, such as magus run test web or magus affected ci. A run keeps its captured output behind an output reference. Every magus run is a run whether or not any job asked for it; see Job for how the two relate. Run in full.

Lease

The grant a holder takes on a job: the write and read paths that job declared, enforced in the checkout that took it with magus job exec. A job is the piece of work; a lease is permission over it. Lease in full.

Conventions

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