stock provisions the packages, tools, and runtimes declared in .store/packages.yaml — one YAML file, one command per machine. Listing brew, apt, and pacman side by side inside a group lets the same config serve your Arch desktop, Debian server, and macOS laptop without forks; stock runs whichever manager is actually installed.
Pair with store for dotfile symlinks, or use it alone — you stock a store with inventory.
Status: v0.3 shipping, unit-tested on the load-bearing paths (config parsing, runner dispatch, plan orchestration, install flow). The maintainer is the first real user; early adopters welcome.
TL;DR — on Arch, yay -S stock-bin. Anywhere else, go install github.com/cushycush/stock/cmd/stock@latest. Full matrix below.
Three packages, pick one:
yay -S stock-bin # prebuilt binary (recommended)
yay -S stock # source build
yay -S stock-git # tracks main; for contributorsnix run github:cushycush/stock -- doctor # run once
nix profile install github:cushycush/stock # install into your profile
nix develop github:cushycush/stock # dev shell with Go + gopls pinnedgo install github.com/cushycush/stock/cmd/stock@latestRequires Go 1.26+.
Cross-compiled zips for linux / darwin / windows on amd64 and arm64 (except windows / arm64) attach to every tagged release on the releases page.
stock reads .store/packages.yaml at the repo root. Each top-level group maps a manager key (brew, apt, pacman, …) to a list of package names. An optional when: clause gates the group to specific platforms, hostnames, or shells.
packages:
core:
pacman: [git, ripgrep, fd, bat]
apt: [git, ripgrep, fd-find, bat]
brew: [git, ripgrep, fd, bat]
when: { os: [linux, darwin] }
gui-linux:
pacman: [firefox, alacritty]
apt: [firefox-esr, alacritty]
when: { os: linux }
work-laptop:
brew: [tailscale, 1password-cli]
when: { hostname: [work-mbp, work-mbp-2] }Listing multiple managers inside one group is the intended pattern. stock runs whichever manager is available on the current machine; stock doctor only flags a group as unservable when none of its managers are installed. apt-on-Arch or brew-on-Linux are not warnings.
os, arch, distro, distro_version, hostname, shell, wsl. Each string field accepts a scalar (os: linux) or a list (os: [linux, darwin]). All specified fields must match; within a list, any entry matches. Semantics match store-core.
Day-to-day
stock install [group...]— install everything matching platform +when:stock diff [group...]— preview whatinstallwould change (read-only)stock doctor— verify managers, detect drift frompackages.yamlstock tui— read-only interactive dashboard (see below)
Maintenance
stock snapshot— write currently installed packages to.store/packages.yamlstock platform— print detected platform info
New machine
stock bootstrap— run hooks,install, thenstore(if available)
Flags
--dry-run— print commands that would run; don't execute. Works forinstallandbootstrap.snapshot --writewrites to.store/packages.yamlinstead of stdout. Add--forceto overwrite an existing file.--group <name>chooses the group header (defaulthost).--managers brew,cargorestricts which managers are snapshotted.bootstrap --skip-store— run hooks andinstall, but skip invoking thestorebinary afterwards.
Unknown commands fall back to stock-<name> on $PATH (git-style), so you can add your own subcommands without recompiling.
stock tui opens a keyboard-driven, read-only dashboard over the same packages.yaml the CLI works against. The screenshot at the top of this README is a live capture; the fixture and snapshot.py that produced it live under docs/hero-demo/.
The layout is a single vertical column: a ledger of every group at the top, the selected group's per-manager breakdown underneath. No panes, no outer frame — the design matches store's TUI so the pair reads as one product.
stock ~/dotfiles linux/amd64 store
─── 6 groups ─── ● 2 installed ◐ 1 partial ○ 1 missing — 1 skipped ✕ 1 unservable ─
casks no manager available ✕ unservable
cli 5 pkgs ● installed
▸ dev-tools 3 pkgs · 2 missing ◐ partial
editors 1 pkg ● installed
macos-gui needs os darwin — skipped
prompt-tools 2 pkgs missing ○ missing
─── dev-tools ─────────────────────────────────────────────── partial ─
apt (5 pkgs · not on this machine)
eza, lazygit, bat, atuin, starship
brew (5 pkgs · not on this machine)
eza, lazygit, bat, atuin, starship
pacman 3/5 installed · 2 missing
+ atuin
+ starship
j/k move / filter r refresh ? help q quit
Alternative managers that don't apply on the current platform are dimmed and labelled not on this machine — they're still declared in the config, so the TUI shows what's there rather than hiding it. The + lines mark what stock install would install.
Navigate
| Key | Action |
|---|---|
j / k |
Move up / down the group list |
g / G |
Top / bottom |
esc / h |
Clear the filter · close the top overlay |
Inspect
| Key | Action |
|---|---|
/ |
Filter groups by name (type, enter to commit, esc to clear) |
r |
Recompute against live manager state (useful after installing something in another shell) |
? |
Help overlay |
q / ctrl+c |
Quit |
The TUI does not run installers. Actions (install, diff, snapshot) stay on the CLI; the dashboard is a read-only inspector so touching pacman / apt / brew still requires typing the verb yourself.
stock runs executables placed under <root>/.store/hooks/ before and after install:
| Hook name | When it runs |
|---|---|
pre-install |
before stock install |
post-install |
after stock install |
pre-bootstrap |
at the start of stock bootstrap |
post-bootstrap |
at the end of stock bootstrap |
Hooks receive the standard STORE_* env vars plus STORE_ACTION=install (or bootstrap), and run with $STORE_ROOT as the working directory.
brew, pacman, apt, dnf (falls back to yum), zypper, apk, winget, cargo, go, npm, pipx, gem, brew-cask.
Contributions of new managers live in internal/managers/. Each file registers itself via init() and implements a short interface (Name, Available, Installed, Install, BootstrapHint).
make build # builds ./stock
make dogfood # ubuntu container with stock + a fixture mounted
make dogfood DISTRO=fedora # alternatives: ubuntu · debian · fedora · alpine · arch
go test ./...make dogfood is the preferred way to exercise real package managers against a clean slate without installing them on your host. The fixture under hack/dogfood/ includes a deliberately-broken group so stock doctor and stock install both have something to complain about.
- Uninstalling or pinning package versions.
stockis a declarative installer, not a full state reconciler. Use your package manager directly for removals or specific versions. - Shipping in nixpkgs upstream. The flake self-installs; upstream packaging is a separate ask.
store— the symlink managerstockpairs with. If both are on$PATH,storedelegates unknown subcommands tostockvia git-style dispatch (store stock doctor≡stock doctor), and its TUI header shows a dimstocksignpost so you know the companion is available.store-core— the shared Go module both tools import for platform detection,when:matching, and theSTORE_*hook env contract.
MIT. See LICENSE.
