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

Leases

One agent hands work to several. magus neither runs that fan-out nor polices it. It answers what the working state is, records what the orchestrating agent says it intends, and shows a person the result - the same rule the rest of the agent surface obeys: answering is the tool's job, deciding is the model's.

How to split the work is not on this page. That is the magus-multi-agent skill: partition by write set rather than by affected project, prove the leases cannot collide, bound the fan-out, match a model to each lease. This page is the surface that skill writes to and reads from.

step surface
Record the working state magus vcs checkpoint, magus_vcs_checkpoint
Hand out the leases the host's own spawn - recorded, never judged
Declare the plan magus_ledger (op=put)
Watch it the console Plan surface, GET /api/v1/ledger
Verify the actual diff since each lease's checkpoint

Only one thing in that table enforces, and it is not the ledger. The ledger is a declaration, the checkpoint is a reading, and the Plan surface renders both. The guard is what reads the declaration back: on a file write it denies a lease that never registered its base, a path the lease itself declared forbidden, and a path another live lease owns. It grades only a worker that named its lease, so the last step below - the actual diff against the checkpoint - is still what catches a write nobody could attribute.

A declared plan, released early, verified by diffAn orchestrator checkpoints the working state, partitions the work by write set using graph evidence, and declares one ledger row per lease: goal, checkpoint, owned paths. Workers release paths as soon as they are done with them, so the plan shrinks while it runs, and the Plan surface renders the rows, their overlaps and their staleness for whoever is watching. The orchestrator verifies each lease by diffing since that lease's checkpoint against what it claimed, then integrates and runs magus affected ci. magus records and answers; it enforces none of it.LEASEA declared plan, released early, verified by diffREPORTS DONERELEASELEDGER ROWSWATCHESmagus vcs checkpointrevision + dirty digestPartition by write setrefs, explain, affectedDeclare the plangoal, checkpoint, pathsWorkers editone write set eachVerify each leasediff since its checkpointIntegratemagus affected ciPlan surface/console/plan/, overlaps, staleThe humanwatches and decidesmagus records and answersit enforces none of itTHE WHOLE GUARANTEEAGENTS AND PEOPLE

Record the working state

A checkpoint is the identity of the tree right now: the head revision, the branch carrying it, whether the tree is dirty, and a digest of the uncommitted patch.

magus vcs checkpoint
# <revision> <branch> clean
# <revision> <branch> dirty <digest>

magus vcs checkpoint -o name
# <revision>              when the tree is clean
# <revision>+<digest>     when it is not

magus vcs checkpoint -o json
# the whole record: revision, branch, dirty, patch_digest, vcs

It resolves and records; it never mints. No tag, no stash, no ref, no file, nothing changed anywhere - so taking one per lease costs the tree nothing, and one nobody keeps costs nothing either.

The digest is the half a revision cannot supply. Every worker on a branch shares the revision, so a dirty tree's revision does not say WHICH dirty tree was handed out; comparing two digests does. That is why -o name renders a dirty checkpoint as <revision>+<digest> and a clean one as the bare revision: the clean form is a token anyone can check out, and the + marks the other as a revision plus uncommitted work that nobody can.

-o name is the single citable token, sized for the one cell a ledger row gives it. Feed the revision half to anything that takes a revision, such as magus graph diff --rev <revision>.

The command takes no arguments - it reports the whole workspace's working state. A path argument is refused rather than ignored, because magus vcs checkpoint <path> would read as a path-scoped digest, which is a different and much narrower fact. Agents connected over MCP call magus_vcs_checkpoint, which takes no parameters and returns the same record. Full flags: magus vcs.

Declare the plan in the ledger

magus_ledger records the lease plan an orchestrating agent declared, so a person can see it. One row per lease, in the skill's vocabulary.

op does
list every row in the order they were recorded, plus the overlaps (the default)
put create or replace one row by id, merging the fields you send
register record the base a worker actually landed on, and read the verdict comparing it
clear drop every row and start a fresh plan

A row carries id and optionally parent (the lease that handed out this one), goal with its observable acceptance criteria, checkpoint (as magus vcs checkpoint -o name prints it), owned_paths and forbidden_paths, depends_on, tier, validation, state, and read_only. The store adds created, updated, releases, and unattributed (paths this lease owns that somebody outside it wrote, noticed by the guard), all output-only: a timestamp a client sent would be a fact about that client's clock. register adds three more the same way - reported_base, the checkpoint token the worker found in its OWN tree; base_verdict, the store's comparison of that against the row's checkpoint; and registered, when that comparison was recorded.

