Repository navigation
Repo Layout
A loadout repo is yours to shape. One file at its root, loadout.yaml,
says where everything lives; every other file goes where it reads best —
including next to the dotfiles it maintains. This page covers the shape;
Writing your manifest covers what goes in it.
The live example, josemiguelo/.dotfiles, is one repo for loadout and chezmoi:
.chezmoiroot "configs" — chezmoi reads only configs/
loadout.yaml meta, layout, data
configs/ the dotfiles (chezmoi's source), each tool's fragment beside its config
private_dot_config/tmux/
tmux.conf.tmpl
.loadout.yaml tmux, tpack, tmux-plugins, its outdated source
.loadout/ the scripts that fragment runs
programs/ programs with no dotfiles: cli/, apps/, brew/, …
maintenance/ scripts with no dotfiles, a folder per concern; lib/ for shared helpers
profiles/ what machines of a kind share (omarchy, macos, fedora)
machines/ one file per real machine, named by hostname
state/ written by loadout, one file per machine
meta:
name: jm's machines
min-tool-version: "2.1.0"
layout:
fragments:
- programs/**/*.yaml
- maintenance/**/*.loadout.yaml
- configs/**/.loadout.yaml
machines: machines
profiles: profiles
state: state
configs: configs
data:
omarchy: false
work: false
kitty:
opacity: 0.85loadout.yaml may also hold installers, programs, scripts and
outdated sections itself, handy for a tiny repo.
-
fragmentslists the files that make up the manifest — programs, scripts, installers and outdated sources. Nothing is discovered behind your back: only what these globs match loads, in their order (path-sorted within each).*matches within a folder,**any depth,?one character. A wildcard never matches a name starting with a dot, so.loadout.yamlloads only because the glob spells the dot;.gitis never entered. -
machines,profilesandstateare folders.machinesandstateare required;profilesonly when a machine extends one. -
configsnames your dotfiles folder (chezmoi's source), when the repo holds them; loadout then observes and applies them too (Configs).
A bad layout fails in one line, naming the problem: a glob reaching
loadout.yaml or a machine file, a path leaving the repo, a folder key with
a wildcard.
Every path in a fragment — file, any file: command, a with value
marked file: — is relative to that fragment's folder, checked on every
load to exist inside the repo. Commands run in that folder too, so a script
reads its siblings by name. A tool's fragment can move with its config and
nothing inside it changes.
# configs/private_dot_config/tmux/.loadout.yaml
scripts:
tmux-plugins:
file: .loadout/plugins.sh # next to this file
check: "file:.loadout/plugins.sh check"Every command also gets LOADOUT_REPO (the repo's root), LOADOUT_FRAGMENT_DIR
(the folder it runs in), LOADOUT_MACHINE and LOADOUT_OS (linux or
macos), so a shared helper is one line away:
. "$LOADOUT_REPO/maintenance/lib/git-clones-behind.sh".
A program's command written by an installer runs in the installer's folder;
a variant's own command or check runs in the program's. That's what lets
an installer keep a helper script beside it
(programs/brew/).
With chezmoi, a tool's fragment can live in the tool's own config folder:
.loadout.yaml and .loadout/ start with a dot, and chezmoi never deploys
dot entries that aren't its own special files — so they stay in the repo and
never reach $HOME. A change to a tool (its config, its plugins, the script
that keeps them in sync) is then one folder and one commit.
A *.loadout.yaml fragment holds named sections: installers, programs,
scripts and outdated. Any other .yaml file under programs/ is one
program, named by its file name, with its top-level keys as its fields.
Tools with no dotfiles go under programs/ (what to install) or
maintenance/<concern>/ (scripts). A tool whose config is a single file in a
shared folder (~/.config/starship.toml) keeps its fragment in
programs/<tool>.yaml.
machines/<hostname>.yaml is a real machine; profiles/<name>.yaml is
something machines of a kind share. Both sit directly in their folder — the
file name is the name. A machine extends a list of profiles, sets its data,
and lists the programs it carries under install_with (see
Writing your manifest):
# machines/GFT-GJD4Y36T5V.yaml
extends: [macos]
data:
zscaler: true
work: trueloadout.yaml's data: declares every setting a machine may have, with its
default; machines and profiles override them under their own data:. A tool's
settings nest under its name, as kitty does above. A key nobody declared,
or of another kind, is a load error. loadout explain shows a machine's
merged settings.
Dotfile templates read the same settings, so the hostname never appears
inside a template — only as a file name. The live repo's chezmoi templates
branch on them through a small partial that merges loadout.yaml, the
machine file and its profiles exactly as loadout does:
{{ if (includeTemplate "machine" . | fromJson).omarchy }}
dynamic_background_opacity yes
{{ end }}
background_opacity {{ (includeTemplate "machine" . | fromJson).kitty.opacity }}
Live: configs/.chezmoitemplates/.
With configs set, loadout reads your dotfiles through chezmoi, using that
folder as chezmoi's source. Each top-level config is one entry: a folder
under ~/.config is named after the folder (tmux, nvim), anything else
after its first path segment (.zshenv, .local). What exists is
chezmoi's call: .chezmoiignore leaves a config out on a machine, and
nothing is opted in.
$ loadout status
…
CONFIG STATUS
✔ kitty applied
╭───────────────────────────────╮
│ ✘ zsh drifted │
│ .config/zsh/.zshrc │
╰───────────────────────────────╯Drifted means loadout apply would change those files: you pulled a
change, or edited one here.
$ loadout apply zsh # write that config (no names: all of them)
$ loadout explain zsh # its files, and its last verdict
$ loadout diff # every machine's configs side by sideOn the home screen, the configs row opens the same list with the drifted ones ticked; enter applies them.
apply, sync and the configs row stop when a file they'd replace was
edited on this machine, and name it. Keep your edit with chezmoi re-add <file>, or take
the repo's with loadout apply --force. Without chezmoi on PATH, the
configs are not checked, and status says so once.
state/<machine>.json is what loadout observed on that machine — written by
status, committed by sync, compared by diff. Nothing hand-edited goes
there.