Skip to content
Jose Miguel Ochoa edited this page Oct 4, 2026 · 7 revisions

loadout

Every machine you own carries a loadout — the set of programs it's equipped with, the way each one gets installed, and the maintenance steps that keep it healthy. On most machines that loadout is implicit: it lives in shell history, in "oh right, I installed that from a tap", in the drift between the laptop you set up carefully and the desktop you set up in a hurry.

loadout (the tool) makes the loadout explicit. You declare it once, in a git repo; every machine converges to its declared loadout, observes itself continuously, and publishes what it actually has — so drift, in every direction, is always one command away from visible.

The three truths

Everything in loadout is one of three kinds of truth, and they never mix:

Truth Where it lives Who writes it
Declared intent — what each machine's loadout should be loadout.yaml, the fragments it lists, machines/, profiles/ you, deliberately, in commits
Observed reality — what each machine actually has state/<machine>.json the tool, only for the machine it runs on
Remote candidates — what the outside world offers nowhere (asked live) loadout outdated asks; nothing is stored

The engine that connects them is the check: a re-askable command that proves a piece of the loadout is really there (rpm -q kitty, chezmoi verify, test -f ~/.ssh/config). loadout never trusts "it ran once" — convergence means making the checks pass, and observation means asking them again. Where a check lives follows where the truth lives: a package database, a binary's version output, or a script you write only when neither knows.

Why "loadouts", plural

One repo holds the loadouts of your whole fleet — and, if you like, its dotfiles too, each tool's fragment beside its config, observed and applied like everything else (Repo layout). Machines of the same kind share small profiles (profiles/omarchy.yaml, profiles/macos.yaml), and each real machine's file declares only what makes it different — down to a one-line file for a machine that's pure standard issue:

# machines/new-macbook.yaml
extends: [macos]

Machines see each other only through the state files they commit — plain git, no server, works offline. loadout diff lays the fleet side by side.

Design stance

  • Explicit over implicit, everywhere. No package-manager auto-detection, no fallbacks, no heuristics. Every mapping is written down; errors beat guesses; the error message carries the fix.
  • Mechanics ship with the tool; intent lives in your repo. dnf, dnf-repo (a vendor rpm repository), dnf-copr, brew, brew-cask, flatpak, apt, pacman, omarchy and omarchy-aur are built in — how to install, how to check, how to ask what's newer. Your repo says which programs and which machine gets them from where. loadout installers shows what a name means, your own installers: entry with the same name replaces one, and loadout installers --eject hands you the lot. Built in is not detected: nothing picks an installer for you.
  • Checks are the truth. Success isn't an exit code — it's the check passing afterwards.
  • Converging installs; upgrading is its own verb. setup-new-machine and install add what's missing and never move a version that's already there. loadout upgrade moves versions — a whole mechanism at a time (dnf, brew…), never a single package, because partial upgrades are what package managers exist to avoid. Pins you own (a version in .tool-versions, a plugin clone) are the exception: those update one item at a time, through a command your oracle declares.
  • Intent and observation never mix. The tool never edits your authored files; you never edit state.
  • The mechanism lives inside; the concern is the name. Scripts are named for what they assert (dotfiles-pull, setup-git), not for the tool that does it.

Pages

  • Repo layout — loadout.yaml, where fragments live, paths relative to their file, machines, profiles and data.
  • Writing your manifest — start with a one-line loadout and grow it: installers, variants, scripts, profiles.
  • A day with loadout — the whole lifecycle in practice: observing, maintaining, adding gear, new-machine day.
  • A real repo — the author's live fleet config and dotfiles; every pattern on these pages links into it.

Install

$ curl -fsSL https://raw.githubusercontent.com/josemiguelo/loadout/master/install.sh | sh

One static binary (Kotlin/Native — no JVM, no runtime dependencies) for linux-x64, macos-arm64, macos-x64. It shells out to your package managers and git, so those must be on PATH. Already installed? loadout self-upgrade.

Then just run loadout: on a terminal the bare command is the home screen — four rows (programs, scripts, remote, fleet), each with its verdict and the one key that resolves it. Everything it shows is a command you could have run yourself; the day page walks it.

Clone this wiki locally