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

Any other host

The four documented hosts are examples, not a fixed list. magus owns the guard rules and the verdict, not integration code per host, so the host-specific part is a template or a few lines of config you control, and adding a host is your edit rather than a new magus release.

That is a standing decision rather than a gap waiting to be filled. A codec per host would cost us upkeep as the products change, and it would cost you more than it costs us: wiring you did not write is wiring you cannot repair on the afternoon your host changes its event shape, and this guard fails OPEN, so a hook that quietly stopped judging looks exactly like a session with nothing to deny. Read the template once and it is yours.

Any host that can run a command and read its output fits.

what where
skills whichever directory your host discovers SKILL.md in
always-on rules AGENTS.md, if your host reads one
guard wiring whatever pre-tool hook or plugin your host offers
MCP MCP

Skills

Not every host reads the Agent Skills format. If yours discovers SKILL.md directories, install into the one it names:

magus agent install --tar | tar -xf - -C <the directory your host reads>

If it reads only an instruction file, run magus agent install for the AGENTS.md block it prints and paste that instead. Skills covers both.

MCP

magus server start

Any client that takes a Streamable HTTP URL plus a bearer token can connect; see MCP.

Guard hook

The wiring is the same shape everywhere: get the command or path out of the host event, hand it to magus session hook, and render the verdict into the host's reply.

printf '%s' "$command" | magus session hook -o 'template=<your host reply>'

If your host writes its payload as JSON with tool_input.command or tool_input.file_path, pipe the payload in unchanged: magus reads the envelope itself, infers a write from a file path, and picks up session_id and hook_event_name for attribution. Otherwise select the field yourself - jq -r '.<path>' is what the shipped templates use - and pass --path when the input is a file. A lease id is not a field you select out of the event: the guard inherits it from the worker's environment, which the orchestrator that spawned the worker has to export - see wiring a lease into a worker.

The fastest start is to copy magus-guard-command.sh and set its override variables: HOST_EVENT_PATH, HOST_RESPONSE, GUARD_AGENT_NAME, and the two unavailable-response variables. That gets you the missing-binary and broken-binary handling without writing it again.

Three decisions are yours to make:

  • Which channel carries a deny. Most hosts have one that reaches the model.
  • Whether an advise can reach the model at all. Some hosts deliver a message only on a denial; there, the advisory nudges live in the installed skills instead. Set GUARD_NO_ADVISE when your host does worse than ignore one - Codex treats the additionalContext key as an error and then fails OPEN, so sending an advisory it cannot take disarms the guard for that call. Suppressed, an advise renders nothing at all; HOST_ADVISE_BRANCH reshapes it instead if your host has some other channel.
  • What happens when magus cannot be found or cannot judge. Failing open keeps the session usable and is what every shipped template does. Say so visibly rather than exiting quietly, because an unguarded session you know about beats one you do not.

If you contribute the result back, add a magus-guard-coverage: line declaring what your glue carries per surface and decision. A parity gate reads those lines and fails the build when a host was never asked about a decision the contract grew.

Lease capture

Separate from the guard, and the same shape: pipe the host's pre-tool event to magus session hook when the tool being called is the one that hands work to a sub-agent.

printf '%s' "$event" | magus session hook --agent-name <your host> >/dev/null 2>&1; exit 0

magus recognizes a lease by the FIELD it carries, never by a tool name it would have to enumerate per host: a tool_input with a prompt is a spawn. It reads the prompt as the handed context, takes the callee's label from subagent_type, then description, then tool_name, and takes the parent's session from session_id. If your host names those fields differently, reshape the payload before piping it - jq is enough.

The ordering is deliberate: a payload carrying command or file_path is judged as a command or a write exactly as before, and only one carrying neither is read as a spawn. Adding this wiring cannot change a verdict you already had.

Nothing judges a lease. A prompt is prose, not a command line, so the verdict is always a pass and a prompt that mentions a denied command is recorded rather than blocked. Discard the output and exit 0.

The event

One agent_spawn event per lease, in the same activity trail and the same listing as every other kind - no new endpoint, and the console's activity filters already select it.

field what it carries
time when the handoff was observed
host, session the PARENT: the host you named, and its own session id
actor agent
action the child's label, or agent.spawn when the payload named none
lease the ledger lease, when the context declared one (see below)
request_ref the handed context, fetched with GetPayload
request_bytes how much context was handed over
outcome ok means the handoff was OBSERVED, never that the child succeeded

The context is a blob, not a field. A lease prompt runs to kilobytes and can carry anything the orchestrator pasted into it, so the event line holds a reference and the body is fetched deliberately, one row at a time. It is redacted through the same resolver as every other trail write, but it is still durable prose on disk: treat the activity trail as readable by anyone who can read the workspace cache.

Correlating a spawn to a lease

Correlation is COOPERATIVE. No host event names a magus lease and magus will not guess one from prose, so an orchestrator that wants the join writes ONE marker:

lease: <id>

It must be the FIRST non-blank line of the handed context, and its trimmed text must be exactly that. The id is a bare token of letters, digits and the separators - _ . / :, at most 128 characters, with nothing after it on the line. Leading blank lines are skipped; the head of the context is capped at 4096 bytes, so a marker cannot hide behind a pathological first line.

Leading the prompt is the contract, not a convention. A lease prompt routinely quotes a ledger listing, a file, or another agent's transcript, and a lease: line lifted from any of them would stamp the event with a lease this handoff has nothing to do with. Position is what separates a marker you wrote from one you pasted.

Anything else leaves lease empty: no marker, an id with prose after it, an id carrying other punctuation, a marker below the first line. That is a missing join, not an error, and it is the designed outcome for an orchestrator that never opted in.

Notifications

Wire any event that means a human is needed to magus session notify; see Attention hooks.

Coverage and limits

Whatever your host's hook surface can carry. One binary produces the rules, so they are identical everywhere, and what differs is only how much of a verdict survives the trip to the model. Parity across hosts records that for the documented four.

Verify

printf '%s' 'git stash' | magus session hook -o name
magus doctor

The first proves magus judges at all from your shell. guard wiring in doctor inventories the host config locations it knows and reports when none of them invokes a current template.

agentsguardhooksintegrationtemplate
Last updated (4f8cc295)
Earlier changes on this page (5)

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.

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.

Cache

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

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.

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.

Lease id

The short identifier a worker carries (the --lease flag, or the magus.lease member of the W3C BAGGAGE environment channel) so its runs, journal facts, and guard verdicts attribute to its lease. Letters, digits and -_./: only.

Advisor

One read-only check from the advice suite: it reads the changeset through magus and writes one titled section of findings. The same advisors run as a pull request comment in CI and inside magus diff --impact locally.

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.