Skip to content

Latest commit

 

History

247 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🍎 dotfiles

Setting up my new computer: clone. run. done.

The one repo I clone onto every machine I own — Mac, Linux, or WSL2 — and it's built to be forked.

CI License: MIT REUSE compliant macOS Linux WSL2

📖 Read the docs →


⚡ Quick start

No toolchain to install first — install.sh bootstraps Homebrew and uv itself.

git clone https://github.com/nivintw/dotfiles ~/dotfiles
~/dotfiles/install.sh

That one command converges a fresh machine to my exact setup: CLI tools, fish (zsh is a selectable opt-in — install.sh --shell zsh), and — on macOS — GUI apps, the MesloLGS NF font, macOS defaults, and the Dock. On Linux and WSL2 it runs the same OS-agnostic core (Homebrew/Linuxbrew, fish, Stow, tmux, Claude Code, …); the macOS-only steps just skip themselves. It's safe to re-run — it converges the machine to the declared state rather than clobbering what's there.

Forking? install.sh installs my taste — package list, Dock, keys, macOS defaults. Review and edit those before you run it. → Make it yours


✨ What makes it tick

Feature What it gives you
🔗 GNU Stow home/ mirrors $HOME via symlinks — editing ~/.config/fish/config.fish edits the repo file directly.
♻️ Idempotent bootstrap Re-run install.sh anytime; it adopts existing packages and symlinks instead of clobbering them.
🧩 Machine-local overlays One branch across every machine — work box, homelab, personal — with nothing machine-specific leaking into the public repo.
Quality gate A prek hook suite (lint, format, license, spelling) plus bats and pytest — run identically by you locally and by CI on every PR — CI installer-smoke jobs that run install.sh --core end-to-end on ephemeral macOS and Linux runners, and an opt-in local Tart VM harness (macOS or Linux) that does it twice to prove idempotency.
🎬 Live demos asciinema casts of the fish functions actually running, embedded on the docs site.
🤖 Local AI fleet Role-based Ollama models (fast / bulk / brainstorm / vision) provisioned by the installer; the ollm CLI routes mechanical work to them, GitLens gets offline AI, and a session-start hook shows Claude Code the live roster.

🗂️ Repo layout

  • home/ — mirrors $HOME, symlinked into place with GNU Stow.
  • Brewfile — formulae + casks, installed with brew bundle.
  • Brewfile.d/*.brewfile — tracked, opt-in bundles (e.g. personal, homelab, 1password), picked from an fzf multi-select (re-runs pre-seed your current pick; --bundle/--no-bundles skip it for scripts, --keep-bundles reuses the saved pick unchanged).
  • uv_tools.txt — Python tools, one uv tool install arg-list per line.
  • claude_mcp.json — Claude Code MCP servers; the GitHub token is a 1Password reference resolved at install time — or, on a machine without 1Password, a GITHUB_PERSONAL_ACCESS_TOKEN read from the environment — so no token is ever committed.
  • iterm2/ — iTerm2 preferences (pointed at directly, not stowed).
  • software_list.md — the few human-only steps Brewfile and stow can't automate.

Full reference — install flow, architecture, every command — lives on the documentation site →.


🧩 Machine-local overlays

The tracked files are a generic baseline. Anything machine-specific lives in untracked files outside the repo that the tracked config reads — so one branch runs everywhere, git pull never conflicts, and nothing private ever lands in the public repo. install.sh creates each file empty on first run; fill in what a given machine needs.

Tool Tracked baseline Local overlay (untracked) Wiring
SSH home/.ssh/config ~/.ssh/config.local Included by the tracked config
git home/.gitconfig ~/.gitconfig_local [include]d last by the tracked config (overlay wins for every key, incl. identity)
fish home/.config/fish/** ~/.config/dotfiles/local.fish sourced by conf.d/zzz-local.fish
zsh home/.config/zsh/**, home/.zshenv ~/.config/dotfiles/local.zsh sourced by conf.d/zzz-local.zsh; always stowed alongside fish — only the login shell is selected (--shell fish|zsh)
Homebrew Brewfile + Brewfile.d/* ~/.config/dotfiles/Brewfile.local auto-loaded by install.sh
Claude memory home/.claude/CLAUDE.md ~/.config/dotfiles/CLAUDE.local.md @-imported by the tracked CLAUDE.md
Claude settings claude_settings.json ~/.config/dotfiles/claude_settings.local.json deep-merged by install.sh (arrays union); written to a real ~/.claude/settings.json
Claude MCP claude_mcp.json ~/.config/dotfiles/claude_mcp.local.json deep-merged by install.sh
macOS defaults macos.sh ~/.config/dotfiles/macos.local.sh sourced by macos.sh

No 1Password? The baseline keeps 1Password as the personal default (SSH commit signing, the op:// MCP token, the desktop app). On a machine without it, the install degrades gracefully: 1Password is an opt-in 1password bundle (so it's simply not installed), install.sh disables commit signing in ~/.gitconfig_local, and the GitHub MCP server falls back to a GITHUB_PERSONAL_ACCESS_TOKEN from the environment.

Git identity lives in the overlay. The tracked home/.gitconfig ships no [user] block — set your name/email/signingkey in ~/.gitconfig_local (install.sh seeds it with a commented stanza). On a fresh machine that already has a real ~/.gitconfig, install.sh backs it up to ~/.gitconfig.pre-stow.bak and folds its contents into ~/.gitconfig_local before stowing — so nothing is stomped and your existing settings keep applying (and override the baseline).

Per-directory git identity — the clean way to use a work email and signing key only inside work repos:

# in ~/.gitconfig_local (untracked)
[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig.work   # work email, signing key, etc.

🔄 Day to day

  • New CLI tool or app — add a brew/cask line to the Brewfile, then brew bundle install --file=~/dotfiles/Brewfile.
  • Dotfile change — just edit the file under home/ (or its symlink in $HOME — same file) and commit.
  • Prune candidatesbrew bundle cleanup --file=~/dotfiles/Brewfile shows what's installed but no longer tracked.

🧹 Uninstalling

~/dotfiles/uninstall.sh is the safe reverse of the install. Preview it with --dry-run (it changes nothing), then run it for real. It removes only what the installer demonstrably owns (stow symlinks, MCP registrations, the iTerm2 pointer), offers to remove things it can't prove it owns (the TPM clone, uv tools, Ollama models), asks before lossy system changes (login shell, the Touch-ID PAM file), and never deletes your machine-local data — it lists what it leaves behind with copy-paste commands to finish by hand.


📄 License

MIT — and REUSE-compliant, so every file carries its own copyright and license. Fork it, adapt it, make it yours.

About

My personal dotfiles

Resources

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages