The change
The ecosystem change: planned in the brain, executed across every repo the feature touches, closing back into the brain. The verb the other three jobs serve.
multivac change new "points expire"
multivac change plan <slug> # which repos, in what order, which invariants it touches
multivac change apply <slug> # branch per repo from origin/main, edits, commits
multivac change land <slug> # MRs respecting the declared order
multivac change close <slug> # updates the brain and verifies the declared claimsFour declared fields
A change declares, before anything is touched:
Which repos it touches. Registry keys. A repo that doesn’t exist yet is legal — greenfield
applycreates it.Landing order — ordered stages. Each stage is a list of repo keys; repos in the same stage land in parallel; a stage lands only after every earlier stage:
landing_order: - [api] # web and worker consume what api serves - [web, worker]The order is law for
land; declare only the ordering that is a real constraint — an empty list is one parallel stage.Which invariants it touches, under the rule: an invariant is never relaxed in code — it is changed in the law first, dated, in the same change.
Which claims it makes true, with their anchors. This is the contract
closeverifies. Draft the anchors now, while the promise is fresh — after merge nobody remembers.
The change file
A change is a file in the brain: .multivac/changes/<slug>.md, carrying the four
declared fields plus per-repo status
(planned / branched / committed / MR / landed). That file is the state the
five subcommands read and write, across days and machines. On close it is
archived, never deleted.
Done when its anchors resolve
A change is not done when it merges. It is done when its anchors resolve.
Because the claims were declared up front, close doesn’t ask whether
someone updated the docs — it re-runs verify scoped to the declared
claims and refuses to archive until:
- every claim in field 4 resolves ok or moved on its new anchors,
- every declared repo is recorded landed,
- the SDD’s own artifacts exist, where one is declared.
That scope is deliberate and it is narrower than it sounds: close evaluates
the claim IDs the change declared, not the rows under touches or
retires, and it never runs an unscoped verify. An amended row that nobody
listed as a claim is not re-checked here — the pre-commit hook is what catches
it, on every commit, which is the earlier and stricter place. Declare the rows
you amend as claims if you want close to be the one that answers.
Updating the documentation stops being discipline and becomes mechanism. Nothing new is invented: the change declares before what today gets checked after, when anyone remembers.
The ritual
Closing a change is a ceremony, and only half of it is mechanical. multivac executes that half — the landing order held, every declared claim resolves, no invariant was relaxed in code instead of in the law. The other half is the team’s: who reviews what, who gets told, what ships before what when the reason is not technical. No tool can invent those, and none can check them.
So the team writes them, one line each, in .multivac/ritual.md next to the
law — and close prints them verbatim once the gate has passed and the
change is archived:
$ mvac change close points-expire
INV-02: ok
archived -> .multivac/changes/archive/points-expire.md
archived — commit this on a branch; nothing lands on main directly:
git -C ~/eco/brain switch -c close-points-expire && git add -- .multivac/changes/archive/points-expire.md .multivac/changes/points-expire.md && git commit -m "Archive the points-expire change" && git push -u origin close-points-expire
then open MR close-points-expire -> main
ritual (.multivac/ritual.md) — multivac cannot check these; walk them with the user:
- [ ] tell support before the flag flips
- [ ] the public site ships before the backendPrinted, not verified. Nothing gates on the ritual, nothing parses it; an
empty or absent ritual prints nothing at all. init scaffolds the file with
a single comment saying what belongs there, and the brain door names it.
It gets its own file rather than a section of the law because the law is
parsed — verify reads its anchors, plan reads its state cells — and the
ritual is prose the tool only ever prints.
Planned — a change that has not started (MV-89)
A roadmap is the list of things an ecosystem intends to do, and the brain
already keeps that list. Every change file is born open, which means a branch
is implied, an invariant id is reserved, and verify --strict counts it
against the next release. So without one more state, the only way to write an
intention down is to commit to starting it today — and the alternative people
reach for is a second list in a wiki or a tracker, which drifts from the first
within a week. Whichever list the tool does not read becomes fiction.
planned sits in front of the lifecycle:
planned → open → landed → closedIt is the same file, in the same directory, with the same schema, plus a
horizon of now, next or later. That is the entire ordering model: no
dates, no estimates, no rank, no dependencies between items. Starting the work
is change new <slug> on a slug that is already planned — the file is
promoted, not replaced, so the prose written when the idea was young
survives into the change that implements it. One document, one history.
Three properties make the state safe to use rather than decorative:
- It reserves nothing. An id allocated for work that may never happen is a
hole in the law table no later change can fill. Reservation stays at
change new, the moment the work actually begins. - It blocks nothing.
verify --strictrefuses to publish while a change is unclosed, which is correct for work in flight and catastrophic for an intention: the first roadmap entry would block every release for as long as the roadmap was not empty, which is forever. - It is not a gate.
change newon a slug nobody planned works exactly as it always did. Requiring a feature to appear on the roadmap first is unverifiable intent — the same category as the ritual, which is why the ritual is printed and never checked. A gate everyone learns to skip at three in the morning teaches people to work around the tool.
Every later step — plan, apply, land, close — refuses a change that has
not started, and names change new as the step that comes first.
See roadmap
for the command, and Running changes
for the flow.
The ritual arrives with candidates (MV-98)
init used to write the ritual as a bare comment, and facing a blank page most
people write nothing — so the closing step printed nothing forever. It now
carries candidates drawn from what you declared, every one commented out.
An unadopted ceremony is not a ceremony. Uncomment what your team actually owes each other and delete the rest; nothing is asserted on your behalf, and a commented line never prints. A fresh brain still prints nothing at close, which is exactly what it did before.
Only things no check could decide are seeded. A declared grapher contributes none: its work is automatic and a gate already requires its artifact, so putting it in the ritual would move a checked thing onto a poster.
The ritual is authored — written once by you, never overwritten by any
command. That is the opposite of flow.md, which is
derived and rewritten whole on every projection.
The subcommands
- plan resolves the declaration against reality: which declared repos
are present, what the order implies, what the change touches. A declared
repo missing locally gets cloned here — an explicit operation that needs
it, the same contract as
git submodule update. - apply branches each repo from its default branch, resolved in that
order: where
origin/HEADpoints, then this machine’sinit.defaultBranch, thenmain, thenmaster— never a fixed name. A repo that doesn’t exist is created with its consumer door. The edits and commits are yours, on those branches. A declared SDD adapter’s apply step is printed here for you to run (--no-sddskips the printing and the later gate for one change). - land reports the MR order the stages dictate: what is ready to push
now, what is blocked behind an earlier stage. It opens nothing — multivac
has no forge integration — and
--landed <repo>is you recording a merge. - close is the gate above. On success the change file is archived; the rows the change promised are already in the law, enacted by the human.
Decisions made mid-change become claims at close: the agent proposes the row, the human enacts. This is the organic birth path — the main one at steady state.
Greenfield
A change whose repos don’t exist yet: apply creates them — git init,
first commit, consumer door with the brain mounted — so the first agent
session in each already knows the law. The brain precedes the code. No
second machinery: apply knows how to create, not only edit.