Architecture

One Core, vendored everywhere

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 nine machines with zero special-casing.

If it changes when the operating system changes, it does not belong in Core.

If it changes when you as an operator change, it does not belong in Core.

Everything left over is Core — and it lives in exactly one place.

The three layers

LayerLives inExamples
Core this repo, vendored into each OS repo via git subtree zsh modules, tmux base, nvim, git/delta
OS-native dotfiles-{MacBook,Windows,Fedora,Arch,…} package manager, clipboard shim, paths
Role / offensive dotfiles-Kali engagement scaffolding, C2, Impacket, wordlists

How an OS repo consumes Core

Each machine repo 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/Gerrrt/dotfiles-core main --squash
        

      
        
        
        

      
        
        # later, to pull Core updates down:
        

      
        $ 
        git subtree pull --prefix=core https://github.com/Gerrrt/dotfiles-core main --squash
        
      

Maintainers fan a Core change out to every OS repo in one shot with scripts/sync-core.sh, which prints the exact short SHA each repo receives so a sync is traceable.

Why subtree (not submodule, not chezmoi)

vs submodule

Submodules store a pointer, so a fresh clone is empty until you run submodule update --init. Subtree vendors the actual files — every repo is self-contained and clone-and-go. Better for public portfolio repos.

vs chezmoi

chezmoi (one repo + per-OS templates) is the most DRY answer and the right move if you ever collapse nine repos into one. This system keeps the nine-repo portfolio; switching later is a content migration, not a rewrite, because Core is already plain and OS-agnostic.

The canonical load order

Load order is load-bearing. tools initializes atuin (registering its widget), options runs compinit (fzf-tab + carapace need it), and fzf defines its widgets before plugins loads zsh-vi-mode, whose init fires the keybinding hook in bindings. Every OS repo’s .zshrc sources the chain in this order:

  1. 01 tools detection + single init point (zoxide/starship/atuin/mise) — loads first
  2. 02 ui terminal-UX primitives (_core_err/ok/hint/confirm/spin), gum-aware
  3. 03 options setopts + completion system (compinit, cached) + zstyles
  4. 04 history HISTFILE/SIZE + history setopts + secret-ignore
  5. 05 aliases modern-CLI aliases, each guarded by tools.zsh detection
  6. 06 git curated OMZ-style git aliases + git_main_branch helper
  7. 07 functions cross-OS shell functions (mkcd, extract, up, …)
  8. 08 fzf fzf env + zle widgets (Ctrl-F/R, Alt-Z) + fif/fbr
  9. 09 bindings vi-mode keybindings (zvm_after_init hook)
  10. 10 plugins lightweight plugin loader + pinned plugin list
  11. 11 op 1Password CLI helpers
  12. 12 maint / update daily-maintenance surface + the up updater nudge
  13. 13 os the OS-native layer (os/<platform>.zsh)
  14. 14 offensive Kali only — engagement scaffolding
  15. 15 local machine-specific overrides (untracked) — always wins

The Kali exception

Kali is the only repo that stacks three layers. Where every other repo’s loader ends … os local, Kali inserts one more stage — … os offensive local — 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.

Deep dives

The design decisions above are documented in full inside the repos. These are the long-form references worth reading next: