magus-shell
Check a command against this workspace's conventions before running it
Synopsis
magus shell '<command>' [flags]
Description
Check a shell command against this workspace's conventions, and name the better command when there is one.
The rules are the workspace's own. A raw `go build` misses the cache and the affected set; a recursive grep misses what the symbol index already knows; `git add -A` sweeps regenerated output into a commit about something else. None of that is a fact about who typed the command, which is why this is a plain subcommand rather than something under an agent namespace.
Nothing is executed and nothing is prevented. This reports; you decide.
THE INPUT ARRIVES TWO WAYS, and they are the same command either way. A person passes it as one quoted argument. A host pipes it on stdin, where it may be plain text or the JSON envelope the host already writes, so nothing has to survive being quoted through a shell twice. That is deliberate: an agent and a person get the same verdict from the same entry point, and neither reads documentation the other cannot.
--path judges the input as a file path an edit is about to write, rather than as a shell command.
--observe records a path the agent merely REACHED, without judging it. No rule applies to a read, so the verdict is always pass and the activity event previews as observed rather than as a guard decision. Which of a host's tools only look is the caller's knowledge, never magus's.
--agent-name, --session, --transcript, and --event are attribution, not policy. They record who produced the observation on the activity event, and the verdict never reads what they say. The host name is an opaque label rather than a set magus knows: a magus that enumerated hosts would need a release per host, and a caller that cannot extract a session id must still be able to get a verdict.
--transport names the form of the hook calling, such as sh or buzz, as that form declares it. Installed hook glue passes it, and glue that passes it without --agent-name is refused with MGS3024: the configuration "magus agent harness apply" writes names the host, so a call that does not is a stale or hand-written config, never defaulted to one host. With --agent-name and --session it names the CALLER that the once-per-session notices and the full text of a repeated deny are kept for, as one key, host/transport/session. A session id alone is not enough: two hosts can present the same id, and two forms of one hook wired into a session are two callers, each told a rule in full once.
--lease is the exception: it IS policy. It names the lease the caller is acting as, and a write is then graded against that lease's declared write boundary in this workspace's lease ledger. Inside its write paths passes; inside its deny paths, or inside another live lease's write paths, is denied and the reason names the owning lease. It defaults to the magus.lease member of $BAGGAGE - the W3C baggage list a spawning tool exports - and the flag wins when both are set.
A call that names no valid lease while a fleet is running is ADVISED and never blocked: a person editing their own repository has no lease id, and the guard is a seatbelt for callers that opt in rather than a sandbox. With no ledger, or with no lease in it declared or running, nothing is graded and nothing is read.
EXIT CODES are the contract a host blocks on: 2 is a deny and everything else is allowed. An advisory exits 0 on purpose - it attaches context and does not block, and a suggestion that failed a script would not be a suggestion. Input that could not be READ is 2, so a host that blocks on 2 fails closed when bytes were lost on the way in; an EMPTY input passes, because a wrapper that hands this nothing must not block every tool call.
Options
- --agent string
- The host's id for the subagent making this call, empty for the main conversation; a subagent magus saw spawned is graded under its job
- --agent-name string
- Name of the agent host this invocation came from (attribution only); required with --transport
- --event string
- The host's hook event name (e.g. PreToolUse)
- --lease string
- The lease this call is acting as, graded against the ledger's declared write boundary; outranks the spawn record, the checkout's marker and magus.lease in $BAGGAGE
- --observe
- Record the input as a path the agent reached, without judging it: no rule applies and the verdict is always pass
- --observes-skill-loads
- This host's wiring reports skill loads to magus, so a rule may require one before a spawn; without it those rules stand down
- --path
- Judge the input as a file path an edit is about to write, not as a shell command
- --renders-ask
- This wiring puts an ask verdict in front of the person through the host's own approval prompt; without it an ask is returned as a deny
- --session string
- The host's own session id for this invocation
- --transcript string
- Path to the host's own log of this session, recorded as a pointer; magus never opens it
- --transport string
- The form of the hook calling, such as sh or buzz; the once-per-session notices and deny explanations are kept per host, transport and session. Without --agent-name it is refused (MGS3024)
Exit status
- 0
- The input is allowed: pass, or advise, which attaches context and does not block. --observe always lands here, because it judges nothing. An EMPTY input is also 0: a wrapper that hands this nothing must not block every tool call.
- 1
- Not returned by a verdict. A wrapper should treat anything other than 2 as allowed rather than enumerating codes, so that a future signal added here does not start blocking commands.
- 2
- A DENIED command or path, and also input that could not be READ - the two share the code deliberately: a guard that could not parse its input has not cleared the command either, so a host that blocks on 2 fails closed in both cases. Misuse (an unquoted command, an unknown flag) is also 2.
Examples
Check one command
magus shell 'go test ./...'
Check a search
magus shell 'grep -rn HandleFoo internal/'
Judge a path an edit would write
magus shell --path MAGUS.md
As a host's pre-tool-use hook
printf '%s' 'go build ./...' | magus shell
Record a path an agent read, without judging it
printf '%s' 'internal/cache/output.go' | magus shell --observe
Grade a write as a lease
printf '%s' 'internal/job/store.go' | magus shell --path --lease f2-guard
The verdict as JSON
magus shell 'git add -A' -o json
See Also
magus(1), magus-ls(1), magus-describe(1), magus-run(1), magus-x(1), magus-where(1), magus-affected(1), magus-graph(1), magus-query(1), magus-explain(1), magus-path(1), magus-refs(1), magus-watch(1), magus-events(1), magus-status(1), magus-clean(1), magus-vcs(1), magus-queue(1), magus-doctor(1), magus-config(1), magus-session(1), magus-memory(1), magus-job(1), magus-notes(1), magus-diff(1), magus-server(1), magus-broker(1), magus-mcp(1), magus-buzz(1), magus-completion(1), magus-man(1), magus-init(1), magus-spell(1), magus-agent(1), magus-self(1), magus-version(1)