Three properties are worth stating plainly.

Owned and forbidden paths are declared here and enforced elsewhere. This store gates nothing: it records the text an orchestrator put in a worker's prompt, where a human can read it. The agent guard is the one reader that turns it into a verdict, and on a file write it DENIES three things - a lease that has not registered the base it landed on, a path covered by that lease's own forbidden_paths, and a path covered by another live lease's owned_paths. It advises on a fourth: your own path, written from a base that base_verdict says is not the checkpoint you were handed. Everything else passes, and every uncertainty fails open with at most an advisory - no ledger, an unreadable one, a writer that named no lease - because this is a seatbelt for a harness that opted in and not a sandbox. Which is why the diff since each lease's checkpoint, the last step below, is still where ownership is finally checked.

Every row ends in pass, fail, or no_return. no_return is not a failure. A lease that failed came back and said so; a lease that died, stalled, or was cancelled said nothing, and it is the only state on this surface that no other system will report. Silence is not a pass.

One plan per workspace, with no history. clear starts a fresh one and keeps nothing. A read-only lease that gathers evidence and writes nothing carries an abbreviated row: read_only set, and empty owned and forbidden paths that then read as deliberate rather than forgotten.

Three answers the ledger gives back

None of them is enforcement. Each is something an orchestrator would otherwise derive by hand from a table it wrote itself, and each leaves the decision where it was.

Overlaps. A list reports every pair of leases whose owned_paths intersect as lease_a/lease_b and paths_a/paths_b - each side's own declarations, kept apart, because they are rarely the same string and which lease claimed which is the part a reader acts on. Derived on the read and stored nowhere, so it cannot go out of date with the rows. A path is compared by containment - a lease owning internal/ledger overlaps one owning internal/ledger/store.go - and a glob is judged by the directories it names, which over-reports rather than misses a pair: console/src/**/*.ts and console/src/**/*.css share no file and are reported anyway. A lease in a terminal state is in no pair, because a finished or released lease is not competing for anything.

Staleness. Every put re-stamps updated. A row nobody touches goes quiet, and a reader watching that gap may judge the lease possibly dead - the console draws the age on live rows and marks one that has not moved in ten minutes. The judgment is the reader's: no row transitions itself, and no_return is only ever a state an agent wrote.

Releases. Shrinking owned_paths is how a lease announces it has finished editing a path, and the store records each dropped path with the digest that path carried at that moment: the file's sha256, or one of three words when it cannot be one - absent when nothing is there, dir for a directory, which has no single content hash, and unreadable for a path that is there and could not be hashed (a permission denied, something that is not a regular file, a file over the store's size cap). absent and unreadable are deliberately not the same answer: "the releaser deleted it" and "something is there nobody could read" send you to different places. Computed here so no worker has to hash anything, and so the digest describes the tree the releaser actually left rather than the one it believed it left. Hand it to the lease taking the path over; a digest that no longer matches at verification time means that lease built on a tree the releaser never saw.

The rows live in one JSON file under the cache directory (<cache-dir>/ledger/leases.json). magus_ledger is its write door and the daemon's read-only GET /api/v1/ledger route is its read door; there is no CLI verb, because the ledger has a single author by definition of what it records - the one agent doing the orchestrating. The store takes no cross-process lock, so do not point two orchestrators at one workspace.

Wiring the lease into a worker

A declared boundary grades nothing until the writing process says which lease it is, and it says that through its ENVIRONMENT. So the orchestrator that spawns a worker exports the id into that worker's environment, and the hook process the worker's host launches inherits it from there:

export BAGGAGE=magus.lease=<its id>

That is the W3C Baggage channel, carried in the environment under the OpenTelemetry convention, and magus.lease is the one member a verdict reads. Export TRACEPARENT too when your host has one, and add magus.spawner=<your label> to the baggage: magus records the trace, the parent span and the label as CLAIMS for magus session ls to show, and keys no verdict on them. The magus-multi-agent skill requires this of every worker prompt it writes, in the same spelling.

Exporting it is the ORCHESTRATOR's job today. The shipped guard templates pass --agent-name and --session, which are attribution, and nothing that names a lease - so a worker whose orchestrator never exported the variable is graded as an editor magus cannot attribute, which is an advisory rather than a deny and leaves every rule above it inert. A wrapper that builds its own argv can pass magus session hook --lease <id> instead; an explicit flag wins over the environment.

Watch it: Dashboard's Lease plan

