The system is built on one decision repeated consistently: draw a hard boundary between what is identical on every machine and what changes with the OS or the operator. Get the boundary right and a single Core can serve every machine with zero special-casing.
One Core, vendored into 8 machine repos viagit subtree — each clone is self-contained (no submodule init).dotfiles-Kali stacks a Role layer on its OS layer; dotfiles-Windowscarries no core/ subtree and mirrors only the Neovim and starship configs. Edge colour tracks live vendoring drift — green = carrying Core v4.10.0, orange = behind (run a sync), cyan = replicated, with no vendored release to drift. Each vendoring repo's label shows the release it carries; the host's shows the Core ref its mirror came from.
How an OS repo consumes Core
Each machine repo (except Windows, which replicates Core natively in PowerShell) vendors dotfiles-core under core/ as a git subtree. That physically copies Core in and commits it, so the repo clones and works with no submodule flags — important, since these are public showcase repos people will browse.
# one-time, inside an OS repo:$ git subtree add --prefix=core https://github.com/dotgibson/dotfiles-core main --squash# later, to pull Core updates down:$ git subtree pull --prefix=core https://github.com/dotgibson/dotfiles-core main --squash
Maintainers fan a Core change out to every OS repo in one shot withscripts/sync-core.sh, which prints the exact short SHA each repo receives so a sync is traceable.
How it compares — and when it's the wrong tool
Every dotfiles approach is a trade. This one optimizes for clone-and-go self-containment across many machines and a public, per-machine portfolio — paying a little vendored duplication for it. Here's how that lands against the usual alternatives, each of which wins in its own case.
vs git submodule
A submodule stores a pointer, so a fresh clone is empty until git submodule update --init — the classic "I cloned it and nothing works" footgun. Subtree vendors the actual files, so every machine repo is self-contained and clone-and-go. The cost subtree pays back: a vendored copy in each repo (kept honest by the sync script + a manifest audit).
vs chezmoi / yadm
One repo + per-OS templates is the most DRY answer, and the right move the day you want to collapse the whole fleet into one. This system keeps the multi-repo portfolio instead — each machine is a clean, public, self-contained artifact. Because Core is already plain and OS-agnostic, moving to chezmoi later is a content migration, not a rewrite.
vs GNU stow
stow is a perfect, zero-magic symlink farmer over a single repo — and genuinely simpler if you have one machine. What it has no opinion about is layering or per-OS divergence, so a multi-OS setup drifts into host branches and .stow-local-ignore gymnastics. This system bakes the Core / OS / Role split in and ships its own idempotent symlinker (with backups + a dry-run).
vs a bare $HOME git repo
The git --bare + alias trick is the leanest possible — no symlinks, files live in $HOME. Hard to beat solo. But it has no layer model, no per-OS story, noisy status against your whole home dir, and it is a real footgun on a shared or multi-user box. This trades that leanness for an explicit, auditable structure.
When to reach for something else
A system that can't name its own constraints isn't worth trusting. Don't use this if:
You have one or two machines with no real OS spread — this is over-engineered for that; a bare $HOME repo or stow is far less ceremony.
You want ONE repo, not a fleet — reach for chezmoi or yadm. (The migration is content, not a rewrite, because Core is already plain.)
You can’t stomach any vendored duplication — the multi-repo + vendored-Core model deliberately trades a little duplication for clone-and-go self-containment and a public per-machine portfolio.
The canonical load order
Load order is load-bearing. 00-tools initializes atuin (registering its widget), 10-options runs compinit (fzf-tab + carapace need it), and 35-fzf defines its widgets before45-pluginsloads zsh-vi-mode, whose init fires the keybinding hook in 40-bindings. Every OS repo’s .zshrc just sources the vendored loader.zsh, which globs $ZSH_CFG/NN-*.zsh, sorts by the numeric prefix, and sources each — the order is the numbering, with no hand-maintained module list:
00toolsdetection + single init point (zoxide/starship/atuin/mise) — loads first
Two v4 refinements ride this loader. Profiles —CORE_PROFILE=minimal|standard|full — gate the Core band (00–69) by number: minimal stops after30-functions, standard after 50-op, andfull loads everything; the OS/role/host fragments (≥ 70) always load, so a lean profile can never drop essential setup. And theXDG split moves mutable state out of the symlinked config tree — history to $XDG_STATE_HOME, the compdump to $XDG_CACHE_HOME, plugins to $XDG_DATA_HOME — while each fragment’s byte-compiled.zwc stays beside it for fast startup.
The Kali role stage
Kali stacks three layers — Core, its apt OS layer, and an offensive role stage (dotfiles-Defense mirrors this on the blue side). Where a plain OS repo’s fragments end … 80-os 99-local, Kali drops in one more —85-offensive.zsh (role band 85), sorting between the two — for engagement scaffolding (scope-first workspaces, an audit-trail logshell, NetExec/BloodHound CE helpers). Engagement data never lives in the repo; it stays under~/engagements, and every tool is for authorized engagements with written rules of engagement only.
The macOS desktop layer
OS-native layers own more than packages and paths. On macOS,dotfiles-MacBook commits a full tiling-desktop setup — window manager, menu bar, and keyboard — themed to Core’s tokyonight palette so the GUI reads as an extension of the terminal, not a separate world.
◳ AeroSpace
i3-style tiling window manager — pure TOML, no SIP disable required, no daemon. alt drives focus, move, resize, and workspaces; its keymap is kept identical to GlazeWM (the Windows host WM) so the tiling workflow is the same on both OSes. JankyBorders rings the focused tile.
▭ SketchyBar
A programmable menu bar themed to tokyonight-storm, matching starship + tmux. Live AeroSpace workspaces on the left; CPU, memory, disk, network, and a click-to-toggle keep-awake on the right — every glyph from the one Nerd Font, no extra deps.
⌨ Karabiner
Caps→Ctrl/Esc, and a Tab-hyper layer that mirrors the WM verbs — hyper+hjkl to focus, hyper+1–5 for workspaces — so the whole tiling workflow stays on the home row.
Deep dives
The design decisions above are documented in full on this site. These are the long-form references worth reading next: