Someone wants to try the tool. They are not going to clone a repository, put bin/ on
their PATH, and read a contributing guide first, and they should not have to: a
supervisory tool that is hard to install is a tool that supervises nothing.
The other half of the situation is the one that makes curl | sh usually a bad idea. The
script is unread, the archive is unverified, a failure halfway leaves a broken binary where
a working one was, and an unsupported machine gets a confusing error instead of an answer.
setup: bare
given:
- 'a repository with no AI layer, and a machine with the tool already installed the way the installer installs it'
steps:
- id: version
run: ['version']
note: 'the installed tool says which release it is; the installer refused to install an archive whose executable said anything else'
expect:
exit: 0
stdout_contains: ['^majordomus [0-9]']
- id: init
run: ['init']
note: 'the command the installer points at next, in the repository you want supervised'
expect:
exit: 0
stdout_contains: ['next: majordomus update', 'next: majordomus doctor']
files_exist: ['.ai/repo/policy.yaml', '.ai/manifest.yaml']
- id: doctor
run: ['doctor']
note: 'the layer the installed tool created is a layer the installed tool accepts; the hook lines init printed are not in place yet, which is exactly what doctor is for'
expect:
exit: 12
stdout_contains: ['^OK layout .ai/']
then:
- 'nothing was installed into the project except .ai/ and the files the policy names'
- 'the hook line init printed names the launcher, so an upgrade does not break it'
- 'uninstalling removes the launchers and the prefix, and no repository state'
curl -fsSL https://majordomus.dev/install.sh | sh
majordomus init
or, in one line:
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --init
The installer resolves this machine from uname and, on Linux, from the C library it
finds; reads the release metadata this repository publishes rather than GitHub's API;
verifies the artifact's SHA-256 and size before unpacking anything; refuses an archive that
carries an absolute path, a traversal, a link or an entry outside its own directory; runs
the unpacked tool once to prove it reports the version that was resolved; and only then
replaces the launcher, by a rename.
--dry-run prints every one of those decisions and changes nothing. --version v0.2.0
pins a release, which is the form to use in CI.
A working majordomus on the PATH — or the exact line to add to make it so — and a
repository one command away from being supervised. Nothing was built, nothing was elevated,
and if anything had gone wrong the installation that was there before would still be the
installation that is there now.
The platforms this works on are not written down anywhere a person maintains: they are
share/distribution.yaml, and the installer's table, the release build, the documentation
and this page all read it (docs/DISTRIBUTION.md).
-
the installed tool says which release it is; the installer refused to install an archive whose executable said anything else
majordomus 1.0.0-alpha.8
- exit 0
- stdout_contains /^majordomus [0-9]/
-
the command the installer points at next, in the repository you want supervised
created
.ai/README.md
.ai/manifest.yaml
.ai/repo/README.md
.ai/repo/policy.yaml
.ai/repo/scope.yaml
.ai/repo/profiles/
.ai/repo/prompts/
.ai/repo/profiles/README.md
.ai/repo/prompts/README.md
.ai/repo/rules/README.md
.ai/repo/rules/project/README.md
.ai/repo/rules/vendor/majordomus/
.ai/repo/knowledge/
.ai/repo/knowledge/curated/README.md
.ai/repo/knowledge/candidates/README.md
.ai/repo/workflows/
.ai/repo/skills/
.ai/repo/adrs/
.ai/repo/use-cases/
.ai/repo/applications/
.ai/repo/why/
.ai/repo/features/
.ai/repo/sessions/README.md
.ai/repo/deployments/README.md
.ai/repo/project/README.md
.ai/repo/mesh/
.gitignore:.ai/local/
.gitignore:.ai/repo/**/.tmp.*
scope: no stack recognised at the root (looked for mix.exs, Cargo.toml); seeded only the entries every repository shares; add your own to .ai/repo/scope.yaml
local state: .ai/local/state/ (ignored by git; this checkout's own)
next: majordomus update # generate the provider instruction files named in the policy
next: majordomus doctor # verify nothing is declared that is not wired
hooks are not installed by init; add these two lines yourself, doctor verifies them:
pre-commit: majordomus doctor || exit $?
pre-push: majordomus finish --check || exit $?
- exit 0
- stdout_contains /next: majordomus update/
- stdout_contains /next: majordomus doctor/
- file_exists .ai/repo/policy.yaml
- file_exists .ai/manifest.yaml
-
the layer the installed tool created is a layer the installed tool accepts; the hook lines init printed are not in place yet, which is exactly what doctor is for
OK knowledge graph — buildable here: 0 node(s), 0 edge(s), compiled into a temporary file and removed; no stored index to go stale
OK knowledge records — 0 record(s) valid against knowledge/v1; every reference resolves [reproduce: majordomus knowledge check]
OK knowledge candidates — 0 await review, cap 40
OK layout .ai/manifest.yaml — schema ai-repository/v1
OK layout .ai/repo/scope.yaml — version 1; 14 in pathspec(s); every key is one the schema declares
OK layout .ai/local/ — ignored, and nothing under it is tracked
OK layout .ai/ — every section the manifest names exists; the layer is readable without the tool
OK layout .ai/repo/prompts — present
OK layout .ai/local/state/handovers — present, 0 record(s)
OK layout .ai/local/state/checkpoints — present, 0 record(s)
OK records ledger.jsonl — every line is a well-formed event
OK policy 39 key(s) — every policy value the code reads is declared, with no reader-side default
OK bootstrap 3 projection(s) — each points at .ai/README.md, carries no rule of its own and names only rules in force
OK catalogue 0 use case(s), 0 application(s) — every command, doctrine, claim, responsibility, category, setup and cross-reference resolves, both directions
OK context .ai/ — 20 context document(s) carry the contract; ids unique, references resolve, no final document superseded, no cycle [reproduce: majordomus context validate]
OK policy .ai/repo/policy.yaml — parsed, version 1
OK profiles 4 files — parsed; default 'implementation' exists
INFO adr .ai/repo/adrs/ — no decisions; nothing to validate
OK records decisions.md — every entry is attributable
INFO project .ai/repo/project — no canonical project model here; nothing to validate
OK command surface — 30 public command(s), reconciled against the dispatch table [reproduce: majordomus doctor]
OK doctrine 50 of 61 rule(s) carry a validator — validator, dispatch, propagation, test and CI resolve for every one of the 50; the remaining 11 declare no validator and this check does not examine them
FAIL wiring doctor-on-commit — hook .git/hooks/pre-commit does not exist [reproduce: ls -l .git/hooks/pre-commit]
FAIL wiring finish-on-push — hook .git/hooks/pre-push does not exist [reproduce: ls -l .git/hooks/pre-push]
OK command coverage — every public command is exercised and refuted [reproduce: bash test/run.sh 31_command_coverage]
OK resolver handovers — no record for this worktree and branch (absence, not a stale match) [reproduce: majordomus handover --resolve]
OK lifecycle ledger — no ledger yet; nothing has happened here to be silent about
OK knowledge wiring — the close path and the compaction adapter call the deriver
OK knowledge deriver — no ledger yet; no episode has closed here
INFO project .ai/repo/project — no canonical project model here; nothing to validate
FAIL projection AGENTS.md — missing (run: majordomus update) [reproduce: majordomus update]
FAIL projection CLAUDE.md — missing (run: majordomus update) [reproduce: majordomus update]
FAIL projection GEMINI.md — missing (run: majordomus update) [reproduce: majordomus update]
OK context builder — 21 lines, budget 300 [reproduce: majordomus context]
OK capture share/schemas/majordomus/capture/capture.v1 — 2 file(s) describe majordomus.capture/v1 at the path the identifier derives: the record as JSON Schema, the document as protobuf
OK capture .ai/local/prompts — ignored and untracked
OK capture .ai/local/prompts — no records yet; the archive is empty
OK capture .ai/local/prompts — every prompt is present as all three: the record, the Markdown and the YAML
OK prompts .ai/local/prompts — the archive and every record in it are readable by their owner only
OK prompts .ai/local/prompts — no records yet; the archive is empty
OK prompt 4 asset(s) — front matter valid, every token known
OK records open-questions.md — every entry parses
OK retention ledger — 0 lines, cap 5000
OK retention handovers — 0 files, cap 200
OK retention checkpoints — 0 files, cap 500
OK retention sessions — 0 records, cap 500
INFO project .ai/repo/project — no canonical project model here; nothing to validate
OK rules .ai/repo/rules/vendor/majordomus — every file matches the manifest (1 (1.0.0-alpha.8))
OK rules 61 rule(s) — resolve in one deterministic order; vendored baseline plus project rules, no override — 51 carry a validator, 10 are normative text this tool does not check
OK rules blocking — all 44 blocking rule(s) carry a validator
OK schema rules — 61 rule(s) resolve in one order: the vendored baseline in manifest order, then the project's, as a dependency graph
OK schema share/kinds.yaml — 37 kind(s); every one that carries metadata declares a schema
OK schema share/schemas — 54 schema(s), each valid JSON and each applied — by a kind, through an allow-list the tool reads, by a validator that names it, or as a generated document's contract (15)
WARN session .ai/repo/sessions/ — 1 record(s) exist here and are committed nowhere, so they reach no surface: README.md [reproduce: git add .ai/repo/sessions && majordomus derive]
OK records 0 record(s) — every changed_files names work, not generated or local state
OK session .ai/local/session-contexts — ignored and untracked
OK session .ai/local/session-contexts — no working contexts yet; the store is empty
INFO skill .ai/repo/skills/ — no skills; nothing to validate
OK skill reachable — no personal command or skill shares a name with a projected skill [reproduce: majordomus run editors.status]
INFO use-case 30 advisory gap(s) — not covered by an active use case, and the policy does not require it: command:init command:update command:doctor command:watch command:start command:context command:checkpoint command:handover command:check command:finish command:history command:decision command:question command:prompt command:evidence command:skills command:capture command:search command:doctrine command:plan command:version command:session command:knowledge command:adr command:usecase command:rules command:migrate command:recover command:bench command:archive [reproduce: majordomus usecase coverage]
OK use-case 0 of 30 target(s) covered — every public command the policy requires is named and run by an active use case (policy use_cases.coverage)
INFO env - — bash <version>, git <version>, jq <version>, shellcheck present
WARN clone unpushed — commits on no remote: main(2) — work on one disk is invisible to every other session and cannot be integrated [reproduce: git push -u origin <branch>]
OK clone uncommitted — no linked worktree, so no uncommitted work can sit in one
INFO clone trunk — no remote-tracking branch, so this checkout's distance from the remote trunk cannot be measured
INFO clone release — no remote-tracking branch, so whether the trunk's landed work is released cannot be measured
· reasoning <decided by the advisors and the executable of the recording machine>
· layout - — <judged when the recording machine has built the executable>
· budget doctor — <timed against the policy budget>
doctor: 5 failure(s)
- exit 12
- stdout_contains /^OK layout .ai//
The chain from this page to the code: the use case names commands, rules and claims; each rule is dispatched from the registry and each claim names the test that proves it; the scenario above executed the commands. Nothing in this chain is prose about intent.
Computed from what they share: claims, rules, commands, category, applications. Nobody maintains this list.