The console's Dashboard includes a Lease plan mode that draws a plan as the DAG it is, from either of the two places a plan comes from. Both share the stage, the state colors, and the accessible node list beside the drawing, so a reader does not learn the picture twice.

  • The declared plan is the ledger: one node per lease, indented by parent, joined to the live activity feeds so a row shows what its worker is doing now. A lease in a reported overlap is marked on both rows, in the word "overlap" and in the warning color; a live row carries how long since it was last touched, and says "stale" once that passes ten minutes. The released paths and their digests read in the detail beside the row.
  • The run plan is the target DAG the engine resolves for plain human work, served by GET /api/v1/plan. Nobody declared it, so nothing about it can go stale the way a hand-kept table can, and it follows the live run: with no ?target the daemon picks the anchor itself and the overview line says how it picked.

Which one opens is decided by the data rather than by a preference. A ledger with rows in it means an orchestration is in flight, which is the more specific answer; anything else hands the surface to the run plan, which is what a person doing plain work came for. no_return gets its own color and belongs to the declared plan alone - the run plan never invents one, because an engine that resolved a DAG knows what happened to every node in it.

Both routes are read-only GETs on the loopback daemon, behind the same bearer token as the rest of the console. Start it with magus server start; see the daemon.

The spawn is recorded, never judged

Wire your host's sub-agent tool to the same magus session hook call as the rest of the guard. A payload carrying a prompt rather than a command or a file path is a lease handoff: magus records it as an agent_spawn event on the local Activity Trail and returns pass without evaluating a single rule.

That exemption is the point, not an oversight. There is no command and no path to judge, only a context transfer to note - and a prompt that merely MENTIONS a denied command would otherwise block the lease that describes it. The handed context is routinely kilobytes, so it lands as a content-addressed blob and only its reference rides the event.

magus does not switch on your host's tool name anywhere: a payload carrying a prompt IS a spawn, and the callee label the host supplies becomes the event's action so a page of leases groups by what was spawned.

Joining an event to a ledger row is cooperative. Nothing in a host event names a magus lease and magus will not infer one from prose, so the lease is stamped only when the handed context's FIRST non-blank line reads:

lease: <id>

Use the same id you passed to magus_ledger. An orchestrator that wants the join writes the marker; one that does not gets an event with no lease, which is a missing join rather than a wrong one. A marker line quoted deeper in a prompt stamps nothing, on purpose.

Verify against the diff

A worker's report of what it changed is a claim. The checkpoint is what turns it into something you can check.

  1. Diff the actual tree against the lease's checkpoint, and compare THAT against the row's owned and forbidden paths. magus graph diff --rev <revision> gives the domain-level answer; git diff <revision> | magus diff - annotates each changed file with its reach, public-surface exposure, and referents. See magus diff - it refuses a git ref given positionally, so the pipe is the sanctioned spelling.
  2. Check the dirty half of the token. A checkpoint whose digest differs from the tree you are diffing means the worker saw a different uncommitted tree, and the comparison you are about to make is not the one you think.
  3. Take acceptance evidence as an output reference the root reopens, never a worker's prose. A worker that ran a filtered subset and one that quietly restated its criteria both report success, and a transcript cannot tell you which happened.
  4. Regenerate declared outputs once, centrally, after the source work converges, then run the release gate yourself.

The same object serves review time. If you recorded a checkpoint when you stopped reading, the delta since then is the incremental-review flow on the agents hub - handing work out and picking review back up read the same identity.

What magus never does here

  • Block a writer it cannot attribute. Only a process that named a live lease is graded against a declared boundary; anyone else editing this workspace is advised at most, because a human in their own checkout names no lease either.
  • Transition a row, or derive a state or a completion from one. Every state in the ledger was written by the agent that declared the plan.
  • Judge a lease prompt, or let one change a guard verdict.
  • Mint anything for a checkpoint - no tag, no stash, no ref, no file.
  • Inject any of this into an agent's context. Every surface here is pull-based, and the knowledge graph the partition is argued from is read the same way.
agentsleasescheckpointledgerplanmagus vcs checkpointmagus_ledgerconsoleactivity
Last updated (4f8cc295)
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.

Engine

The interpreter a magusfile runs on; magus embeds 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.

Sandbox

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

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.

Trace

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

Span

OpenTelemetry's name for one unit of work under a trace - a target execution, whose sub-operations are child spans. An output reference points at a span's captured output. See telemetry.

Knowledge graph

The queryable graph of a workspace's spells, targets, docs, and code relationships; query it with magus query/explain/path. 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.

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.