Architecture
The insight everything follows from
Section titled “The insight everything follows from”An alias cannot be a binary. gpush and .. are shell state, not programs. A compiled tool can only ever hand your shell some text and ask it to evaluate it.
So the tool must emit shell no matter what language it is written in. Once it is a generator, keeping the functions as generated shell too is the consistent choice, and it keeps the binary out of the hot path entirely.
The CLI and the web interface are two front-ends over one configuration file. Neither runs when you open a shell.
Decisions
Section titled “Decisions”| Decision | Choice | Why |
|---|---|---|
| Product scope | Curated defaults, user-personalisable | The taste is the value. Personal values are data. |
| Language | Go | Single static binary, cross-compiles to both platforms, go:embed ships the web UI inside it |
| Web UI | On-demand localhost server | No daemon, no background surface |
| Shell integration | Generated file, sourced | Zero process spawn per shell start, and p/activate stay real functions |
| Shells | zsh and bash, pluggable backends | The interface existed from day one, so bash was a new file rather than a rewrite |
| Secrets | OS keychain | Secrets never land in a file |
| Sync | Git-backed config repository | Config is text. Credentials stay per-machine because a keychain is deliberately non-exportable |
Layout
Section titled “Layout”cmd/loadout/ cobra commands, one file per command groupinternal/ config/ schema, local.yaml overlay, validation catalog/ the shipped set, embedded with go:embed data/aliases.yaml 136 aliases with category, pack, platform, requires data/functions.yaml per-function metadata: summary, usage, requires data/functions/ text/template bodies, one per function data/scripts/ shipped executables generate/ rendering backend/ Backend interface; zsh and bash binaries/ fetch, verify, extract, install third-party executables credentials/ keychain: security, secret-tool, pass requires/ capability checks driving doctor, describe and the UI server/ localhost web UI and its access control web/ embedded page, no build step sync/ git-backed config repo, secret scanning selfupdate/ install-method detection, self-replacement uninstall/ inventory and removaltestdata/ fixture/config.yaml exercises every schema section golden/ pinned output: 2 shells x 2 platformsProduct versus user data
Section titled “Product versus user data”A clean split, and the reason emails can sit in plaintext configuration:
- The repository ships the product: Go source, the curated templates, the web UI.
~/.config/loadout/holds the user’s data.- The OS keychain holds credential values, and nothing else.
Nothing personal is committed to the repository. The test fixture and every example use illustrative values.
The backend abstraction
Section titled “The backend abstraction”The generator has a Backend interface with an implementation per shell dialect. Adding bash was one new file.
Every alias line the two backends emit is byte-identical. Only the preamble differs, because bash expands aliases in interactive shells only and needs shopt -s expand_aliases where zsh needs nothing.
The abstraction was never the risk. The risk was in the function bodies, and adding a second shell found four constructs that had been wrong all along — see Shell portability.
The requires mechanism
Section titled “The requires mechanism”One declaration per entry, driving three outputs:
pw: requires: - binary: code - config: workspacesloadout doctorreports everything unmet.- Calling an unconfigured command gives a real error instead of a silent failure.
- The web interface shows a green, amber or red indicator per entry.
They cannot drift apart because there is only one declaration.
This is where a review finding became a product feature. On the machine this was designed against, thirteen aliased tools were not installed, ls shadowed a real binary, dl pointed at a dead youtube-dl, and roughly twenty-eight aliases were Linux-only. A flat alias file cannot surface any of that.
Diff before apply
Section titled “Diff before apply”The tool writes a file sourced into every shell you open. Showing exactly what changes is what makes that trustworthy, and it is nearly free since text is being generated anyway.
A test asserts the applied file is byte-identical to what the diff previewed. A preview that can differ from the result is worse than no preview.
macOS parity
Section titled “macOS parity”Not a build flag. Real behavioural differences in the catalog, roughly twenty-eight aliases:
| Linux | macOS |
|---|---|
apt-get, dpkg -i | brew |
systemctl (7 aliases) | launchctl |
netstat -tulanp | lsof -i -P |
wg-quick, openvpn3 | different tooling |
Generating for darwin yields fewer aliases than Linux: some drop out entirely and several resolve differently.
Tool names were the easy half. The subtler risk is a command that exists on both and behaves differently — which is what sshp hit with find -regex, silently skipping every ed25519 key.