Skip to content

Install

npx multivac@latest init

That is the whole thing. No install, no clone, no global.

Requirements

requirementwhy
Node.js ≥ 24declared in engines; the CLI is ESM and uses modern node: APIs
gitverify shells out to git ls-files; the brain and every repo are git-native

Nothing else. Three runtime dependencies — picomatch, yaml and citty — and that count is itself law: the third arrived as a design change with the row and the constitution moved before the package, and a fourth faces the same.

Try it, then keep it

npx fetches and runs without installing anything, which is the right shape for the first command you ever run against a repo:

npx multivac@latest doctor        # what it would find here
npx multivac@latest init          # write the brain

Once you know you want it, put it on your PATH so the hooks find it too:

npm i -g multivac@latest
# or: pnpm add -g multivac@latest

The hooks care which one you did. The shims try mvac on PATH first, then npx --no-install multivac, then a repo-local build. npx --no-install resolves a package already present in the project, not one it has to fetch — so a global install, or multivac as a devDependency of the brain, both arm the floor. npx multivac@latest typed by hand does not, because nothing persists.

Published on npm, MIT, and small enough to read: npx multivac@latest fetches the current release. The CLI surface below is what ships today, and the parts still moving say so where they appear.

Or from source

For working on multivac itself, or to run an unreleased commit:

git clone https://gitlab.com/ulm0/multivac
cd multivac
corepack pnpm install
pnpm run build
pnpm link --global      # optional; every command also works as `node /path/to/multivac/dist/cli.js`

The repo develops with pnpm and says so if you reach for another one:

$ npm install
multivac develops with pnpm — run: corepack pnpm install

That guard is scoped to the repo. Installing the published package with npm or npx is entirely fine — a tool that refused its own users’ package manager would be a tool nobody installs.

Two names, one binary

{
  "bin": {
    "multivac": "dist/cli.js",
    "mvac": "dist/cli.js"
  }
}

multivac and mvac are the same file. The docs use them interchangeably: multivac in prose where it reads better, mvac in shell blocks where it is shorter. The hooks look for mvac first — the shims try mvac on PATH, then npx --no-install multivac, then a repo-local dist/cli.js with its node_modules beside it. Expose mvac and the first rung hits; with none of the three the shim warns on stderr and exits 0, verifying nothing. See Hooks.

Check it

$ mvac --version

It prints the version in the package you installed. The site does not repeat that number anywhere — MV-84 keeps every version string off these pages, so there is nothing here to fall out of step. What holds the published version honest is MV-68: a release cannot publish under a tag that disagrees with the manifest.

$ mvac --help
multivac <command> [args]

commands:
  init       scaffold the brain: everything multivac owns under .multivac/
  seed       deterministic boundary inventory -> .multivac/seed-report.md
  verify     check anchors against the declared repos (deterministic, offline)
  count      dry-run an anchor leg: match count + per-file breakdown, verify's own matcher
  doors      project doors + install git hooks into the brain and declared repos
  doctor     what is declared, what was found, what is degraded, how to fix it
  repos      list declared repos; `repos sync [--shallow]` clones the missing, fetches the rest
  change     new/plan/apply/land/close — the ecosystem change lifecycle
  roadmap    the changes that have not started yet — list them, record one
  help       help <topic|command> — `help anchor` prints the anchor grammar on one screen
Built from source rather than installed? Then the version string is whatever package.json said at the commit you cloned, and the commit is the identity — a build between releases carries the previous release’s number.

Every machine needs its own runner

The hooks travel with the clone — core.hooksPath points at a versioned .multivac/hooks/ — but the binary does not. On a machine where none of the three runners resolves, the shim prints one warning to stderr and exits 0: the commit lands, unverified. That is deliberate, and it is why the install above is per machine and why multivac doctor names the runner it found, or says INACTIVE. See Hooks.

Next

Scaffold a brain: Getting started.