A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
docs/INSTALL.md
Installing Majordomus
What it is
- URI
majordomus://document/docs/INSTALL.md- Kind
document- Identity
docs/INSTALL.md- Path
docs/INSTALL.md- Provenance
- generated
- Media type
text/markdown- As a capability
- document.docs/INSTALL.md
This file is generated. Editing it is pointless: the generator overwrites it, and `majordomus generate --check` fails while it differs.
Front matter
{}Content
# Installing Majordomus
<!-- GENERATED FILE — DO NOT EDIT DIRECTLY
Source: share/install/INSTALL.md.in (the prose) and share/distribution.yaml (every platform, name and URL);
regenerate with `majordomus generate`
Generator: majordomus-cli 0.29.0 -->
## Quick install
```bash
curl -fsSL https://majordomus.dev/install.sh | sh
```
Then, in the repository you want supervised:
```bash
majordomus init
```
## Install and initialise in one command
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --init
```
`--init` runs `majordomus init` in the current directory using the executable that was just
installed, by its absolute path, so it does not depend on your `PATH` having been reloaded.
If installation succeeds and initialisation fails, the installer says so in those words and
leaves the working installation in place.
## Personal mode
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --personal
```
For using the tool as your own in a repository other people share: your team's, a
client's, an open-source project's. `--personal` runs `majordomus init --personal` in the
current directory. It creates the same layer a plain `init` creates and changes nothing the
repository shares.
- No tracked file is changed and nothing is added to `.gitignore`. The layer is covered by
a marked block in the git directory's `info/exclude`, a file git never commits, pushes or
clones.
- `majordomus init --personal` reads `git status` before it writes and exits 10 unless it
reads the same afterwards. The installer then compares the status again by itself and
prints `Verified (personal)`.
- `majordomus update` and `majordomus capture install` cover each file before they write it and
leave a file the project already tracks alone. `majordomus doctor` re-verifies the cover on
every run.
- The layer is this checkout's. It does not travel with a clone, a push or a stash.
When the trial has made its case, hand the layer to the team:
```bash
majordomus init --extend --shared
```
It removes the cover, adds the two `.gitignore` lines a plain `init` adds, and prints what
is now the repository's to commit. It commits nothing; that step is yours. A file that is
one person's by its own name, such as `CLAUDE.local.md`, stays covered and stays yours.
To stop instead, delete the block between `# >>> majordomus personal >>>` and
`# <<< majordomus personal <<<` and the files it lists.
Personal mode keeps a layer apart from what a repository shares. It is not access control,
and it is not a way around an organisation's rules about tools. The decision is ADR 0145;
[`PERSONAL_MODE.md`](PERSONAL_MODE.md) is the whole account: what it is for, what stays
visible, and the way from a personal layer to a shared one.
## Verify
```bash
majordomus --version
majordomus doctor
```
`doctor` reports whether the layer resolves, whether every enforcement it claims is actually
wired, and which hook lines are still missing.
## What it does to your machine
Nothing outside two places, and never as root:
```text
$HOME/.local/share/majordomus/versions/<version>/ the release, unpacked
$HOME/.local/bin/majordomus a launcher
$HOME/.local/bin/majordomus-mcp a launcher for the MCP server
```
The launchers are two-line shell scripts that exec the versioned tree. No shell profile is
edited, no package manager is invoked, and `sudo` is never run: if a directory is not
writable the installer says which one and stops.
## Supported platforms
| Platform | Architecture | libc | Rust target | Status |
|---|---|---|---|---|
| macOS | ARM64 | — | `aarch64-apple-darwin` | supported |
| macOS | x86_64 | — | `x86_64-apple-darwin` | supported |
| Linux | x86_64 | glibc | `x86_64-unknown-linux-gnu` | supported |
| Linux | x86_64 | musl | `x86_64-unknown-linux-musl` | supported |
| Linux | ARM64 | glibc | `aarch64-unknown-linux-gnu` | supported |
| Linux | ARM64 | musl | `aarch64-unknown-linux-musl` | supported |
| Windows | x86_64 | — | `x86_64-pc-windows-msvc` | unavailable |
That table is generated from `share/distribution.yaml`, which is the one place a platform is
declared. The installer resolves your machine to a row of it from `uname -s`, `uname -m` and,
on Linux, the C library it finds; the release build matrix is generated from the same rows,
so a platform listed here is a platform a release actually built.
**Windows x86_64** (`x86_64-pc-windows-msvc`) — The command a person runs is bash: bin/majordomus and lib/*.sh are POSIX shell, and the archive carries them beside the executable. Until that half has a Windows answer, publishing a Windows archive would ship an executable nothing can drive.
## Choosing where it goes
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --install-dir "$HOME/bin"
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --prefix "$HOME/opt/majordomus"
```
or, equivalently:
```bash
MAJORDOMUS_INSTALL_DIR="$HOME/bin" curl -fsSL https://majordomus.dev/install.sh | sh
```
## Pinning a version
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --version v0.29.0
```
A pinned installation resolves `https://majordomus.dev/releases/v0.29.0.json`, which names the exact artifact and its
sha256 digest, and therefore installs the same bytes every time. An unpinned
installation resolves `https://majordomus.dev/releases/latest.json`, which is the latest stable release and moves
forward as releases are published. Use the pinned form in CI.
## Using it in CI
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --version v0.29.0
export PATH="$HOME/.local/bin:$PATH"
majordomus --version
```
The installer needs no interaction and asks none: everything it does is decided by its
arguments and environment. Pin the version so that a new release cannot change a build that
used to pass.
## Upgrading and reinstalling
Run the same command again. The installer is idempotent:
- the same version already installed — it says so and exits 0;
- an older version installed — it upgrades, and the previous installation keeps working
until the moment the launcher is replaced;
- a newer version installed and no version pinned — it refuses to move you backwards, and
says how to do it anyway (`--force`, or `--version`).
## Uninstalling
```bash
rm -f $HOME/.local/bin/majordomus $HOME/.local/bin/majordomus-mcp
rm -rf $HOME/.local/share/majordomus
```
That is the whole of it. It removes the tool. It does **not** remove any repository's
`.ai/` directory: your policy, rules, decisions, plan and history are the repository's, not
the tool's, and no command of this project deletes them.
## Releases
| Release | Published | Channel | Artifacts | Metadata |
|---|---|---|---|---|
| `v0.29.0` (latest) | 2026-10-17 | stable | 6 | [`v0.29.0.json`](https://majordomus.dev/releases/v0.29.0.json) |
| `v0.28.0` | 2026-10-17 | stable | 6 | [`v0.28.0.json`](https://majordomus.dev/releases/v0.28.0.json) |
| `v0.27.0` | 2026-10-16 | stable | 6 | [`v0.27.0.json`](https://majordomus.dev/releases/v0.27.0.json) |
| `v0.26.0` | 2026-10-14 | stable | 6 | [`v0.26.0.json`](https://majordomus.dev/releases/v0.26.0.json) |
| `v0.25.0` | 2026-10-14 | stable | 6 | [`v0.25.0.json`](https://majordomus.dev/releases/v0.25.0.json) |
| `v0.24.1` | 2026-10-14 | stable | 6 | [`v0.24.1.json`](https://majordomus.dev/releases/v0.24.1.json) |
| `v0.23.0` | 2026-10-13 | stable | 6 | [`v0.23.0.json`](https://majordomus.dev/releases/v0.23.0.json) |
| `v0.22.0` | 2026-10-13 | stable | 6 | [`v0.22.0.json`](https://majordomus.dev/releases/v0.22.0.json) |
| `v0.21.0` | 2026-10-12 | stable | 6 | [`v0.21.0.json`](https://majordomus.dev/releases/v0.21.0.json) |
| `v0.20.0` | 2026-10-10 | stable | 6 | [`v0.20.0.json`](https://majordomus.dev/releases/v0.20.0.json) |
| `v0.19.1` | 2026-10-10 | stable | 6 | [`v0.19.1.json`](https://majordomus.dev/releases/v0.19.1.json) |
| `v0.19.0` | 2026-10-09 | stable | 6 | [`v0.19.0.json`](https://majordomus.dev/releases/v0.19.0.json) |
| `v0.18.0` | 2026-10-09 | stable | 6 | [`v0.18.0.json`](https://majordomus.dev/releases/v0.18.0.json) |
| `v0.17.0` | 2026-10-08 | stable | 6 | [`v0.17.0.json`](https://majordomus.dev/releases/v0.17.0.json) |
| `v0.16.0` | 2026-10-08 | stable | 6 | [`v0.16.0.json`](https://majordomus.dev/releases/v0.16.0.json) |
| `v0.15.0` | 2026-10-07 | stable | 6 | [`v0.15.0.json`](https://majordomus.dev/releases/v0.15.0.json) |
| `v0.14.0` | 2026-10-06 | stable | 6 | [`v0.14.0.json`](https://majordomus.dev/releases/v0.14.0.json) |
| `v0.13.2` | 2026-10-06 | stable | 6 | [`v0.13.2.json`](https://majordomus.dev/releases/v0.13.2.json) |
| `v0.13.1` | 2026-10-04 | stable | 6 | [`v0.13.1.json`](https://majordomus.dev/releases/v0.13.1.json) |
| `v0.13.0` | 2026-10-04 | stable | 6 | [`v0.13.0.json`](https://majordomus.dev/releases/v0.13.0.json) |
| `v0.12.0` | 2026-10-03 | stable | 6 | [`v0.12.0.json`](https://majordomus.dev/releases/v0.12.0.json) |
| `v0.11.0` | 2026-10-02 | stable | 6 | [`v0.11.0.json`](https://majordomus.dev/releases/v0.11.0.json) |
| `v0.10.0` | 2026-09-29 | stable | 6 | [`v0.10.0.json`](https://majordomus.dev/releases/v0.10.0.json) |
| `v0.9.0` | 2026-09-25 | stable | 6 | [`v0.9.0.json`](https://majordomus.dev/releases/v0.9.0.json) |
| `v0.8.0` | 2026-09-20 | stable | 6 | [`v0.8.0.json`](https://majordomus.dev/releases/v0.8.0.json) |
| `v0.7.0` | 2026-09-15 | stable | 6 | [`v0.7.0.json`](https://majordomus.dev/releases/v0.7.0.json) |
| `v0.6.0` | 2026-09-12 | stable | 6 | [`v0.6.0.json`](https://majordomus.dev/releases/v0.6.0.json) |
| `v0.5.0` | 2026-09-11 | stable | 6 | [`v0.5.0.json`](https://majordomus.dev/releases/v0.5.0.json) |
| `v0.3.1` | 2026-09-08 | stable | 6 | [`v0.3.1.json`](https://majordomus.dev/releases/v0.3.1.json) |
Each release publishes one archive per supported target plus a `SHA256SUMS` file, and
its metadata is served as JSON beside the installer. The installer reads that JSON and never
GitHub's API or HTML, so a change in GitHub's pages cannot break an installation.
## Security model
What is protected, and how:
- **The metadata is fetched over HTTPS**, with redirects restricted to HTTPS. A base URL
that is not HTTPS is refused unless two explicit environment variables say otherwise, which
exists so the installer's own tests can serve fixtures.
- **The artifact is verified before it is unpacked.** The metadata carries a sha256
digest and a size; the installer checks both and, on a mismatch, discards the download and
stops. There is no "warn and continue".
- **The artifact URL is checked against the project's own release host** before anything is
fetched from it, and every value read out of the metadata is matched against the shape it
must have. Nothing read over the network reaches a command line, a path or the shell.
- **The archive is inspected before extraction.** Absolute paths, `..` traversal, symbolic
and hard links, devices, and any entry outside the archive's own directory are refused by
name and nothing is unpacked.
- **The installation is atomic.** The new tree is unpacked beside the old one and its
executable is run once, from a temporary location, to prove it reports the version that was
resolved. Only then is the launcher replaced, by a rename. Any failure before that leaves
the previous installation exactly as it was.
- **Nothing is elevated.** `sudo` appears nowhere in the installer.
What remains trusted: GitHub Pages serving the metadata, GitHub Releases serving the
artifacts, and the release pipeline that produced both. Checksums bind the artifact to the
metadata; they do not, on their own, prove who wrote the metadata. That is what provenance
is for: every release archive is attested by the release workflow, and where the GitHub CLI
is installed and signed in the installer asks it whether this archive was built by this
repository's workflow. The closing report says which it verified — `provenance (…) and
checksum`, or `checksum only` with the reason. `MAJORDOMUS_REQUIRE_PROVENANCE=1` installs
nothing short of verified provenance. By hand: `gh attestation verify <archive> --repo
<repository>`. What each path verifies is in `docs/DISTRIBUTION.md`.
## Reading it before running it
`curl … | sh` runs a script you have not read. If you would rather read it first:
```bash
curl -fsSL https://majordomus.dev/install.sh -o install-majordomus.sh
less install-majordomus.sh
sh install-majordomus.sh
```
The installer is one file with no dependencies beyond `curl` or `wget`, `tar`, and one of
`sha256sum` or `openssl`. Its top half is generated from the distribution model and
its bottom half is behaviour; both are reviewed in this repository and linted by
`shellcheck` in CI.
## Troubleshooting
**`majordomus: command not found` after installing.** The launcher directory is not on your
`PATH`. The installer prints the exact line to add; it does not edit your shell profile.
**"does not provide a prebuilt binary for".** Your machine resolved to no supported target.
The message names what was detected and lists what is supported. There is no automatic
fallback to building from source: that would need the toolchain this installer promises not
to require.
**"the downloaded archive does not match its digest".** Stop. Nothing was installed. Run it
again; if it happens twice, the artifact or the metadata is wrong and forcing it would be
the wrong response.
**Behind a proxy.** `curl` and `wget` read the usual `https_proxy` environment; the
installer adds nothing of its own.
**Seeing what it would do.**
```bash
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --dry-run
curl -fsSL https://majordomus.dev/install.sh | sh -s -- --verbose
```
`--dry-run` resolves the platform, the release and every path, prints them, and changes
nothing.
## Building from source
For contributors, not for installation. The repository's own tooling is documented in
`CONTRIBUTING.md`:
```bash
git clone https://github.com/korczis/prismatic-majordomus
cd majordomus
cargo build --release --manifest-path apps/majordomus-cli/Cargo.toml
```
The shell tool needs no build at all: `bin/majordomus` runs from a checkout. Use the
installer for everything else — a source checkout is a development environment, not an
installation.
## How this works underneath
The architecture, the trust path, the release procedure and how to add a platform are in
[`DISTRIBUTION.md`](DISTRIBUTION.md).