macOS (Apple Silicon / Intel) terminal environment — the OS-native layer of a
nine-repo dotfiles system. The shared Core (zsh modules, tmux, Neovim, git,
mise, starship, clipboard) is vendored under core/ as a git subtree from
dotfiles-core; this repo adds only what is specific to macOS.
Identity of the operator lives in Core. Identity of the machine lives here. Offensive/engagement tooling lives in
dotfiles-Kali— not here.
bootstrap.sh Homebrew + brew bundle + symlink wiring (idempotent)
Brewfile macOS packages (CLI + casks + fonts) ← you provide
core/ vendored Core subtree (do not edit here; edit dotfiles-core)
os/
macos.zsh interactive shell extras → ~/.config/zsh/os.zsh
macos.gitconfig osxkeychain + excludes + gpg → ~/.config/git/os.gitconfig
macos.gitignore global git excludes → ~/.config/git/ignore
macos.conf tmux en0 + battery bits → ~/.config/tmux/os.conf
zsh/
zshenv → ~/.zshenv (sets ZDOTDIR + XDG + universal env)
zprofile → ~/.config/zsh/.zprofile (Homebrew, juliaup, 1Password agent)
zshrc → ~/.config/zsh/.zshrc (history + completion + the loader)
macos/
defaults.sh `defaults write` system prefs (opt-in) ← you provide
ghostty/
config Ghostty terminal config → ~/.config/ghostty/config
ssh/
config SSH client config (keys never tracked) ← you provide
git clone <your-remote>/dotfiles-MacBook ~/dotfiles-MacBook
cd ~/dotfiles-MacBook
git subtree add --prefix=core <your-remote>/dotfiles-core main --squash # one-time
./bootstrap.sh # Homebrew + brew bundle + symlinks
exec zsh
./bootstrap.sh --macos-defaults # optional: apply system prefs (may need logout)Flags: --links-only (just symlinks), --no-brew (skip Homebrew/bundle),
--macos-defaults (also run macos/defaults.sh).
~/.zshenv sets ZDOTDIR=~/.config/zsh, so the rest of zsh lives there.
.zprofile (login) sets Homebrew/PATH; .zshrc (interactive) sources the Core
modules + the macOS layer + your local overrides, in order:
tools → options → history → aliases → git → functions → fzf → bindings
→ plugins → op → maint → update → os → local
options.zsh owns compinit + setopts and history.zsh owns history config
(both run before plugins.zsh). tools…update are Core; os is
os/macos.zsh; local is your untracked ~/.config/zsh/local.zsh. The order
is load-bearing — see the comments in zshrc.
Edit in dotfiles-core, then from there run ./bin/sync-core.sh, or here:
git subtree pull --prefix=core <your-remote>/dotfiles-core main --squash
./bootstrap.sh --links-only- Homebrew lives at
/opt/homebrew(Apple Silicon) or/usr/local(Intel);.zprofilehandles both. - Clipboard is native — Core's
clip/clip-pasteshell out topbcopy/pbpaste. - 1Password SSH agent —
.zprofilepointsSSH_AUTH_SOCKat the 1Password socket; comment it out if you don't use it. - Credentials — git uses the macOS keychain via
osxkeychain.
Static analysis is the test suite here — dotfiles can't really be unit-tested, so
shellcheck + shfmt + bash -n are what guard every change. The same commands run
locally and in CI:
brew bundle # installs the lint toolchain (see Brewfile "Dev: lint & format")
make lint # shellcheck + shfmt -d + bash -n (what CI runs)
make fmt # auto-format repo-owned bash in place
make help # list all targets
pre-commit install # optional: run the same gate at commit time- CI —
.github/workflows/ci.ymlrunsmake {shellcheck,fmt-check,syntax}plusactionlinton every push/PR. Tool versions (shfmt, actionlint) are pinned. - Style — repo-owned bash is 2-space (
shfmt -i 2);.editorconfigis the source of truth andshfmt/editors both read it. - Scope —
core/is a vendored git-subtree fromdotfiles-core; the lint targets and pre-commit hooks exclude it on purpose. Editing it here would diverge the subtree, so its Lua/shell is linted in that repo's CI.make core-advisorysurfaces anycore/findings locally without gating.
These were found during audit but belong to dotfiles-core (fix there, then
git subtree pull / sync-core.sh brings them down — don't hand-edit core/):
core/tmux/scripts/tmux-scratch.sh— shebang is#!/bin/bash; every other script uses#!/usr/bin/env bash.core/tmux/scripts/tmux-sessionizer.sh— superseded bytmux-sesh.sh(percore.manifest); it's dead and should be removed upstream.core/maint/dotfiles-maint.sh— ShellCheck SC2015 (A && B || C) and SC2016.core/tmux/scripts/tmux-menu.sh— ShellCheck SC2016.