diff --git a/.cursor/rules/dotfiles-knowledge-base.mdc b/.cursor/rules/dotfiles-knowledge-base.mdc deleted file mode 100644 index 289ca02..0000000 --- a/.cursor/rules/dotfiles-knowledge-base.mdc +++ /dev/null @@ -1,126 +0,0 @@ ---- -description: Standards for this dotfiles repo — sources of truth, no-duplication rule, and checklists for adding tools -alwaysApply: true ---- - -# Dotfiles Repo Standards - -## 1. Search the repo before anything else - -For any question about this Mac dev setup: - -- **`docs/inventory.md`** — what is installed and how (start here for "what's in the setup") -- **`README.md`** — orientation, quick start, links to cheat sheets -- **`docs/`** — full command references; see [`README.md` Cheat Sheets section](../README.md#cheat-sheets--references) for the full annotated index -- **`Brewfile`** — authoritative package list; **`.tool-versions`** — authoritative runtime versions; **`setup.sh`** / **`verify.sh`** — bootstrap and smoke tests -- Root configs (`ghostty-config`, `.zshrc`, `starship.toml`) — live configuration - -| Question type | Start here | -|---|---| -| What is installed / how | `docs/inventory.md` | -| How-to / CLI reference | `docs/*-cheatsheet.md` | -| Bootstrap / wiring | `setup.sh`, `verify.sh`, `Brewfile` | -| Live config / "what is set?" | Root dotfiles (`ghostty-config`, `.zshrc`, etc.) | - ---- - -## 2. Sources of truth — one file owns each type of data - -Never duplicate these. Every other place must link, not repeat. - -| Data | Authoritative file | Rule | -|------|--------------------|------| -| Installed packages (formulae + casks) | `Brewfile` | Every `brew install` entry lives here | -| Language runtime versions | `.tool-versions` | Version numbers never written in docs | -| Zsh plugin list | `.zsh_plugins.txt` | Plugin names never written in docs | -| Human-readable inventory | `docs/inventory.md` | What's installed, how, one row per item | -| Detailed command references | `docs/*-cheatsheet.md` | Full usage, flags, examples, gotchas | -| Orientation + links | `README.md` | Overview only — no content, only links | - ---- - -## 3. No duplicate content across docs - -**One source, everywhere else links.** - -- If a table, code block, or list already exists in one doc, all other docs link to it — never copy it. -- `README.md` is orientation only: it describes categories and links out. No tool lists, keybinding tables, command blocks, or version numbers. -- Version numbers appear only in `.tool-versions`. Docs name the language but never the version. -- Plugin names appear only in `.zsh_plugins.txt`. Docs reference that file rather than listing plugins inline. -- New content from research goes in the single most relevant `docs/*-cheatsheet.md` — not in README as well. - ---- - -## 4. Adding a new tool, app, or runtime — full checklist - -Work through every applicable item. Skipping any item leaves the repo inconsistent. - -### Adding a Homebrew formula - -- [ ] Add to `Brewfile` under the correct section comment -- [ ] Add a row to the appropriate CLI tools section in `docs/inventory.md` with "Installed via: `brew install`" -- [ ] Add to the matching category block in `setup.sh` (`want "..."` + `formula ...`) -- [ ] Add to the CLI tools loop in `verify.sh` if it provides a binary - -### Adding a Homebrew cask (GUI app) - -- [ ] Add to `Brewfile` under the correct section comment -- [ ] Add a row to the GUI Applications table in `docs/inventory.md` with "Installed via: `brew install --cask`" -- [ ] Add to the matching category block in `setup.sh` (`want "..."` + `cask_pkg ...`) -- [ ] Add to the `APPS` array in `verify.sh` -- [ ] If the app writes back to a config file, symlink that file into the dotfiles repo (see `linearmouse.json` pattern in `setup.sh`) - -### Adding a language runtime (asdf) - -- [ ] Add to `.tool-versions` — version number goes here and nowhere else -- [ ] Add a row to the Language Runtimes table in `docs/inventory.md` (language name + key only, no version) -- [ ] Add `asdf plugin add ` to the asdf section of `setup.sh` -- [ ] Add the language to the runtime loop in `verify.sh` - -### Adding a Zsh plugin - -- [ ] Add to `.zsh_plugins.txt` — plugin entry goes here and nowhere else -- [ ] Add a row to the Zsh plugins table in `docs/inventory.md` -- [ ] Add a `check_contains` line for the plugin in `verify.sh` - -### Removing anything - -- [ ] Remove from `Brewfile` / `.tool-versions` / `.zsh_plugins.txt` -- [ ] Remove the corresponding row from `docs/inventory.md` -- [ ] Remove from `setup.sh` -- [ ] Remove from `verify.sh` - ---- - -## 5. README is orientation only - -`README.md` must never contain: - -- Lists of tool or app names → link to `docs/inventory.md` -- Keybinding tables → link to the relevant cheatsheet -- Command examples already in a cheatsheet → link to the cheatsheet -- Version numbers → link to `.tool-versions` -- Plugin names → link to `.zsh_plugins.txt` - -When editing README, ask: "does this content already exist in a cheatsheet or inventory?" If yes, replace with a link. - ---- - -## 6. verify.sh must stay in sync - -`verify.sh` is the contract that the setup is complete and correct. Keep it in sync: - -- New CLI binary → add to the `check_command` loop -- New GUI app → add to the `APPS` array -- New symlink in `setup.sh` → add a `check_symlink` call -- New config file → add `check_contains` or `check_json` assertions for its critical settings -- New Zsh plugin → add a `check_contains` line for `.zsh_plugins.txt` -- New `.zshrc` initialization → add a `check_contains` line for `.zshrc` - ---- - -## 7. If the repo does not contain the answer - -- Use current upstream or official docs (prefer release notes when versions matter). -- State clearly when the answer comes from outside this repo. -- If the answer is stable and reusable, add it to the most relevant `docs/*-cheatsheet.md`. Match existing tone: skimmable, commands first, gotchas where they matter. diff --git a/.gitignore b/.gitignore index e43b0f9..517cbe0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,35 @@ .DS_Store +/.obsidian + +# Nix build artifacts (created by `nix build` without -o; never commit) +result +result-* + +# herdr runtime artifacts under the edit-in-place config symlink +# (keep home/.config/herdr/config.toml tracked; ignore everything herdr writes) +# Docs: https://herdr.dev/docs/configuration/ , https://herdr.dev/docs/session-state/ , +# https://herdr.dev/docs/socket-api/ , https://herdr.dev/docs/plugins/ +home/.config/herdr/*.log +home/.config/herdr/*.log.* +home/.config/herdr/*.sock +home/.config/herdr/session.json +home/.config/herdr/session.json.bak-* +home/.config/herdr/session-history.json +home/.config/herdr/sessions/ +home/.config/herdr/release-notes.json +home/.config/herdr/product-announcements.json +home/.config/herdr/plugins.json +home/.config/herdr/plugins/ +home/.config/herdr/config.toml.bak-* + +# herdr artifacts can end up stray in other config dirs (e.g. copied into +# home/.config/ghostty/ by accident) - catch them repo-wide by name too +herdr-*.log +herdr.sock +herdr-client.sock + +# no-mistakes local validation state - never commit in this public repo +.no-mistakes/ + +# Local Lavish review artifacts - preserve locally, never commit +.lavish/ diff --git a/.zsh_plugins.txt b/.zsh_plugins.txt deleted file mode 100644 index 1869e34..0000000 --- a/.zsh_plugins.txt +++ /dev/null @@ -1,17 +0,0 @@ -# ~/.zsh_plugins.txt -# Antidote plugin bundle. Kept intentionally minimal; each plugin earns its -# place by solving a specific problem. Add more as needed. -# -# Load order matters: zsh-syntax-highlighting MUST load last (per its docs). -# zsh-autosuggestions and zsh-completions are order-flexible but listed before. - -# Command autosuggestions based on history (press the right arrow to accept) -zsh-users/zsh-autosuggestions - -# Extra completion definitions for common tools (git, docker, kubectl, etc.) -zsh-users/zsh-completions - -# Syntax highlighting as you type (valid commands green, invalid red). -# IMPORTANT: must be the LAST plugin loaded, otherwise other plugins can -# unbind its widget hooks. See: https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.md -zsh-users/zsh-syntax-highlighting diff --git a/.zshrc b/.zshrc deleted file mode 100644 index 23be9c8..0000000 --- a/.zshrc +++ /dev/null @@ -1,91 +0,0 @@ -# ~/.zshrc -# macOS developer environment. Wires together Homebrew, asdf, starship, antidote, and modern CLI tools. -# -# Load order matters here. Each section below explains why. - -# ---- 1. Homebrew PATH (Apple Silicon) ---- -# Must come first; most other tools live under /opt/homebrew. -eval "$(/opt/homebrew/bin/brew shellenv)" - -# ---- 2. asdf shims ---- -# Must come before any tool that might invoke node/python/go. Uses the Go-rewrite -# style (asdf 0.16+); the old `source asdf.sh` approach is deprecated. -export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH" - -# ---- 2b. Claude Code (native installer puts binary here) ---- -export PATH="$HOME/.local/bin:$PATH" - -# ---- 3. Atuin (SQLite shell history) ---- -# MUST load before antidote, so that zsh-syntax-highlighting (loaded LAST by -# antidote) can hook atuin's rebound Ctrl+R widget. Reversing this order causes -# autosuggestions/syntax-highlighting to silently fail. -# Replaces Ctrl+R with a full-screen history search UI. -eval "$(atuin init zsh)" - -# ---- 4. Antidote plugin manager ---- -# Loads the static plugin bundle. Plugin list lives in ~/.zsh_plugins.txt. -# Plugin order inside that file matters: zsh-syntax-highlighting MUST be last. -source /opt/homebrew/opt/antidote/share/antidote/antidote.zsh -antidote load - -# ---- 5. Starship prompt ---- -# Must come after plugins so it renders on top of their setup. Config lives -# in ~/.config/starship.toml. -eval "$(starship init zsh)" - -# ---- 6. zoxide (smarter cd) ---- -# `z ` jumps to any directory you've visited. Kept as a separate command -# from `cd` on purpose: aliasing `cd` to `z` breaks scripts that expect POSIX cd behavior. -eval "$(zoxide init zsh)" - -# ---- 7. fzf (fuzzy finder) ---- -# Binds Ctrl+R (history), Ctrl+T (file picker), Alt+C (directory picker). -# Note: atuin (loaded earlier) also binds Ctrl+R. Whichever loads LAST wins; -# here fzf wins at binding, but atuin's UI is invoked by fzf's Ctrl+R hook. -# Requires `$(brew --prefix)/opt/fzf/install` to have been run once. -[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh - -# fzf preview integration. Uses bat for file contents, eza for directory trees. -export FZF_CTRL_T_OPTS="--preview 'bat -n --color=always --line-range :500 {}'" -export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'" - -# ---- 8. Modern CLI aliases ---- -# Drop-in replacements. The classics remain available under their original names. -alias ls='eza --icons --group-directories-first' -alias ll='eza -lah --git --icons' -alias lt='eza --tree --level=2 --icons' -alias cat='bat --paging=never' -alias top='btop' -alias du='dust' - -# Deliberately NOT aliased: -# - grep -> rg (rg has different flag semantics; breaks scripts/pipes) -# - find -> fd (same reason) -# - cd -> z (zoxide; breaks scripts assuming POSIX cd) -# Use `rg`, `fd`, and `z` as their own commands instead. - -# ---- 9. Navigation shortcuts ---- -alias ..='cd ..' -alias ...='cd ../..' -alias ....='cd ../../..' - -# ---- 10. Git shortcuts ---- -alias g='git' -alias gs='git status' -alias gd='git diff' -alias gds='git diff --staged' -alias gl='git log --oneline --graph --decorate -20' -alias lg='lazygit' - -# ---- 11. Reload helper ---- -alias reload='exec zsh' - -# ---- 12. Docker CLI completions ---- -# Markers kept verbatim so Docker Desktop detects them and skips re-appending on first launch. -# The following lines have been added by Docker Desktop to enable Docker CLI completions. -if [[ -d "$HOME/.docker/completions" ]]; then - fpath=($HOME/.docker/completions $fpath) -fi -autoload -Uz compinit -compinit -# End of Docker CLI completions diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8c0c856 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,158 @@ +# Claude Code Rules for this Dotfiles Repo + +## 1. Always search this repo first + +Before answering any question about this Mac dev setup, shell tools, CLI tools, configs, or anything that could be documented here — **read the repo first**. + +### Where to look (in order) + +| Question type | Search here first | +|---|---| +| What is installed / how | `docs/inventory.md` | +| How-to / CLI reference | `docs/cheatsheets/` (see index below) | +| Bootstrap / wiring | `flake.nix`, `configuration.nix`, `home.nix`, `bootstrap.sh`, `rebuild.sh`, `verify.sh` | +| Live config / "what is set?" | `home/.config/{wezterm,ghostty,nvim,herdr,linearmouse}/`, `home/.baby-menu/`, `home.nix`'s `programs.starship`/`programs.zsh` blocks | +| Setup walkthrough / daily commands | `README.md` | + +### docs/ index + +See [`README.md` — Cheat Sheets & References](README.md#cheat-sheets--references) for the full annotated index. Key lookup: + +| Topic | File | +|-------|------| +| Installed software (what, how installed) | `docs/inventory.md` | +| Nix / nix-darwin / home-manager workflow | `docs/cheatsheets/nix-cheatsheet.md` | +| Homebrew (via nix-homebrew) | `docs/cheatsheets/homebrew-cheatsheet.md` | +| Language runtimes | `docs/cheatsheets/asdf-cheatsheet.md` | +| Terminal keybindings / config | `docs/cheatsheets/ghostty-cheatsheet.md` | +| Git workflows | `docs/cheatsheets/git-cheatsheet.md` | +| Git TUI | `docs/cheatsheets/lazygit-cheatsheet.md` | +| Modern CLI tools | `docs/cheatsheets/modern-cli-cheatsheet.md` | +| Claude Code CLI | `docs/cheatsheets/claude-code-cheatsheet.md` | +| Cursor IDE | `docs/cheatsheets/cursor-cli-cheatsheet.md` | +| Docker | `docs/cheatsheets/docker-cheatsheet.md` | +| Vim/Neovim keybindings | `docs/cheatsheets/vim-cheat-sheet.md` | + +### How to search + +Use `rg` (ripgrep) to find relevant content fast before doing a full file read: + +``` +rg "" /Users/lakshyadevsingh/dotfiles/docs/ -l +rg "" -n +``` + +--- + +## 2. Sources of truth — one file owns each type of data + +Never duplicate these. Every other place must link, not repeat. + +| Data | Authoritative file | What goes here | +|------|--------------------|----------------| +| GUI apps (casks), asdf itself + build deps, tapped tools (terraform, stripe) | `configuration.nix`'s `homebrew` block | Every `homebrew.brews` / `homebrew.casks` entry. Rule of thumb: `.app` bundles and things not sensibly packaged in nixpkgs stay here. | +| CLI tools available in nixpkgs | `home.nix`'s `home.packages` | Everything installable straight from nixpkgs (ripgrep, fd, bat, lazygit, etc.) | +| Zsh plugins, aliases, keybinds, Starship prompt | `home.nix`'s `programs.zsh` / `programs.starship` blocks | Antidote is retired — native home-manager zsh plugin toggles replace it. There is no more standalone plugin-list file. | +| Dotfile symlink targets | `home.nix`'s `home.file` / `mkOutOfStoreSymlink` entries | Every path under `~` that should point back into this repo | +| Language runtime versions | `.tool-versions` | Version numbers only — never written in docs. Runtimes stay asdf-managed by design (not Nix-managed) — see README's Design Decisions. | +| Human-readable inventory | `docs/inventory.md` | What's installed, how, one row per item | +| Detailed command references | `docs/cheatsheets/*-cheatsheet.md` | Full usage, flags, examples, gotchas | +| Orientation + links | `README.md` | Overview only — links to cheatsheets, no duplicated content | + +--- + +## 3. No duplicate content across docs + +**One source, everywhere else links.** + +- If a table, code block, or list already exists in one doc, all other docs must link to it — never copy it. +- `README.md` is orientation only: it describes categories and links out. It does not contain tool lists, keybinding tables, command blocks, or version numbers. +- Version numbers appear only in `.tool-versions`. Docs name the language (e.g. "Node.js") but never the version. +- Package lists appear only in `configuration.nix` (Homebrew) and `home.nix` (Nix packages). Docs say "see `configuration.nix`" / "see `home.nix`" rather than listing packages. +- When adding content from the web: place it in the single most relevant `docs/cheatsheets/*-cheatsheet.md`. Do not add it to README as well. + +--- + +## 4. Adding a new tool, app, or runtime — full checklist + +Work through every applicable item. Skipping any item leaves the repo inconsistent. + +### Adding a Homebrew cask (GUI app) + +- [ ] Add to `configuration.nix`'s `homebrew.casks` +- [ ] Add a row to the GUI Applications table in `docs/inventory.md` (include "Installed via: `brew install --cask`" or "configuration.nix's homebrew.casks") +- [ ] Add to the `APPS` array in `verify.sh` +- [ ] If the app writes back to a config file, add a `home.file` entry in `home.nix` using `config.lib.file.mkOutOfStoreSymlink` (NOT plain `home.file`, which symlinks from the read-only Nix store) plus a `home.activation` script that backs up any pre-existing real file before the symlink lands — see the `linearmouse.json` pattern in `home.nix` (`home.activation.backupLinearMouseConfig`) +- [ ] Run `./rebuild.sh` + +### Adding a Homebrew formula (only for things that must stay Homebrew — e.g. asdf, build-support libs, tapped tools) + +- [ ] Add to `configuration.nix`'s `homebrew.brews` (add a `homebrew.taps` entry too if it's from a third-party tap) +- [ ] Add a row to the appropriate CLI tools section in `docs/inventory.md` (include "Installed via: `brew install`") +- [ ] Run `./rebuild.sh` + +### Adding a Nix-native CLI package (tools available in nixpkgs — the default choice for new CLI tools) + +- [ ] Check it exists in nixpkgs first (`nix search nixpkgs `), not `brew search` +- [ ] Add to `home.nix`'s `home.packages` +- [ ] Add a row to the appropriate CLI tools section in `docs/inventory.md` (include "Installed via: Nix (home.packages)") +- [ ] Add to the `check_command` loop in `verify.sh` if it provides a binary +- [ ] Run `./rebuild.sh` + +### Adding a language runtime (asdf) + +- [ ] Add to `.tool-versions` (version number goes here and nowhere else) +- [ ] Add a row to the Language Runtimes table in `docs/inventory.md` (language name and `.tool-versions` key only — no version number) +- [ ] Run `./bootstrap.sh` (registers the asdf plugin and runs `asdf install` for anything new in `.tool-versions`) +- [ ] Confirm the language's runtime-version check loop in `verify.sh` covers it + +### Adding a zsh alias / keybind + +- [ ] Add to `home.nix`'s `programs.zsh.shellAliases` (aliases) or `programs.zsh.initContent` (keybinds, env vars, PATH changes) +- [ ] Run `./rebuild.sh` + +### Removing anything + +- [ ] Remove from `configuration.nix` / `home.nix` / `.tool-versions` +- [ ] Remove the corresponding row from `docs/inventory.md` +- [ ] Remove from `verify.sh` (`check_command` loop, `APPS` array, or `check_contains`/`check_resolves_to_repo` calls as applicable) +- [ ] Run `./rebuild.sh` — note `homebrew.onActivation.cleanup = "none"` means removed Homebrew packages are left installed but undeclared, not force-uninstalled; `brew uninstall` manually if you want it gone from disk too + +--- + +## 5. README is orientation only + +`README.md` must never contain: +- Lists of tool or app names (link to `docs/inventory.md`) +- Keybinding tables (link to `docs/cheatsheets/ghostty-cheatsheet.md` or `docs/cheatsheets/modern-cli-cheatsheet.md`) +- Command examples that are already in a cheatsheet (link to the cheatsheet) +- Version numbers (link to `.tool-versions`) +- Package lists (link to `configuration.nix` / `home.nix`) + +When editing README, ask: "does this content already exist in a cheatsheet or inventory?" If yes, replace with a link. + +--- + +## 6. verify.sh and nix flake check — two layers of contract + +`nix flake check --no-build` (and `nix build .#darwinConfigurations.mac.system --dry-run`) is the **primary** contract now for anything declared in `configuration.nix`/`home.nix` — if a package or symlink is declared wrong, the flake fails to evaluate or build before you ever get to `verify.sh`. `verify.sh` itself now runs `nix flake check` as its first check, then covers what Nix genuinely can't express on its own: + +- Whether things are *actually* wired up on THIS machine right now (not just declared correctly) +- GUI app presence and `/Applications` state (Nix can't verify sign-in state) +- asdf runtime versions matching `.tool-versions` (asdf is deliberately outside Nix's management) +- Git identity (still `bootstrap.sh`-driven, written directly to mutable `~/.gitconfig`; pager/merge/delta config is nix-managed via `programs.git` in `home.nix`, applied to `~/.config/git/config`) +- LinearMouse JSON content integrity (a write-back file, worth sanity-checking regardless of installer mechanism) + +Keep `verify.sh` in sync: +- New CLI binary installed → add to the `check_command` loop +- New GUI app installed → add to the `APPS` array +- New symlink added in `home.nix` → add a `check_resolves_to_repo` call (for edit-in-place files) or `check_nonempty` (for home-manager-generated files like `.zshrc`/`starship.toml`) +- New config file added → add `check_contains` or `check_json` assertions for its critical settings + +--- + +## 7. If the repo does not have the answer + +1. **Say so explicitly.** +2. **Search the web** using the WebSearch tool. Prefer official docs and release notes over blog posts. +3. **Update the repo** if the answer is stable and reusable — place it in the most relevant `docs/cheatsheets/*-cheatsheet.md`. Match existing tone: skimmable, commands first, gotchas where they matter. Do this proactively in Agent sessions. diff --git a/Brewfile b/Brewfile index 5cb65d4..e8dc9c1 100644 --- a/Brewfile +++ b/Brewfile @@ -1,95 +1,9 @@ -# Brewfile: macOS Developer Setup +# Brewfile: RETIRED — kept only as a pointer for anyone who lands here out +# of habit or an old bookmark. # -# Usage: -# brew bundle # install everything -# brew bundle check # dry-run check -# brew bundle cleanup # remove anything not listed here -# brew bundle list --all # show what would be installed +# Package management moved to Nix: +# - GUI apps (casks) and the handful of formulae still worth Homebrew +# (asdf + build deps, tapped tools) -> configuration.nix's `homebrew` block +# - CLI tools available in nixpkgs -> home.nix's home.packages # -# Language runtimes are NOT in this file by design; they're managed by asdf -# via a committed .tool-versions file. See .tool-versions alongside this -# Brewfile. Claude Code is also excluded by design: it uses its own -# auto-updating native installer. - -# ---- Version control & core utilities ---- -brew "git" # Version control -brew "gh" # GitHub CLI -brew "jq" # JSON processor -brew "tree" # Directory tree visualizer -brew "wget" # HTTP downloader - -# ---- Modern CLI replacements (Rust-based, drop-in upgrades) ---- -brew "ripgrep" # Fast recursive grep (rg); respects .gitignore -brew "fd" # Modern find: intuitive syntax, parallel execution -brew "bat" # cat with syntax highlighting and git integration -brew "eza" # Modern ls: icons, git status, tree view -brew "zoxide" # Smarter cd: jumps to directories by partial name -brew "fzf" # Fuzzy finder: powers Ctrl+R, file pickers, etc. -brew "git-delta" # Syntax-highlighted git diffs -brew "lazygit" # Terminal UI for git -brew "btop" # Modern resource monitor (replaces top/htop) -brew "dust" # Visual disk usage (replaces du) -brew "tldr" # Simplified man pages with real examples -brew "atuin" # SQLite-backed shell history with search - -# ---- Shell productivity ---- -brew "starship" # Cross-shell prompt (actively maintained; replaces powerlevel10k) -brew "antidote" # Zsh plugin manager (fast, static-generated loader) - -# ---- Language version manager ---- -# Runtimes for Node.js, Python, Go are declared in .tool-versions. -# After `brew bundle`, run `asdf install` to fetch them. -brew "asdf" - -# ---- Language-adjacent build tools ---- -# Needed by some asdf plugins and native modules during compilation. -brew "coreutils" # GNU core utilities (required by asdf on macOS) -brew "openssl@3" # TLS library (Python, Node native modules) -brew "readline" # Line-editing library (Python build) -brew "xz" # Compression library (Python build) - -# ---- Containers ---- -# Docker Desktop provides both the Docker daemon and docker/docker-compose CLIs. -# All local databases (PostgreSQL, Redis, etc.) run as containers per your setup. -cask "docker-desktop" - -# ---- Cloud tooling ---- -cask "gcloud-cli" # gcloud, gsutil, bq (kubectl installed on demand) - # Formerly the "google-cloud-sdk" formula; renamed + moved to cask in 2025. - -# ---- Terminal emulator & editors ---- -cask "ghostty" # Native GPU-accelerated terminal (replaces iTerm2 in 2026) -cask "visual-studio-code" # Editor -cask "cursor" # AI-native code editor - -# ---- AI coding tools ---- -# Claude Code (CLI) is intentionally excluded — it uses its own auto-updating native installer. -cask "claude" # Anthropic Claude desktop app -cask "codex" # OpenAI Codex CLI (coding agent in terminal) -cask "codex-app" # OpenAI Codex desktop app (manages coding agents) - -# ---- Browsers ---- -cask "google-chrome" -cask "firefox" -cask "chatgpt-atlas" # OpenAI's browser with ChatGPT built in - -# ---- Productivity & utilities ---- -cask "rectangle" # Window management (keyboard-driven tiling) -cask "1password" # Password manager -cask "appcleaner" # Clean app uninstalls -cask "maccy" # Clipboard history manager (Cmd+Shift+C) -cask "linearmouse" # Mouse customization: extra buttons, per-device scroll/accel - # Essential for third-party mice with side/extra buttons. - # Fixes macOS's patchy handling of back/forward buttons. -cask "superwhisper" # AI voice-to-text dictation (system-wide) -cask "obsidian" # Markdown-based knowledge base / note-taking - -# ---- API testing ---- -cask "granola" # AI-powered notepad for meetings -cask "postman" # REST client & API testing -cask "whimsical" # Collaboration and diagramming tool - -# ---- Developer fonts ---- -# Nerd Fonts include glyphs required by Starship, eza icons, and modern TUI tools. -cask "font-jetbrains-mono-nerd-font" # Recommended: primary coding font -cask "font-fira-code-nerd-font" # Alternative with strong ligatures +# See docs/nix-cheatsheet.md for the day-to-day workflow (./rebuild.sh etc). diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 49bde3c..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,142 +0,0 @@ -# Claude Code Rules for this Dotfiles Repo - -## 1. Always search this repo first - -Before answering any question about this Mac dev setup, shell tools, CLI tools, configs, or anything that could be documented here — **read the repo first**. - -### Where to look (in order) - -| Question type | Search here first | -|---|---| -| What is installed / how | `docs/inventory.md` | -| How-to / CLI reference | `docs/` cheat sheets (see index below) | -| Bootstrap / wiring | `setup.sh`, `verify.sh`, `Brewfile`, `.tool-versions` | -| Live config / "what is set?" | Root dotfiles: `.zshrc`, `starship.toml`, `ghostty-config` | -| Setup walkthrough / daily commands | `README.md` | - -### docs/ index - -See [`README.md` — Cheat Sheets & References](README.md#cheat-sheets--references) for the full annotated index. Key lookup: - -| Topic | File | -|-------|------| -| Installed software (what, how installed) | `docs/inventory.md` | -| Homebrew / Brewfile | `docs/homebrew-cheatsheet.md` | -| Language runtimes | `docs/asdf-cheatsheet.md` | -| Terminal keybindings / config | `docs/ghostty-cheatsheet.md` | -| Git workflows | `docs/git-cheatsheet.md` | -| Git TUI | `docs/lazygit-cheatsheet.md` | -| Modern CLI tools | `docs/modern-cli-cheatsheet.md` | -| Claude Code CLI | `docs/claude-code-cheatsheet.md` | -| Cursor IDE | `docs/cursor-cli-cheatsheet.md` | - -### How to search - -Use `rg` (ripgrep) to find relevant content fast before doing a full file read: - -``` -rg "" /Users/lakshyadevsingh/dotfiles/docs/ -l -rg "" -n -``` - ---- - -## 2. Sources of truth — one file owns each type of data - -Never duplicate these. Every other place must link, not repeat. - -| Data | Authoritative file | What goes here | -|------|--------------------|----------------| -| Installed packages (formulae + casks) | `Brewfile` | Every `brew install` and `brew install --cask` | -| Language runtime versions | `.tool-versions` | Version numbers only — never written in docs | -| Zsh plugin list | `.zsh_plugins.txt` | Plugin names only — never written in docs | -| Human-readable inventory | `docs/inventory.md` | What's installed, how, one row per item | -| Detailed command references | `docs/*-cheatsheet.md` | Full usage, flags, examples, gotchas | -| Orientation + links | `README.md` | Overview only — links to cheatsheets, no duplicated content | - ---- - -## 3. No duplicate content across docs - -**One source, everywhere else links.** - -- If a table, code block, or list already exists in one doc, all other docs must link to it — never copy it. -- `README.md` is orientation only: it describes categories and links out. It does not contain tool lists, keybinding tables, command blocks, or version numbers. -- Version numbers appear only in `.tool-versions`. Docs name the language (e.g. "Node.js") but never the version. -- Plugin names appear only in `.zsh_plugins.txt`. Docs say "see `.zsh_plugins.txt`" rather than listing plugins. -- When adding content from the web: place it in the single most relevant `docs/*-cheatsheet.md`. Do not add it to README as well. - ---- - -## 4. Adding a new tool, app, or runtime — full checklist - -Work through every applicable item. Skipping any item leaves the repo inconsistent. - -### Adding a Homebrew formula - -- [ ] Add to `Brewfile` under the correct section comment -- [ ] Add a row to the appropriate CLI tools section in `docs/inventory.md` (include "Installed via: `brew install`") -- [ ] Add to the matching category block in `setup.sh` with a `want "..."` + `formula ...` line -- [ ] Add to the CLI tools loop in `verify.sh` if it provides a binary - -### Adding a Homebrew cask (GUI app) - -- [ ] Add to `Brewfile` under the correct section comment -- [ ] Add a row to the GUI Applications table in `docs/inventory.md` (include "Installed via: `brew install --cask`") -- [ ] Add to the matching category block in `setup.sh` with a `want "..."` + `cask_pkg ...` line -- [ ] Add to the `APPS` array in `verify.sh` -- [ ] If the app writes back to a config file, symlink that file into the dotfiles repo so changes persist (see `linearmouse.json` pattern in `setup.sh`) - -### Adding a language runtime (asdf) - -- [ ] Add to `.tool-versions` (version number goes here and nowhere else) -- [ ] Add a row to the Language Runtimes table in `docs/inventory.md` (language name and `.tool-versions` key only — no version number) -- [ ] Add `asdf plugin add ` to the asdf section in `setup.sh` -- [ ] Add the language to the runtime loop in `verify.sh` - -### Adding a Zsh plugin - -- [ ] Add to `.zsh_plugins.txt` (plugin entry goes here and nowhere else) -- [ ] Add a row to the Zsh plugins table in `docs/inventory.md` -- [ ] Add a `check_contains` line for the plugin in `verify.sh` - -### Removing anything - -- [ ] Remove from `Brewfile` / `.tool-versions` / `.zsh_plugins.txt` -- [ ] Remove the corresponding row from `docs/inventory.md` -- [ ] Remove from `setup.sh` -- [ ] Remove from `verify.sh` - ---- - -## 5. README is orientation only - -`README.md` must never contain: -- Lists of tool or app names (link to `docs/inventory.md`) -- Keybinding tables (link to `docs/ghostty-cheatsheet.md` or `docs/modern-cli-cheatsheet.md`) -- Command examples that are already in a cheatsheet (link to the cheatsheet) -- Version numbers (link to `.tool-versions`) -- Plugin names (link to `.zsh_plugins.txt`) - -When editing README, ask: "does this content already exist in a cheatsheet or inventory?" If yes, replace with a link. - ---- - -## 6. verify.sh must stay in sync - -`verify.sh` is the contract that the setup is complete and correct. Keep it in sync: - -- New CLI binary installed → add to the `check_command` loop -- New GUI app installed → add to the `APPS` array -- New symlink added in `setup.sh` → add a `check_symlink` call -- New config file added → add `check_contains` or `check_json` assertions for its critical settings -- New Zsh plugin added → add a `check_contains` line for `.zsh_plugins.txt` -- New `.zshrc` initialization added → add a `check_contains` line for `.zshrc` - ---- - -## 7. If the repo does not have the answer - -1. **Say so explicitly.** -2. **Search the web** using the WebSearch tool. Prefer official docs and release notes over blog posts. -3. **Update the repo** if the answer is stable and reusable — place it in the most relevant `docs/*-cheatsheet.md`. Match existing tone: skimmable, commands first, gotchas where they matter. Do this proactively in Agent sessions. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..0b96cc9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +/Users/lakshyadevsingh/.dotfiles/AGENTS.md \ No newline at end of file diff --git a/README.md b/README.md index 14a0ea3..67d8bd1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # macOS Developer Setup (2026) -A reproducible macOS development environment. Clone this repo onto a fresh Mac, run one script, and you get: +A reproducible macOS development environment, managed with **nix-darwin** and **home-manager**. Clone this repo onto a fresh Mac, run one script, and you get: -- A modern terminal (Ghostty) with an actively-maintained cross-shell prompt (Starship) +- A modern terminal stack (Ghostty + WezTerm) with an actively-maintained cross-shell prompt (Starship) - Language runtimes pinned per-project via asdf - Rust-based CLI replacements for classic Unix tools, all aliased transparently -- Code editors, containers, cloud tools, and developer utilities -- Everything wired together via `.zshrc`, Starship, Antidote, and a bootstrap script +- Code editors, containers, cloud tools, and developer utilities — declared once, applied atomically +- Everything wired together via `flake.nix`, `configuration.nix`, `home.nix`, and a bootstrap script See [`docs/inventory.md`](docs/inventory.md) for the complete list of every installed tool, app, and runtime — including how each one is installed. @@ -20,7 +20,7 @@ See [`docs/inventory.md`](docs/inventory.md) for the complete list of every inst - [CLI Tools & Aliases](#cli-tools--aliases) - [Language Runtimes (via asdf)](#language-runtimes-via-asdf) - [Applications Installed](#applications-installed) -- [Manual Steps (After `./setup.sh`)](#manual-steps-after-setupsh) +- [Manual Steps (After `./bootstrap.sh`)](#manual-steps-after-bootstrapsh) - [1. Grant Accessibility Permissions](#1-grant-accessibility-permissions-one-time-per-app) - [2. Configure Git Identity](#2-configure-git-identity) - [3. Authenticate GitHub CLI](#3-authenticate-github-cli) @@ -36,16 +36,17 @@ See [`docs/inventory.md`](docs/inventory.md) for the complete list of every inst - [Updating Your Setup](#updating-your-setup) - [Update everything](#update-everything) - [Update just Homebrew packages](#update-just-homebrew-packages) - - [Update Claude Code](#update-claude-code) + - [Roll back a bad switch](#roll-back-a-bad-switch) - [Update asdf plugins](#update-asdf-plugins) - [Troubleshooting](#troubleshooting) - - [`./setup.sh` returns "permission denied"](#setupsh-returns-permission-denied) + - [`./bootstrap.sh` returns "permission denied"](#bootstrapsh-returns-permission-denied) + - [`sudo: darwin-rebuild: command not found`](#sudo-darwin-rebuild-command-not-found) - ["command not found" on a tool that should exist](#command-not-found-on-a-tool-that-should-exist) - [Icons show as squares in Starship / eza](#icons-show-as-squares-in-starship--eza) - [Ghostty Quick Terminal doesn't respond](#ghostty-quick-terminal-doesnt-respond) - [SSH session looks broken](#ssh-session-looks-broken-vim--less-render-incorrectly) - [asdf says "No version is set"](#asdf-says-no-version-is-set-for-command-x) - - [`brew bundle` fails with permissions errors](#brew-bundle-fails-with-permissions-errors) + - [`darwin-rebuild switch` fails on a Homebrew step](#darwin-rebuild-switch-fails-on-a-homebrew-step) - [Atuin doesn't import my old history](#atuin-doesnt-import-my-old-history) - [Starting over on a single tool](#starting-over-on-a-single-tool) - [Cheat Sheets & References](#cheat-sheets--references) @@ -66,19 +67,21 @@ xcode-select --install # 2. Clone and bootstrap git clone https://github.com/lakshyads/dotfiles.git ~/dotfiles cd ~/dotfiles -chmod +x setup.sh # first time only; see note below -./setup.sh +chmod +x bootstrap.sh # first time only; see note below +./bootstrap.sh ``` -`setup.sh` launches an interactive wizard — it walks you through each category (core tools, CLI tools, editors, apps, fonts, etc.) and asks whether to install all, customize, or skip. Pass `--full` to skip all prompts and install everything non-interactively: +`bootstrap.sh` is the single entry point. In order, it: installs Xcode CLT if missing, installs Determinate Nix if missing, symlinks the repo to `~/.dotfiles`, runs the first `darwin-rebuild switch` (this installs every package — Homebrew via nix-homebrew, CLI tools via home-manager — and wires up every dotfile symlink), then registers asdf plugins and installs runtimes from `.tool-versions`, and finally prompts for your git identity. + +It's designed to be re-run: some steps (Xcode CLT install, first Nix install) deliberately exit and ask you to re-run once they finish, since they need a fresh shell or a GUI installer to complete first. Pass `--full` to skip the interactive git-identity prompt (just reports current state instead): ```bash -./setup.sh --full +./bootstrap.sh --full ``` -The script is idempotent and safe to re-run at any time. Already-installed packages are detected and skipped. +Every step is idempotent — safe to re-run at any time. Already-applied steps are detected and skipped. -When it finishes, open Ghostty, run `exec zsh`, and you're in the new environment. +When it finishes, open Ghostty or WezTerm, run `exec zsh`, and you're in the new environment. To verify everything installed correctly in a new shell: @@ -86,9 +89,16 @@ To verify everything installed correctly in a new shell: ./verify.sh ``` -This runs non-destructive smoke tests: checks every CLI tool resolves, every symlink is in place, every GUI app installed, language runtimes match `.tool-versions`, fonts are detected, and Git is configured. Exit 0 on success, 1 with a failure summary otherwise. +This runs non-destructive smoke tests: checks every CLI tool resolves, every dotfile symlink is wired correctly, every GUI app is installed, language runtimes match `.tool-versions`, fonts are detected, and Git is configured. It also runs `nix flake check --no-build` as its first check — that's the primary structural contract now (anything declared in `configuration.nix`/`home.nix` that fails to evaluate fails there first). Exit 0 on success, 1 with a failure summary otherwise. + +After the first bootstrap, day-to-day changes to configuration go through: + +```bash +./rebuild.sh # build + apply configuration.nix / home.nix changes +./rebuild.sh --dry-run # build only, validate before switching +``` -> **Why `chmod +x`?** Depending on how you cloned or downloaded the repo, the executable bit on `setup.sh` may not be preserved (macOS Gatekeeper strips it for quarantined files, and some git configs do too). Running `chmod +x setup.sh` once fixes it permanently. If you cloned via plain `git clone` into a trusted directory, it may already be executable and this step is a no-op. +> **Why `chmod +x`?** Depending on how you cloned or downloaded the repo, the executable bit on `bootstrap.sh` may not be preserved (macOS Gatekeeper strips it for quarantined files, and some git configs do too). Running `chmod +x bootstrap.sh` once fixes it permanently. If you cloned via plain `git clone` into a trusted directory, it may already be executable and this step is a no-op.

↑ Back to top

@@ -96,23 +106,24 @@ This runs non-destructive smoke tests: checks every CLI tool resolves, every sym ## What the Setup Gives You -See [`docs/inventory.md`](docs/inventory.md) for a full list of what's provisioned automatically. Everything below is set up for you—no manual configuration required after running `./setup.sh`. +See [`docs/inventory.md`](docs/inventory.md) for a full list of what's provisioned automatically. Everything below is set up for you — no manual configuration required after running `./bootstrap.sh`. ### Terminal & Shell -- **Ghostty** with JetBrains Mono Nerd Font, Catppuccin theme (auto light/dark switching), 25M-line scrollback, and split keybindings +- **Ghostty** and **WezTerm**, both themed `rose-pine-moon` with Hack Nerd Font, 25M-line scrollback, and split keybindings - **Quick Terminal** (Quake-style dropdown) bound to ```Ctrl+` ```; see manual steps for required permission -- **Zsh** with Antidote — see [Zsh plugins](docs/inventory.md#zsh-plugins) +- **Zsh** with native home-manager plugin support (autosuggestions, syntax-highlighting) — see [`home.nix`](home.nix)'s `programs.zsh` block - **Starship** prompt showing directory, git branch + status, active language version, and command duration - **Atuin** replacing `Ctrl+R` with a full-screen SQLite-backed history search +- **herdr**, a terminal-based agent multiplexer (tmux-style `Ctrl+B` prefix), for running multiple coding agent sessions side by side ### CLI Tools & Aliases -Classic commands (`ls`, `cat`, `top`, `du`, `git`) are aliased to their modern replacements. Shell key bindings for history search and fuzzy file/directory picking are wired up. See [`docs/modern-cli-cheatsheet.md`](docs/modern-cli-cheatsheet.md) for the full alias map, key bindings, and usage reference. +Classic commands (`ls`, `cat`, `top`, `du`, `git`) are aliased to their modern replacements. Shell key bindings for history search and fuzzy file/directory picking are wired up. See [`docs/cheatsheets/modern-cli-cheatsheet.md`](docs/cheatsheets/modern-cli-cheatsheet.md) for the full alias map, key bindings, and usage reference. ### Language Runtimes (via asdf) -Versions are pinned in `.tool-versions` — that is the only place versions are defined. See [`docs/inventory.md`](docs/inventory.md#language-runtimes) for the list of managed languages and [`docs/asdf-cheatsheet.md`](docs/asdf-cheatsheet.md) for version management commands. +Versions are pinned in `.tool-versions` — that is the only place versions are defined. Runtimes stay asdf-managed by design (not Nix-managed): asdf's per-project `.tool-versions` override, walking up the directory tree, is a workflow Nix doesn't replicate without a heavier devshell/direnv setup. See [`docs/inventory.md`](docs/inventory.md#language-runtimes) for the list of managed languages and [`docs/cheatsheets/asdf-cheatsheet.md`](docs/cheatsheets/asdf-cheatsheet.md) for version management commands. ### Applications Installed @@ -122,7 +133,7 @@ See **[`docs/inventory.md`](docs/inventory.md)** for the full list of GUI apps, --- -## Manual Steps (After `./setup.sh`) +## Manual Steps (After `./bootstrap.sh`) These genuinely require human action, either because they need you to sign in, grant macOS permissions, or make personal choices. Work through them in order: @@ -139,6 +150,8 @@ Some apps need Accessibility permission to function. macOS will prompt on first ### 2. Configure Git Identity +`./bootstrap.sh` already prompted you for this interactively. To change it later: + ```bash git config --global user.name "Your Name" git config --global user.email "you@example.com" @@ -149,7 +162,7 @@ git config --global pull.rebase true git config --global rebase.autoStash true ``` -Full recommended git config and a workflow reference are in [`docs/git-cheatsheet.md`](docs/git-cheatsheet.md). +This is deliberately kept out of home-manager's `programs.git` — that would make `~/.gitconfig` an immutable Nix-store symlink. Full recommended git config and a workflow reference are in [`docs/cheatsheets/git-cheatsheet.md`](docs/cheatsheets/git-cheatsheet.md). ### 3. Authenticate GitHub CLI @@ -161,11 +174,10 @@ gh auth login # follow prompts, choose SSH or HTTPS First launch triggers a macOS prompt to install a privileged helper. Click through it. After that, `docker` and `docker compose` work from any terminal. -Docker Desktop also appends a CLI completions block to `~/.zshrc` on first launch. This is already committed to the dotfiles `.zshrc`; don't let it get added a second time if you re-run setup on a machine where Docker Desktop has already launched. +Docker Desktop also appends a CLI completions block to `~/.zshrc` on first launch — but `~/.zshrc` is now home-manager generated (not a plain file), so that append doesn't persist across a `./rebuild.sh`. The Docker completions fpath addition is already handled declaratively in `home.nix`'s `programs.zsh.initContent`, so this is a no-op in practice. ### 5. Sign Into GUI Apps -- **1Password**: sign into your account so the CLI (`op`) can authenticate later - **Chrome**: sign in, set as default browser if desired - **Cursor / VS Code**: sign in for settings sync - **Maccy**: no account, but enable "Launch at Login" in its preferences @@ -189,7 +201,7 @@ claude # first run opens browser for OAuth login claude doctor # verifies installation + auth ``` -Requires a paid Anthropic account (Pro, Max, Team, Enterprise, or Console with API credits). +Requires a paid Anthropic account (Pro, Max, Team, Enterprise, or Console with API credits). Claude Code is installed via the `claude-code` Homebrew cask (declared in `configuration.nix`), not a native installer — Homebrew's `onActivation.autoUpdate` keeps it current on every `./rebuild.sh`. ### 8. Optional: Enable Atuin History Sync @@ -212,12 +224,12 @@ System Settings > Desktop & Dock > Scroll to "Default web browser / Default term The defaults are chosen carefully, but if you want to customize: -- **Ghostty theme:** edit `ghostty-config`, change the `theme = ...` line. Preview options with `ghostty +list-themes`. -- **Font:** the Brewfile installs both `font-jetbrains-mono-nerd-font` (default) and `font-fira-code-nerd-font`. Change `font-family` in `ghostty-config`. -- **Starship prompt:** edit `starship.toml`. See [starship.rs/presets](https://starship.rs/presets) for ready-made layouts. -- **Shell aliases:** edit `.zshrc` and run `reload`. +- **Ghostty theme:** edit `home/.config/ghostty/config`, change the `theme = ...` line. Preview options with `ghostty +list-themes`. +- **Font:** Hack Nerd Font is the primary system font (Ghostty + WezTerm). JetBrains Mono and Fira Code are also installed (via `home.nix`'s `home.packages`) as alternatives — to switch, change `font-family` in `home/.config/ghostty/config` and `config.font`/`config.window_frame.font` in `home/.config/wezterm/wezterm.lua` to `JetBrainsMono Nerd Font` or `FiraCode Nerd Font`, then run `./rebuild.sh`. +- **Starship prompt:** edit `home.nix`'s `programs.starship.settings`, then run `./rebuild.sh`. +- **Shell aliases:** edit `home.nix`'s `programs.zsh.shellAliases`, then run `./rebuild.sh`. -All configs live in this repo and are symlinked, so changes are preserved in git. +`home/.config/{wezterm,ghostty,nvim,herdr}/` and `home/.baby-menu/` files are edit-in-place — home-manager symlinks them directly into place (`mkOutOfStoreSymlink`), so editing them takes effect immediately, no rebuild needed. Everything else (packages, shell aliases, Starship settings) requires `./rebuild.sh` to apply.

↑ Back to top

@@ -227,12 +239,13 @@ All configs live in this repo and are symlinked, so changes are preserved in git | What you need | Where to look | |---|---| -| Terminal keybindings (tabs, splits, Quick Terminal) | [`docs/ghostty-cheatsheet.md`](docs/ghostty-cheatsheet.md) | -| Shell history search, fuzzy file/dir picker, autosuggestions | [`docs/modern-cli-cheatsheet.md`](docs/modern-cli-cheatsheet.md) | -| Directory jumping (`z`) | [`docs/modern-cli-cheatsheet.md`](docs/modern-cli-cheatsheet.md#jumping-to-directories-zoxide) | -| `rg`, `fd`, `bat`, `eza`, `dust`, `btop` usage | [`docs/modern-cli-cheatsheet.md`](docs/modern-cli-cheatsheet.md) | -| Git TUI (`lg`) | [`docs/lazygit-cheatsheet.md`](docs/lazygit-cheatsheet.md) | -| Language runtime commands (`asdf current`, `asdf install`) | [`docs/asdf-cheatsheet.md`](docs/asdf-cheatsheet.md) | +| Terminal keybindings (tabs, splits, Quick Terminal) | [`docs/cheatsheets/ghostty-cheatsheet.md`](docs/cheatsheets/ghostty-cheatsheet.md) | +| Shell history search, fuzzy file/dir picker, autosuggestions | [`docs/cheatsheets/modern-cli-cheatsheet.md`](docs/cheatsheets/modern-cli-cheatsheet.md) | +| Directory jumping (`z`) | [`docs/cheatsheets/modern-cli-cheatsheet.md`](docs/cheatsheets/modern-cli-cheatsheet.md#jumping-to-directories-zoxide) | +| `rg`, `fd`, `bat`, `eza`, `dust`, `btop` usage | [`docs/cheatsheets/modern-cli-cheatsheet.md`](docs/cheatsheets/modern-cli-cheatsheet.md) | +| Git TUI (`lg`) | [`docs/cheatsheets/lazygit-cheatsheet.md`](docs/cheatsheets/lazygit-cheatsheet.md) | +| Language runtime commands (`asdf current`, `asdf install`) | [`docs/cheatsheets/asdf-cheatsheet.md`](docs/cheatsheets/asdf-cheatsheet.md) | +| Nix / nix-darwin / home-manager commands (`darwin-rebuild`, rollback, GC) | [`docs/cheatsheets/nix-cheatsheet.md`](docs/cheatsheets/nix-cheatsheet.md) | > **On Mac, `Alt` = `Option` (⌥).** fzf and readline docs use "Alt" historically. @@ -246,16 +259,18 @@ This repo is meant to be forked and personalized. The files worth editing: | File | What it controls | |---|---| -| `Brewfile` | What gets installed via Homebrew. Add/remove lines, run `brew bundle`. | -| `.tool-versions` | Language runtime versions. Edit and run `asdf install`. | -| `.zshrc` | Aliases, env vars, tool integration. Run `reload` after editing. | -| `.zsh_plugins.txt` | Zsh plugins loaded by Antidote. | -| `starship.toml` | Prompt appearance. | -| `ghostty-config` | Terminal appearance and keybindings. Reload with `Cmd+Shift+,`. | -| `linearmouse.json` | Mouse settings (side buttons, scroll direction, acceleration). Edit via the LinearMouse GUI; changes write back to the file automatically. | -| `setup.sh` | Bootstrap steps. Only touch if you add new tools needing custom setup. | - -After any changes, commit them to your dotfiles repo. Other machines pick up changes with `git pull && ./setup.sh`. +| `configuration.nix` | System defaults, and Homebrew packages: GUI apps (casks), asdf + its build deps, and the two tapped tools (`terraform`, `stripe`) not worth moving to Nix. Run `./rebuild.sh` after editing. | +| `home.nix` | CLI tools available in nixpkgs (`home.packages`), zsh aliases/keybinds/plugins (`programs.zsh`), Starship prompt (`programs.starship`), and every dotfile symlink (`home.file`). Run `./rebuild.sh` after editing. | +| `home/.tool-versions` | Language runtime versions. Edit and run `./bootstrap.sh` (registers asdf plugins + runs `asdf install`). | +| `home/.config/wezterm/wezterm.lua` | WezTerm terminal appearance. Edit-in-place, no rebuild needed. | +| `home/.config/ghostty/config` | Ghostty terminal appearance and keybindings. Edit-in-place, no rebuild needed. Reload in-app with `Cmd+Shift+,`. | +| `home/.config/nvim/` | Neovim config (lazy.nvim plugin specs under `lua/plugins/`). Edit-in-place, no rebuild needed. | +| `home/.config/herdr/config.toml` | herdr (terminal agent multiplexer) keybindings. Edit-in-place, no rebuild needed. | +| `home/.config/linearmouse/linearmouse.json` | Mouse settings (side buttons, scroll direction, acceleration). Edit via the LinearMouse GUI; changes write back to the file automatically. | +| `home/.baby-menu/` | Baby Menu extensions, preferences, and custom agents. Agent edits write through the symlink; DB/caches stay under `~/.baby-menu/` only. | +| `home/AGENTS.md` | Shared agent instructions, symlinked into Claude Code, Codex, opencode, Pi, and Cursor. | + +After any changes, commit them to your dotfiles repo. Other machines pick up changes with `git pull && ./rebuild.sh` (or `./bootstrap.sh` on a machine that hasn't been bootstrapped yet).

↑ Back to top

@@ -266,34 +281,45 @@ After any changes, commit them to your dotfiles repo. Other machines pick up cha ### Update everything ```bash -./update.sh +git pull +./rebuild.sh ``` -`update.sh` runs each updater in sequence — Homebrew (formulae + casks + cleanup), Zsh plugins (antidote), asdf plugins, and Claude Code. A failure in one section does not abort the rest. +`darwin-rebuild switch` (what `./rebuild.sh` runs) re-applies `configuration.nix` and `home.nix` in one atomic step: any new Homebrew packages, any new `home.packages` entries, any dotfile symlink changes. There's no separate "install new Brewfile entries" step anymore — `Brewfile` is a retired stub; `configuration.nix`'s `homebrew` block is what `darwin-rebuild switch` reads, and it applies unconditionally on every switch (`onActivation.autoUpdate = true`). -After pulling dotfiles changes, also run: +For runtime version changes: ```bash -git pull -brew bundle # install any new Brewfile entries -asdf install # install any new .tool-versions runtimes +./bootstrap.sh # re-registers asdf plugins and runs `asdf install` for anything new in .tool-versions ``` -> **Note:** `brew bundle` installs everything in `Brewfile` unconditionally — including anything you chose to skip in an earlier interactive `./setup.sh` run. See [Homebrew cheat sheet — Common Pitfalls](docs/homebrew-cheatsheet.md#common-pitfalls). +To bump the Nix flake's own pins (nixpkgs, nix-darwin, home-manager, nix-homebrew — this is how Nix-packaged CLI tool *versions* move forward, since `home.packages` doesn't pin exact versions itself) and update Homebrew/asdf all in one pass: + +```bash +./update.sh # nix flake update, then a reminder to ./rebuild.sh; also upgrades Homebrew packages and asdf plugins +``` ### Update just Homebrew packages +Homebrew's own package *versions* (not the declared list, which comes from `configuration.nix`) update via: + ```bash brew update && brew upgrade && brew upgrade --cask brew cleanup ``` -### Update Claude Code +This is independent of `./rebuild.sh` — it updates the installed version of whatever `configuration.nix` already declares, it doesn't change what's declared. + +### Roll back a bad switch + +One of the reasons for the Nix migration — a bad `./rebuild.sh` is a one-command undo: ```bash -claude update +sudo /run/current-system/sw/bin/darwin-rebuild --rollback ``` +See [`docs/cheatsheets/nix-cheatsheet.md`](docs/cheatsheets/nix-cheatsheet.md) for generation management and garbage collection. + ### Update asdf plugins ```bash @@ -306,40 +332,48 @@ asdf plugin update --all ## Troubleshooting -### `./setup.sh` returns "permission denied" +### `./bootstrap.sh` returns "permission denied" The executable bit wasn't preserved. One-time fix: ```bash -chmod +x setup.sh -./setup.sh +chmod +x bootstrap.sh +./bootstrap.sh ``` To make the fix permanent so other machines cloning the repo don't hit this, commit the mode change: ```bash -chmod +x setup.sh -git add setup.sh # `git status` should show "mode change 100644 → 100755" -git commit -m "chore: make setup.sh executable" +chmod +x bootstrap.sh +git add bootstrap.sh # `git status` should show "mode change 100644 → 100755" +git commit -m "chore: make bootstrap.sh executable" git push ``` +### `sudo: darwin-rebuild: command not found` + +`sudo` resets `PATH` and doesn't include where nix-darwin installs `darwin-rebuild`. Use the full path, or just use `./rebuild.sh` (already handles this): + +```bash +sudo /run/current-system/sw/bin/darwin-rebuild switch --flake .#mac +``` + ### "command not found" on a tool that should exist -1. Did you run `./setup.sh`? It symlinks `.zshrc`; without that, aliases and PATH aren't set. +1. Did you run `./bootstrap.sh` (or `./rebuild.sh` if already bootstrapped)? It's what wires up `~/.zshrc`, PATH, and every dotfile symlink. 2. Did you restart your shell after install? Run `exec zsh` or open a new tab. -3. Check the tool is actually installed: `brew list | grep `. +3. Check the tool is actually declared: `grep configuration.nix home.nix`. 4. For language tools (node, python, go): run `asdf current` to verify the active version is installed. ### Icons show as squares in Starship / eza -Your terminal isn't using a Nerd Font. Check `ghostty-config`: +Your terminal isn't using a Nerd Font. Check `home/.config/ghostty/config`: ``` -font-family = JetBrainsMono Nerd Font +font-family = Hack Nerd Font ``` -The spaces matter. See [`docs/ghostty-cheatsheet.md`](docs/ghostty-cheatsheet.md#themes--fonts) for details. +The spaces matter. See [`docs/cheatsheets/ghostty-cheatsheet.md`](docs/cheatsheets/ghostty-cheatsheet.md#themes--fonts) for details. ### Ghostty Quick Terminal doesn't respond @@ -347,7 +381,7 @@ Accessibility permission not granted. Go to System Settings > Privacy & Security ### SSH session looks broken (vim / less render incorrectly) -The remote host doesn't have Ghostty's terminfo. Your `ghostty-config` already sets `term = xterm-256color` to avoid this, but if you removed that line, re-add it. +The remote host doesn't have Ghostty's terminfo. Your `home/.config/ghostty/config` already sets `term = xterm-256color` to avoid this, but if you removed that line, re-add it. ### asdf says "No version is set for command X" @@ -357,9 +391,9 @@ The `.tool-versions` file references a version that isn't installed yet: asdf install ``` -See [`docs/asdf-cheatsheet.md`](docs/asdf-cheatsheet.md#troubleshooting) for deeper issues. +See [`docs/cheatsheets/asdf-cheatsheet.md`](docs/cheatsheets/asdf-cheatsheet.md#troubleshooting) for deeper issues. -### `brew bundle` fails with permissions errors +### `darwin-rebuild switch` fails on a Homebrew step Usually means Homebrew itself needs repair: @@ -368,11 +402,11 @@ sudo chown -R $(whoami) /opt/homebrew brew doctor ``` -See [`docs/homebrew-cheatsheet.md`](docs/homebrew-cheatsheet.md#common-pitfalls). +See [`docs/cheatsheets/homebrew-cheatsheet.md`](docs/cheatsheets/homebrew-cheatsheet.md#common-pitfalls). Note: `brew doctor` will report this Homebrew install as "managed by Nix" (Tier 3) — that's expected since nix-homebrew owns it; ignore warnings that only apply to a plain native Homebrew install. ### Atuin doesn't import my old history -See [Shell History (atuin)](docs/modern-cli-cheatsheet.md#shell-history-atuin) in the modern CLI cheat sheet. +See [Shell History (atuin)](docs/cheatsheets/modern-cli-cheatsheet.md#shell-history-atuin) in the modern CLI cheat sheet. ### Starting over on a single tool @@ -394,18 +428,21 @@ reload ## Cheat Sheets & References -Full command references for the tools that get the most daily use. These live in `docs/` so you can open them in-repo rather than fishing through web docs: - -- **[Software inventory](docs/inventory.md)**: full list of GUI apps, CLI tools, and language runtimes — update this whenever `Brewfile` or `.tool-versions` changes -- **[Homebrew cheat sheet](docs/homebrew-cheatsheet.md)**: install, daily commands, Brewfile workflows, FAQ, common pitfalls -- **[asdf cheat sheet](docs/asdf-cheatsheet.md)**: plugin management, version commands, `.tool-versions` format, CI integration, troubleshooting -- **[Ghostty cheat sheet](docs/ghostty-cheatsheet.md)**: default keybindings, config syntax, action reference, SSH terminfo fixes, themes and fonts -- **[Git cheat sheet](docs/git-cheatsheet.md)**: daily workflow commands, branching, rebasing, undoing mistakes, stash, tags, `.gitignore` essentials, troubleshooting -- **[Lazygit cheat sheet](docs/lazygit-cheatsheet.md)**: panel navigation, default keybindings, line-staging, interactive rebase workflows, custom commands -- **[Modern CLI tools cheat sheet](docs/modern-cli-cheatsheet.md)**: ripgrep, fd, bat, eza, zoxide, fzf, atuin, delta, dust, btop, tldr. Usage per tool plus composition examples -- **[Docker cheat sheet](docs/docker-cheatsheet.md)**: images, containers, volumes, networks, Docker Compose, Dockerfile basics, disk cleanup, troubleshooting -- **[Claude Code cheat sheet](docs/claude-code-cheatsheet.md)**: CLI flags, slash commands, keyboard shortcuts, permission modes, CLAUDE.md, hooks, MCP, subagents, models and cost -- **[Cursor CLI cheat sheet](docs/cursor-cli-cheatsheet.md)**: agent modes (Agent/Plan/Ask), slash commands, cloud handoff, MCP integration, rules and skills, subagents +Full command references for the tools that get the most daily use. These live in `docs/cheatsheets/` so you can open them in-repo rather than fishing through web docs (this folder doubles as an Obsidian vault — see `home.nix`'s `Documents/workspace/my-matrix/a-utils/cheatsheets` symlink): + +- **[Software inventory](docs/inventory.md)**: full list of GUI apps, CLI tools, and language runtimes — update this whenever `configuration.nix`, `home.nix`, or `.tool-versions` changes +- **[Nix cheat sheet](docs/cheatsheets/nix-cheatsheet.md)**: `darwin-rebuild` workflow, rollback, generations, garbage collection, the `homebrew.onActivation.cleanup` gotcha +- **[Homebrew cheat sheet](docs/cheatsheets/homebrew-cheatsheet.md)**: install, daily commands, nix-homebrew notes, FAQ, common pitfalls +- **[asdf cheat sheet](docs/cheatsheets/asdf-cheatsheet.md)**: plugin management, version commands, `.tool-versions` format, CI integration, troubleshooting +- **[Ghostty cheat sheet](docs/cheatsheets/ghostty-cheatsheet.md)**: default keybindings, config syntax, action reference, SSH terminfo fixes, themes and fonts +- **[Git cheat sheet](docs/cheatsheets/git-cheatsheet.md)**: daily workflow commands, branching, rebasing, undoing mistakes, stash, tags, `.gitignore` essentials, troubleshooting +- **[Lazygit cheat sheet](docs/cheatsheets/lazygit-cheatsheet.md)**: panel navigation, default keybindings, line-staging, interactive rebase workflows, custom commands +- **[Modern CLI tools cheat sheet](docs/cheatsheets/modern-cli-cheatsheet.md)**: ripgrep, fd, bat, eza, zoxide, fzf, atuin, delta, dust, btop, tldr. Usage per tool plus composition examples +- **[Docker cheat sheet](docs/cheatsheets/docker-cheatsheet.md)**: images, containers, volumes, networks, Docker Compose, Dockerfile basics, disk cleanup, troubleshooting +- **[Claude Code cheat sheet](docs/cheatsheets/claude-code-cheatsheet.md)**: CLI flags, slash commands, keyboard shortcuts, permission modes, CLAUDE.md, hooks, MCP, subagents, models and cost +- **[Cursor CLI cheat sheet](docs/cheatsheets/cursor-cli-cheatsheet.md)**: agent modes (Agent/Plan/Ask), slash commands, cloud handoff, MCP integration, rules and skills, subagents +- **[Pi cheat sheet](docs/cheatsheets/pi-cheatsheet.md)**: minimal coding agent harness — CLI flags, slash commands, AGENTS.md/skills, packages and extensions +- **[Herdr cheat sheet](docs/cheatsheets/herdr-cheatsheet.md)**: session/workspace/tab/pane model, tmux-style keybindings, worktrees, agent integrations, socket API for scripting agents Each is written as a skimmable reference, not a tutorial. Use them when you need to look something up. @@ -418,26 +455,42 @@ Each is written as a skimmable reference, not a tutorial. Use them when you need ``` dotfiles/ ├── README.md # this file (orientation + daily reference) -├── setup.sh # one-command bootstrap (idempotent) +├── CLAUDE.md # governance rules for Claude Code working in this repo +├── bootstrap.sh # single entry point: fresh-machine bootstrap (idempotent) +├── rebuild.sh # daily use: re-apply configuration.nix/home.nix after editing ├── update.sh # update all package managers and tools -├── verify.sh # end-to-end smoke test (run after setup.sh) -├── Brewfile # Homebrew packages (formulae + casks) -├── .tool-versions # asdf runtime versions (Node, Python, Go) -├── .zshrc # shell config (aliases, tool integration) -├── .zsh_plugins.txt # Antidote plugin list -├── starship.toml # Starship prompt config -├── ghostty-config # Ghostty terminal config -├── linearmouse.json # Mouse customization (side buttons, acceleration) +├── verify.sh # end-to-end smoke test (run after bootstrap.sh) +├── flake.nix # Nix flake entry point (inputs, darwinConfigurations) +├── flake.lock # pinned input versions +├── configuration.nix # system defaults + Homebrew (casks, asdf, tapped tools) +├── home.nix # home-manager: CLI packages, zsh/starship, dotfile symlinks +├── Brewfile # RETIRED — pointer stub, superseded by configuration.nix +├── home/ # edit-in-place source for home-manager's mkOutOfStoreSymlink files +│ ├── AGENTS.md # shared agent instructions (Claude, Codex, opencode, Pi, Cursor) +│ ├── .tool-versions # asdf runtime versions (Node, Python, Go, Java) +│ ├── .claude/ +│ │ └── settings.json # Claude Code settings (theme, statusline) +│ ├── .baby-menu/ # Baby Menu extensions + preferences + agents.json +│ └── .config/ +│ ├── wezterm/wezterm.lua +│ ├── ghostty/config +│ ├── nvim/ # lazy.nvim config: init.lua, vim_config.lua, keys.lua, plugin.lua, plugins/ +│ ├── herdr/config.toml +│ └── linearmouse/linearmouse.json └── docs/ ├── inventory.md # full list of installed apps, tools, and runtimes - ├── homebrew-cheatsheet.md - ├── asdf-cheatsheet.md - ├── ghostty-cheatsheet.md - ├── git-cheatsheet.md - ├── lazygit-cheatsheet.md - ├── modern-cli-cheatsheet.md - ├── claude-code-cheatsheet.md - └── cursor-cli-cheatsheet.md + └── cheatsheets/ + ├── README.md # cheatsheet index (also an Obsidian vault folder) + ├── nix-cheatsheet.md + ├── homebrew-cheatsheet.md + ├── asdf-cheatsheet.md + ├── ghostty-cheatsheet.md + ├── git-cheatsheet.md + ├── lazygit-cheatsheet.md + ├── modern-cli-cheatsheet.md + ├── docker-cheatsheet.md + ├── claude-code-cheatsheet.md + └── cursor-cli-cheatsheet.md ```

↑ Back to top

@@ -448,12 +501,14 @@ dotfiles/ A few choices that drive the rest of the setup. Full context is in the cheat sheets, but the gist: -- **Ghostty over iTerm2**: GPU-accelerated native macOS rendering, ~3× faster than iTerm2, zero-config +- **nix-darwin + home-manager over plain Homebrew + shell scripts**: declarative, atomically-applied config with one-command rollback (`darwin-rebuild --rollback`) beats an imperative install script with no undo. See [`docs/cheatsheets/nix-cheatsheet.md`](docs/cheatsheets/nix-cheatsheet.md). +- **Homebrew kept, not replaced**: GUI `.app` bundles and a few tools not worth repackaging (asdf, terraform, stripe) stay Homebrew-managed via nix-homebrew, declared in `configuration.nix`. CLI tools available in nixpkgs moved to `home.nix`'s `home.packages`. +- **Ghostty and WezTerm, both kept**: rather than picking one, both stay maintained in parallel (`rose-pine-moon` theme, Hack Nerd Font, matching split keybindings) since both had real, independent customization worth preserving. +- **Native home-manager zsh plugins over Antidote**: `programs.zsh.autosuggestion`/`syntaxHighlighting` replace the Antidote plugin manager entirely — fewer moving parts, same behavior. - **Starship over Powerlevel10k**: P10k is on life support; Starship is actively maintained and cross-shell -- **Antidote over Oh My Zsh**: faster startup, picks exactly what you need (OMZ is also defensible if you want its catalog) -- **asdf over pyenv/nvm/rbenv**: one tool replaces all of them; single `.tool-versions` file per project +- **asdf over pyenv/nvm/rbenv, and over Nix for runtimes**: one tool replaces all of them; single `.tool-versions` file per project. Kept outside Nix's management deliberately — asdf's per-project override (walking up the directory tree) is a workflow Nix doesn't replicate without a heavier devshell/direnv setup. - **Zsh kept as login shell**: POSIX-compatible (unlike Fish) and already the macOS default -- **Claude Code via native installer, not Homebrew**: the native installer auto-updates; the brew cask does not -- **Docker for all local databases**: Brewfile intentionally omits `postgresql` / `redis` so they don't conflict with container-based local environments +- **Claude Code via Homebrew cask, not the native installer**: `configuration.nix`'s `homebrew.onActivation.autoUpdate` keeps it current on every switch, consistent with how every other package in this repo updates. +- **Docker for all local databases**: `configuration.nix` intentionally omits `postgresql` / `redis` so they don't conflict with container-based local environments

↑ Back to top

diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..05087a4 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,216 @@ +#!/usr/bin/env bash +# bootstrap.sh — Single entry point for a fresh Mac. +# +# Usage: +# ./bootstrap.sh # interactive (prompts for git identity) +# ./bootstrap.sh --full # non-interactive (reports git identity, doesn't prompt) +# +# What it does, in order: +# 1. Installs Xcode Command Line Tools, if missing. +# 2. Installs Determinate Nix, if it isn't already installed. +# 3. Symlinks this repo to ~/.dotfiles (home.nix points at config files +# through that path). +# 4. Checks the `user` variable in flake.nix against your actual macOS +# username, and offers to fix it for you if they differ. +# 5. Runs the first `darwin-rebuild switch` — this installs every package +# (Homebrew via nix-homebrew, CLI tools via home.nix) and wires up all +# dotfile symlinks. Everything past this point is stuff Nix genuinely +# can't express: +# 6. Registers asdf plugins and installs runtimes from .tool-versions +# (per-project .tool-versions overrides don't fit Nix's model, so +# runtimes stay asdf-managed by design). +# 7. Installs the Cursor CLI (`agent`) via Cursor's own installer — not +# Nix/Homebrew-managed. +# 8. Prompts for git identity (still written directly to ~/.gitconfig — +# pager/merge/delta config is now nix-managed separately via +# ~/.config/git/config). +# +# After this, `darwin-rebuild` exists on PATH and you're on the normal +# workflow: edit files, then run ./rebuild.sh. +# +# Idempotent: safe to re-run at any time (steps that are already done are skipped). + +set -euo pipefail + +DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HOST_LABEL="mac" +FULL=false +[[ "${1:-}" == "--full" ]] && FULL=true + +if [[ -t 1 ]]; then + G=$'\033[0;32m' Y=$'\033[0;33m' B=$'\033[0;34m' C=$'\033[0;36m' W=$'\033[1m' R=$'\033[0m' +else + G='' Y='' B='' C='' W='' R='' +fi +info() { printf "${B} → ${R}%s\n" "$*"; } +done_() { printf "${G} ✓ ${R}%s\n" "$*"; } +warn() { printf "${Y} ! ${R}%s\n" "$*" >&2; } +section() { printf "\n${W}${C}━━ %s${R}\n" "$*"; } + +# ── 1. Xcode Command Line Tools ────────────────────────────────────────────── +section "Xcode Command Line Tools" +if ! xcode-select -p >/dev/null 2>&1; then + info "Installing Xcode Command Line Tools (GUI prompt) …" + xcode-select --install + warn "Re-run this script once CLT installation finishes." + exit 0 +fi +done_ "Xcode Command Line Tools" + +# ── 2. Determinate Nix ─────────────────────────────────────────────────────── +section "Nix" +if ! command -v nix &>/dev/null; then + info "Installing Determinate Nix..." + curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install --no-confirm + done_ "Determinate Nix installed" + warn "Open a new terminal (or re-run this script) so the Nix environment is loaded." + exit 0 +else + done_ "Nix already installed" +fi + +# ── 3. Symlink repo to ~/.dotfiles ────────────────────────────────────────── +if [[ ! -e "$HOME/.dotfiles" ]]; then + ln -s "$DOTFILES_DIR" "$HOME/.dotfiles" + done_ "Symlinked $DOTFILES_DIR -> ~/.dotfiles" +elif [[ "$(readlink "$HOME/.dotfiles" 2>/dev/null)" != "$DOTFILES_DIR" ]]; then + warn "~/.dotfiles exists and points somewhere else — leaving it alone." +else + done_ "~/.dotfiles already linked" +fi + +# ── 4. Username check ──────────────────────────────────────────────────────── +ACTUAL_USER="$(whoami)" +DECLARED_USER="$(grep -o 'user = "[^"]*"' "$DOTFILES_DIR/flake.nix" | head -1 | sed 's/user = "\(.*\)"/\1/')" +if [[ "$ACTUAL_USER" != "$DECLARED_USER" ]]; then + warn "flake.nix declares user \"$DECLARED_USER\" but this Mac's user is \"$ACTUAL_USER\"." + read -rp " Update flake.nix to use \"$ACTUAL_USER\"? [y/N] " REPLY + if [[ "$REPLY" =~ ^[Yy]$ ]]; then + sed -i '' "s/user = \"$DECLARED_USER\"/user = \"$ACTUAL_USER\"/" "$DOTFILES_DIR/flake.nix" + done_ "Updated flake.nix" + else + warn "Leaving flake.nix as-is — the switch below may fail." + fi +else + done_ "flake.nix user matches this Mac ($ACTUAL_USER)" +fi + +# ── 5. First switch ────────────────────────────────────────────────────────── +section "darwin-rebuild switch" +info "Running first darwin-rebuild switch (this will prompt for your password)..." +sudo nix run nix-darwin/nix-darwin-26.05#darwin-rebuild -- switch --flake "$DOTFILES_DIR#${HOST_LABEL}" +done_ "nix-darwin bootstrapped — packages installed, dotfiles symlinked." + +# ── 6. Language Runtimes (asdf) ─────────────────────────────────────────────── +# asdf itself just got installed via configuration.nix's homebrew.brews. +# Plugins and the actual runtime installs from .tool-versions aren't Nix's job. +section "Language Runtimes (asdf)" +if command -v asdf >/dev/null 2>&1; then + while read -r lang _version; do + [[ -z "$lang" ]] && continue + asdf plugin add "$lang" 2>/dev/null || true + done_ "asdf plugin: $lang" + done < "$DOTFILES_DIR/home/.tool-versions" + info "Installing versions from .tool-versions (may take a few minutes) …" + asdf install + done_ "Language runtimes installed" +else + warn "asdf not found on PATH yet — open a new terminal and re-run this script." +fi + +# ── 7. Cursor CLI ───────────────────────────────────────────────────────────── +# Not Nix/Homebrew-managed — Cursor ships its own self-updating installer, +# same trust model already accepted for the Nix installer above. +section "Cursor CLI" +if ! command -v agent &>/dev/null; then + info "Installing Cursor CLI..." + curl https://cursor.com/install -fsS | bash + done_ "Cursor CLI installed (agent)" +else + done_ "Cursor CLI already installed (agent)" +fi + +# ── 8. Git Configuration ───────────────────────────────────────────────────── +# Identity stays here (not home-manager's programs.git) so it's easily +# settable per-machine and writes directly to mutable ~/.gitconfig. +# Pager/merge/delta config is nix-managed separately via home.nix's +# programs.git.settings, applied to ~/.config/git/config. +section "Git Configuration" + +_branch=main +if ! $FULL; then + _cur_branch=$(git config --global init.defaultBranch 2>/dev/null || echo "main") + printf " Default branch [%s]: " "$_cur_branch" + read -r _branch /dev/null || echo "") +_cur_email=$(git config --global user.email 2>/dev/null || echo "") + +if ! $FULL; then + printf " Name" + [[ -n "$_cur_name" ]] && printf " [%s]" "$_cur_name" + printf ": " + read -r _name Privacy & Security > Accessibility" +echo +echo " 5. Launch Docker Desktop once to complete its install:" +echo " open -a Docker" +echo +echo " 6. Sign into GUI apps (Chrome, Cursor, VS Code)" +echo +echo " 7. Authenticate Claude Code:" +echo " claude" +echo +echo " 8. Authenticate Cursor CLI:" +echo " agent login" +echo +echo " 9. (Optional) Enable Atuin shell history sync:" +echo " atuin register -u -e " +echo +echo " 10. (Optional) Authenticate cloud CLIs:" +echo " gcloud auth login" +echo +echo " From now on, after editing config: ./rebuild.sh" +echo " See README.md 'Manual Steps' section for full details." diff --git a/claude/settings.json b/claude/settings.json deleted file mode 100644 index 4fed33f..0000000 --- a/claude/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "statusLine": { - "type": "command", - "command": "bash /Users/lakshyadevsingh/.claude/statusline-command.sh" - }, - "effortLevel": "high", - "agentPushNotifEnabled": true, - "skipAutoPermissionPrompt": true -} diff --git a/claude/statusline-command.sh b/claude/statusline-command.sh deleted file mode 100644 index b15eafe..0000000 --- a/claude/statusline-command.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# ~/.claude/statusline-command.sh -# Mirrors the Starship prompt style: dir · git branch/status · model · context % - -input=$(cat) - -# --- Directory (truncate to 3 levels, similar to Starship truncation_length=3) --- -cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd') -home_cwd="${cwd/#$HOME/~}" -# Keep last 3 path components -dir=$(echo "$home_cwd" | awk -F'/' '{ if (NF > 3) { print "…/" $(NF-2) "/" $(NF-1) "/" $NF } else { print $0 } }') - -# --- Git branch + dirty flag (skip optional locks to avoid races) --- -branch="" -dirty="" -if git_branch=$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null); then - branch="$git_branch" - if [ -n "$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" status --porcelain 2>/dev/null)" ]; then - dirty="*" - fi -elif git_tag=$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" describe --tags --exact-match HEAD 2>/dev/null); then - branch="$git_tag" -fi - -# --- Claude session data --- -model=$(echo "$input" | jq -r '.model.display_name // empty') -remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty') - -# --- Assemble output with ANSI colors (dimmed-friendly) --- -# Cyan for dir, purple for git, green for model, yellow for context -printf "\033[36m%s\033[0m" "$dir" - -if [ -n "$branch" ]; then - printf " \033[35m %s%s\033[0m" "$branch" "$dirty" -fi - -if [ -n "$model" ]; then - printf " \033[32m%s\033[0m" "$model" -fi - -if [ -n "$remaining" ]; then - printf " \033[33mctx:%s%%\033[0m" "$(printf '%.0f' "$remaining")" -fi diff --git a/codex-instructions.md b/codex-instructions.md deleted file mode 100644 index b9eb467..0000000 --- a/codex-instructions.md +++ /dev/null @@ -1,41 +0,0 @@ -# Git Conventions - -## Commit Messages - -Write commit subjects as Conventional Commits with a scope. If the current -branch name contains a Jira ticket ID, prefix the subject with that ID: - -``` -(): -``` - -``` - (): -``` - -- **type**: one of `feat`, `fix`, `refactor`, `chore`, `docs`, `deploy`, `test`, `perf`, `style`, `build`, `ci`. -- **scope**: area touched, lowercase (e.g. `billing`, `auth`). Combine related scopes with `+` (e.g. `auth+security`, `vouchers+billing`). -- **summary**: imperative mood, lowercase start, no trailing period. -- **JIRA-ID**: only include when present in the current branch name (e.g. `ABC-123` from `feature/ABC-123-add-login`). Preserve uppercase. -- Add a blank line then a body for context (what/why), wrapped at ~72 chars. -- Keep each commit focused — split unrelated changes into separate commits. - -Examples: -- `refactor(billing): unify billing_category resolution` -- `ABC-123 refactor(billing): unify billing_category resolution` -- `feat(vouchers): admin list / get endpoints` -- `fix(vouchers+billing): voucher_grant rounding` -- `chore(infra+deploy): rotate voucher secret` - -## Pull Requests - -- **Title**: under 70 characters, concise, imperative mood. -- **Body**: - - ``` - ## Summary - <1-3 bullet points> - - ## Test plan - [Bulleted markdown checklist of TODOs for testing the PR] - ``` diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..2f2894f --- /dev/null +++ b/configuration.nix @@ -0,0 +1,107 @@ +{ user, ... }: + +{ + # Determinate already manages the Nix daemon, so nix-darwin shouldn't. + nix.enable = false; + + nixpkgs.config.allowUnfree = true; + nixpkgs.hostPlatform = "aarch64-darwin"; # use x86_64-darwin for Intel CPU + + system.primaryUser = user; + users.users.${user} = { + home = "/Users/${user}"; + }; + system.stateVersion = 6; + + system.defaults = { + NSGlobalDomain = { + AppleInterfaceStyle = "Dark"; + KeyRepeat = 2; # fast key repeat + InitialKeyRepeat = 15; # short delay before repeat + _HIHideMenuBar = true; # auto-hide the menu bar + AppleShowAllExtensions = true; + }; + dock.autohide = true; + finder.FXPreferredViewStyle = "Nlsv"; # list view by default + finder.CreateDesktop = false; # clean desktop + trackpad.Clicking = true; # tap to click + }; + + + nix-homebrew = { + enable = true; + inherit user; + # This Mac already has a native Homebrew install. autoMigrate lets + # nix-homebrew adopt it: it deletes and recreates Homebrew's own + # management directory (the `brew` tool + git metadata), but leaves + # already-installed formulae/casks (Cellar/Caskroom) untouched. + autoMigrate = true; + }; + + homebrew = { + enable = true; + onActivation.autoUpdate = true; + # Start at "none", not "zap": undeclared casks/formulae are left alone + # rather than force-uninstalled. Only consider "zap" once `brew list` + # has been verified to match this list exactly after a few switches. + onActivation.cleanup = "none"; + + taps = [ + "hashicorp/tap" + "stripe/stripe-cli" + "kunchenguid/tap" + ]; + + # CLI tools that exist in nixpkgs (ripgrep, fd, bat, eza, zoxide, fzf, + # delta, lazygit, btop, dust, tldr, atuin, neovim, starship, jq, + # tree, wget, git, gh, opencode) are now installed via home.nix's + # home.packages / programs.* instead of here — see home.nix. antidote is + # dropped entirely (native home-manager zsh plugins replace it). Only + # things genuinely still Homebrew's job stay in this list: asdf itself + # (runtimes stay asdf-managed by design) and its build-support libs, plus + # the two tapped tools not worth moving. + brews = [ + "asdf" + "coreutils" + "openssl@3" + "readline" + "xz" + "hashicorp/tap/terraform" + "stripe/stripe-cli/stripe" + "herdr" # agent multiplexer for the terminal (tmux-style, config in home/.config/herdr) + ]; + + casks = [ + # Containers + "docker-desktop" + # Cloud tooling + "gcloud-cli" + # Terminal emulators & editors + "ghostty" + "wezterm" + "visual-studio-code" + "cursor" + # AI coding tools + "claude" + "claude-code" + "codex" + "codex-app" + # Browsers + "google-chrome" + "firefox" + "chatgpt-atlas" + # Productivity & utilities + "rectangle" + "appcleaner" + "maccy" + "linearmouse" + "opensuperwhisper" + "obsidian" + "kunchenguid/tap/baby-menu" # agent-editable menu bar (https://github.com/kunchenguid/baby-menu) + # API testing + "granola" + "postman" + "whimsical" + ]; + }; +} diff --git a/cursor-rules/git-commits.mdc b/cursor-rules/git-commits.mdc deleted file mode 100644 index 23cd0c6..0000000 --- a/cursor-rules/git-commits.mdc +++ /dev/null @@ -1,46 +0,0 @@ ---- -description: Git commit message and pull request conventions -alwaysApply: true ---- - -# Git Conventions - -## Commit Messages - -Write commit subjects as Conventional Commits with a scope. If the current -branch name contains a Jira ticket ID, prefix the subject with that ID: - -``` -(): -``` - -``` - (): -``` - -- **type**: one of `feat`, `fix`, `refactor`, `chore`, `docs`, `deploy`, `test`, `perf`, `style`, `build`, `ci`. -- **scope**: area touched, lowercase (e.g. `billing`, `auth`). Combine related scopes with `+` (e.g. `auth+security`, `vouchers+billing`). -- **summary**: imperative mood, lowercase start, no trailing period. -- **JIRA-ID**: only include when present in the current branch name (e.g. `ABC-123` from `feature/ABC-123-add-login`). Preserve uppercase. -- Add a blank line then a body for context (what/why), wrapped at ~72 chars. -- Keep each commit focused — split unrelated changes into separate commits. - -Examples: -- `refactor(billing): unify billing_category resolution` -- `ABC-123 refactor(billing): unify billing_category resolution` -- `feat(vouchers): admin list / get endpoints` -- `fix(vouchers+billing): voucher_grant rounding` -- `chore(infra+deploy): rotate voucher secret` - -## Pull Requests - -- **Title**: under 70 characters, concise, imperative mood. -- **Body**: - - ``` - ## Summary - <1-3 bullet points> - - ## Test plan - [Bulleted markdown checklist of TODOs for testing the PR] - ``` diff --git a/docs/cheatsheets/README.md b/docs/cheatsheets/README.md new file mode 100644 index 0000000..ab2c09e --- /dev/null +++ b/docs/cheatsheets/README.md @@ -0,0 +1,43 @@ +--- +tag: + - type/readme + - topic/cheatsheet +--- + +# Cheat Sheets — Index + +Every cheat sheet here has frontmatter `tag:`/`related:` for Obsidian's tag pane and graph view — this index is the entry point, not the only way in. Backlinks aren't maintained manually anywhere in this vault; Obsidian computes them automatically from any note-to-note link, so linking one direction here is enough. + +--- + +## Package Management + +- [[homebrew-cheatsheet]] — GUI apps (casks), the handful of CLI tools still installed via Homebrew, Brewfile mechanics +- [[nix-cheatsheet]] — nix-darwin/home-manager daily workflow, validation, rollback, the `cleanup = "none"` gotcha +- [[asdf-cheatsheet]] — language runtime versions via `.tool-versions` + +## Terminal & Shell + +- [[ghostty-cheatsheet]] — keybindings, config syntax, Quick Terminal, SSH terminfo fixes +- [[modern-cli-cheatsheet]] — ripgrep/fd/bat/eza/zoxide/fzf/atuin/delta/dust/btop, organized by task + +## Git & Version Control + +- [[git-cheatsheet]] — daily git workflow, branching, rebasing, undoing mistakes +- [[lazygit-cheatsheet]] — the `lg` TUI: panels, keybindings, line-staging + +## Editors + +- [[vim-cheat-sheet]] — modal editing 80/20: motions, operators, the `[count]+operator+motion` formula + +## AI Coding Agents + +- [[claude-code-cheatsheet]] — Claude Code CLI: flags, slash commands, hooks, MCP, subagents +- [[cursor-cli-cheatsheet]] — Cursor CLI: Agent/Plan/Ask modes, Cloud Handoff, MCP, subagents +- [[pi-cheatsheet]] — Pi coding agent: minimal harness, packages/extensions, AGENTS.md, skills +- [[herdr-cheatsheet]] — herdr agent multiplexer: sessions/workspaces/tabs/panes, tmux-style keybindings, socket API for scripting agents + +## Containers + +- [[docker-cheatsheet]] — Docker Desktop: images, containers, Compose, cleanup + diff --git a/docs/asdf-cheatsheet.md b/docs/cheatsheets/asdf-cheatsheet.md similarity index 98% rename from docs/asdf-cheatsheet.md rename to docs/cheatsheets/asdf-cheatsheet.md index 7f17830..f02a2c6 100644 --- a/docs/asdf-cheatsheet.md +++ b/docs/cheatsheets/asdf-cheatsheet.md @@ -1,3 +1,13 @@ +--- +tag: + - type/cheatsheet + - topic/package-management +related: + - "[[homebrew-cheatsheet]]" + - "[[nix-cheatsheet]]" + - "[[git-cheatsheet]]" +--- + # asdf Cheat Sheet & Best Practices A reference for the day-to-day and the "I set this up months ago and now I need to remember how" moments. Targets asdf `0.16+` (the Go rewrite); older `source asdf.sh` syntax is deprecated and not covered here. diff --git a/docs/claude-code-cheatsheet.md b/docs/cheatsheets/claude-code-cheatsheet.md similarity index 97% rename from docs/claude-code-cheatsheet.md rename to docs/cheatsheets/claude-code-cheatsheet.md index 969bba1..3d1fb82 100644 --- a/docs/claude-code-cheatsheet.md +++ b/docs/cheatsheets/claude-code-cheatsheet.md @@ -1,6 +1,15 @@ +--- +tag: + - type/cheatsheet + - topic/ai-agent +related: + - "[[cursor-cli-cheatsheet]]" + - "[[git-cheatsheet]]" +--- + # Claude Code Cheat Sheet -Reference for Claude Code, Anthropic's agentic CLI. Current as of April 2026, covering through v2.1.116 (the version installed by your `setup.sh`). +Reference for Claude Code, Anthropic's agentic CLI. Current as of April 2026, covering through v2.1.116 (the version installed via the `claude-code` Homebrew cask). Official docs: @@ -27,7 +36,7 @@ Official docs: ## Installation & Authentication -Claude Code was installed by `setup.sh` via the native installer. Basic management: +Claude Code is installed via the `claude-code` Homebrew cask, declared in `configuration.nix`'s `homebrew.casks` and kept up to date by Homebrew's `onActivation.autoUpdate` (not a native installer). Basic management: ```bash claude doctor # verify installation health diff --git a/docs/cursor-cli-cheatsheet.md b/docs/cheatsheets/cursor-cli-cheatsheet.md similarity index 95% rename from docs/cursor-cli-cheatsheet.md rename to docs/cheatsheets/cursor-cli-cheatsheet.md index 4640938..453135d 100644 --- a/docs/cursor-cli-cheatsheet.md +++ b/docs/cheatsheets/cursor-cli-cheatsheet.md @@ -1,3 +1,11 @@ +--- +tag: + - type/cheatsheet + - topic/ai-agent +related: + - "[[claude-code-cheatsheet]]" +--- + # Cursor CLI Cheat Sheet Reference for Cursor CLI (the terminal companion to the Cursor editor). Current as of April 2026, covering Agent Modes, Cloud Handoff, MCP integration, and Subagents (Cursor 2.4+). @@ -309,6 +317,8 @@ Manage with `/rules` to create or edit interactively. The CLI also reads `AGENTS.md` and `CLAUDE.md` at project root (if present) and applies them as rules, so a well-written CLAUDE.md works for both tools. +> **No global rules yet.** Unlike Claude Code (`~/.claude/CLAUDE.md`) and Codex (`~/.codex/AGENTS.md`), Cursor CLI has no home-directory rules file - it only reads `.cursor/rules/`, `AGENTS.md`, and `CLAUDE.md` from the current project's root. Cursor's own team has confirmed this on the forum ("Global AI rules aren't supported yet, instructions must be defined at the project level"); there's an open, unresolved feature request for it as of mid-2026. This repo's `home/AGENTS.md` is the shared source of truth for Claude/Codex/OpenCode, but it must be manually symlinked or copied into each project's root for Cursor CLI to pick it up there. + ### Skills (on-demand knowledge) New in 2.4. Unlike rules, skills are discovered by the agent when relevant, or you invoke them via the slash menu. diff --git a/docs/docker-cheatsheet.md b/docs/cheatsheets/docker-cheatsheet.md similarity index 99% rename from docs/docker-cheatsheet.md rename to docs/cheatsheets/docker-cheatsheet.md index 0b64e9f..ebc4d43 100644 --- a/docs/docker-cheatsheet.md +++ b/docs/cheatsheets/docker-cheatsheet.md @@ -1,3 +1,11 @@ +--- +tag: + - type/cheatsheet + - topic/containers +related: + - "[[homebrew-cheatsheet]]" +--- + # Docker Cheat Sheet A reference for Docker Desktop on macOS. Covers daily container/image commands, Compose workflows, and the troubleshooting you'll actually need. diff --git a/docs/ghostty-cheatsheet.md b/docs/cheatsheets/ghostty-cheatsheet.md similarity index 96% rename from docs/ghostty-cheatsheet.md rename to docs/cheatsheets/ghostty-cheatsheet.md index cb85162..fd76ae3 100644 --- a/docs/ghostty-cheatsheet.md +++ b/docs/cheatsheets/ghostty-cheatsheet.md @@ -1,3 +1,12 @@ +--- +tag: + - type/cheatsheet + - topic/terminal +related: + - "[[modern-cli-cheatsheet]]" + - "[[nix-cheatsheet]]" +--- + # Ghostty Cheat Sheet & Best Practices A reference for Ghostty on macOS (2026). Covers default keybindings, config syntax, common actions, and the gotchas that trip people up. @@ -49,7 +58,7 @@ These ship with Ghostty and don't require config. All use the `Cmd` modifier to | `Cmd+Shift+E` | Equalize splits | | `Cmd+Shift+F` | Zooms into one panel (press again to restore) | -Note: Split *creation* keybindings aren't default; they're in your `ghostty-config`. Navigation between existing splits is fully default on macOS. (`Alt` in shortcuts above = the key labeled Option `⌥`.) +Note: Split *creation* keybindings aren't default; they're in your `home/.config/ghostty/config`. Navigation between existing splits is fully default on macOS. (`Alt` in shortcuts above = the key labeled Option `⌥`.) ### Clipboard @@ -391,7 +400,7 @@ Do this once per remote you care about. ### Commit your config to dotfiles -`~/.config/ghostty/config` is plain text. Version it. In this repo it's at `ghostty-config` in the root and symlinked into place by `setup.sh`. +`~/.config/ghostty/config` is plain text. Version it. In this repo it's at `home/.config/ghostty/config`, symlinked into place by `home.nix` (`mkOutOfStoreSymlink`) — edits there take effect immediately, no rebuild needed. ### Keep the config minimal diff --git a/docs/git-cheatsheet.md b/docs/cheatsheets/git-cheatsheet.md similarity index 73% rename from docs/git-cheatsheet.md rename to docs/cheatsheets/git-cheatsheet.md index 63ff393..2497fac 100644 --- a/docs/git-cheatsheet.md +++ b/docs/cheatsheets/git-cheatsheet.md @@ -1,3 +1,12 @@ +--- +tag: + - type/cheatsheet + - topic/git +related: + - "[[lazygit-cheatsheet]]" + - "[[asdf-cheatsheet]]" +--- + # Git Cheat Sheet & Best Practices A reference for git workflows that come up daily. Focused on what you actually use, organized by task, with the gotchas that cause real problems. @@ -12,9 +21,13 @@ Official docs: - [Starting a Repository](#starting-a-repository) - [The Daily Loop](#the-daily-loop) - [Branching](#branching) +- [Worktrees (Bare-Repo Pattern)](#worktrees-bare-repo-pattern) - [Merging & Rebasing](#merging--rebasing) - [Remote Work (Pushing, Pulling, Fetching)](#remote-work-pushing-pulling-fetching) - [Inspecting History](#inspecting-history) +- [Code Smell Review](#code-smell-review) +- [Commit Message Conventions](#commit-message-conventions) +- [Pull Request Description Conventions](#pull-request-description-conventions) - [Undoing Things](#undoing-things) - [Stashing](#stashing) - [Tags & Releases](#tags--releases) @@ -170,6 +183,74 @@ git branch --merged | grep -v "main\|master\|\*" | xargs -n 1 git branch -d --- +## Worktrees (Bare-Repo Pattern) + +For projects with many parallel branches in flight (e.g. running multiple coding agents across features), use a bare repo as the project's git store, with every branch — including the default one — checked out as an equal-status sibling worktree. No single "primary" clone; no asymmetry. + +``` +tatbiq/ +├── .bare/ # bare repo — the actual git store +├── .git # file: "gitdir: ./.bare" +├── main/ # one worktree per branch, named after the branch +├── feature/ +│ └── x/ # slash in branch name nests the worktree dir to match +└── td-130/ +``` + +### Setting one up from scratch + +```bash +mkdir myproject && cd myproject +git clone --bare git@github.com:org/myproject.git .bare +git --git-dir=.bare config core.bare true +git --git-dir=.bare config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" +git --git-dir=.bare fetch origin +# `clone --bare` mirrors origin's branches straight into refs/heads with no +# tracking info attached. Wipe them now (refs/remotes/origin/* above already +# has everything) so the first `worktree add` of each branch goes through +# git's normal DWIM tracking setup instead of silently skipping it. +git --git-dir=.bare for-each-ref --format='delete %(refname)' refs/heads | git --git-dir=.bare update-ref --stdin +printf 'gitdir: ./.bare\n' > .git +git worktree add main main +``` + +### Day to day + +```bash +git worktree list # see every worktree (run from anywhere in the tree) +git worktree add # add one for an existing branch +git worktree add -b # create a new branch off as a worktree +git worktree remove # deregister + delete; NEVER just `rm -rf` a worktree dir — + # that leaves a stale/prunable entry behind +git worktree prune # clean up stale entries after a manual rm -rf +git worktree lock # protect a worktree (e.g. on a network/removable drive) from pruning +``` + +Gotchas: +- Git refuses to check out the same branch in two worktrees at once — relevant when parallelizing agents, since each needs its own branch. +- Hooks and local git config are shared across all worktrees (one `.bare`); a `git fetch` in any worktree makes new branches visible to all of them immediately. +- A repo's default branch for new worktrees (`origin/HEAD`) can be repointed per local clone without touching the actual GitHub default: + ```bash + git --git-dir=.bare symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/develop + ``` + +### `wtnew` — this repo's shortcut + +`home.nix` defines a `wtnew` shell function (see `programs.zsh.initContent`) that wraps the setup above: + +```bash +wtnew [base-branch] [target-path] +``` + +- Discovers the project root by walking up from `$PWD` looking for a `.bare/` dir — works in any project using this pattern, not just one repo. +- ``: creates it (branching off `[base-branch]`, or the bare repo's `origin/HEAD` if omitted) if it doesn't exist yet locally or on `origin`; otherwise just checks it out. +- `[target-path]`: defaults to `/`; pass an explicit path to override. +- If `` has no upstream set (common right after the initial `git clone --bare`, which mirrors `origin`'s branches straight into `refs/heads` with no tracking info, and doesn't configure `remote.origin.fetch` either), `wtnew` configures `remote.origin.fetch`, fetches that one branch from `origin` into `refs/remotes/origin/`, and backfills the upstream with `git branch --set-upstream-to`. Silently skips if `origin` doesn't have the branch (e.g. a local-only branch). +- Attaches a herdr session via `herdr worktree open` afterward, if herdr is installed — see [herdr-cheatsheet.md](herdr-cheatsheet.md#worktrees). +- If `[target-path]` (or the default `/`) already exists and is a worktree registered against the bare repo (checked via `git worktree list`), `wtnew` skips creation entirely and just (re)attaches a herdr session to it — so the same command doubles as "open an existing worktree." A path that exists but isn't a registered worktree of this repo still errors out, to avoid clobbering an unrelated directory. + +--- + ## Merging & Rebasing ```bash @@ -298,6 +379,42 @@ lg # lazygit (full TUI) --- +## Code Smell Review + +A shared `smell` skill (Clean Code + Gang of Four + Python-specific catalog) is symlinked into Claude Code, Codex CLI, and Cursor from a single canonical source — see [inventory.md — Shared agent skills](../inventory.md#shared-agent-skills) for how the symlinks are wired. + +Ask any of the three agents to run a smell review (it triggers on phrases like "check for code smells" or "review this before I merge"), optionally naming a base branch: + +``` +review this diff for code smells against develop +``` + +It diffs committed + working-tree changes against the resolved base branch (explicit branch, else `origin/HEAD`, else `main`), classifies the change, picks a Clean Code / Gang of Four / Mixed lens, then reports findings as `BLOCKER`/`HIGH`/`MEDIUM`/`LOW`/`NIT`, each citing one catalog ID (e.g. `CC.G5` Duplication, `PY.BARE-EXCEPT`), a one-line why, and a one-line fix. + +Canonical source: `home/skills/smell/SKILL.md` in this repo. Edit it there — the per-tool copies are symlinks, so changes apply everywhere without a rebuild. + +--- + +## Commit Message Conventions + +A shared `commit-message` skill is symlinked into Claude Code, Codex CLI, and Cursor from a single canonical source — see [inventory.md — Shared agent skills](../inventory.md#shared-agent-skills) for how the symlinks are wired. + +It formats commit subjects as Conventional Commits with a lowercase scope (`type(scope): summary`), prefixing the Jira ticket ID when the current branch name contains one (e.g. `ABC-123 feat(billing): ...`). + +Canonical source: `home/skills/commit-message/SKILL.md` in this repo. Edit it there — the per-tool copies are symlinks, so changes apply everywhere without a rebuild. + +--- + +## Pull Request Description Conventions + +A shared `pr-description` skill is symlinked into Claude Code, Codex CLI, and Cursor from a single canonical source — see [inventory.md — Shared agent skills](../inventory.md#shared-agent-skills) for how the symlinks are wired. + +It formats PR titles the same way as commit subjects, and bodies as `# Summary` / `# Changes` / `# Why` / `# Test plan` sections wrapped in a fenced markdown code block. + +Canonical source: `home/skills/pr-description/SKILL.md` in this repo. Edit it there — the per-tool copies are symlinks, so changes apply everywhere without a rebuild. + +--- + ## Undoing Things This is the section people need most. Git's philosophy: almost everything is recoverable if you haven't deleted the `.git` directory. diff --git a/docs/cheatsheets/herdr-cheatsheet.md b/docs/cheatsheets/herdr-cheatsheet.md new file mode 100644 index 0000000..27ebd04 --- /dev/null +++ b/docs/cheatsheets/herdr-cheatsheet.md @@ -0,0 +1,325 @@ +--- +tag: + - type/cheatsheet + - topic/herdr + - topic/terminal +related: + - "[[ghostty-cheatsheet]]" + - "[[claude-code-cheatsheet]]" + - "[[cursor-cli-cheatsheet]]" + - "[[pi-cheatsheet]]" + - "[[git-cheatsheet]]" +--- + +# Herdr Cheat Sheet + +A reference for herdr, the terminal workspace manager for AI coding agents used in this setup (tmux-style `Ctrl+B` prefix, config at `home/.config/herdr/config.toml`, edit-in-place — no rebuild needed). herdr runs a persistent background server; the terminal you attach to is a thin client, so agent sessions survive terminal restarts and can be detached/reattached like tmux. + +Official docs: + +--- + +## Table of Contents + +- [Mental Model: Session → Workspace → Tab → Pane](#mental-model-session--workspace--tab--pane) +- [Launching & Sessions](#launching--sessions) +- [Prefix Keybindings (this repo's config)](#prefix-keybindings-this-repos-config) +- [Default Keybindings (unconfigured actions)](#default-keybindings-unconfigured-actions) +- [Workspaces](#workspaces) +- [Tabs](#tabs) +- [Panes](#panes) +- [Worktrees](#worktrees) +- [Agent Integrations](#agent-integrations) +- [Socket API — Scripting Herdr](#socket-api--scripting-herdr) +- [Remote & Server](#remote--server) +- [Configuration](#configuration) +- [Common Workflows](#common-workflows) +- [Tips & Gotchas](#tips--gotchas) + +--- + +## Mental Model: Session → Workspace → Tab → Pane + +herdr's structure nests four levels, each with its own subcommand namespace: + +| Level | Analogy | What it holds | +|---|---|---| +| Session | tmux session | A named, persistent server-backed connection. Survives detach/terminal close. | +| Workspace | tmux session-within-a-session / project | A logical project context (often one per repo or git worktree). Has its own set of tabs. | +| Tab | tmux window | A named tab within a workspace, holding one or more panes. | +| Pane | tmux pane | A split terminal running a shell or a detected AI agent (Claude Code, Codex, Cursor, etc.). | + +herdr auto-detects which coding agent is running in a pane (via [integrations](#agent-integrations)) and tracks its state (`idle` / `working` / `blocked` / `unknown`), which drives notifications and the `herdr agent wait` / `herdr wait` scripting commands. + +--- + +## Launching & Sessions + +```bash +herdr # launch or attach to the persistent (default) session +herdr --session # use or create a named persistent session +herdr --no-session # run monolithically, no server/client (escape hatch) +herdr --remote user@host # attach through SSH to a remote herdr server +herdr status # local client + running server status +``` + +| Command | Action | +|---|---| +| `herdr session list [--json]` | List named sessions | +| `herdr session attach ` | Attach to a named session | +| `herdr session stop ` | Stop a session (`default` targets the default session) | +| `herdr session delete ` | Delete a named session | + +Detach without killing anything with the `detach` keybinding (default `prefix+q`) — the server keeps running headless, agents keep working, and `herdr` or `herdr session attach ` picks the session back up. + +--- + +## Prefix Keybindings (this repo's config) + +All prefix actions require pressing `Ctrl+B` first, then the key — same two-step model as tmux. This repo intentionally mirrors tmux's split keys (`"` / `%`) instead of herdr's defaults. + +| Key | Action | +|---|---| +| `Ctrl+B h` / `j` / `k` / `l` | Focus pane left / down / up / right | +| `Ctrl+B "` | Split horizontal | +| `Ctrl+B %` | Split vertical | +| `Ctrl+B c` | New tab | +| `Ctrl+B &` | Close tab | +| `Ctrl+B w` | Workspace picker | +| `Ctrl+B g` | Goto (jump menu) | +| `Ctrl+B Shift+O` | Open worktree (jump to an existing worktree-backed workspace) | +| `Ctrl+B Shift+X` | Remove worktree (opens confirmation) | +| `Ctrl+B y` | Enter copy mode | +| `Ctrl+B Alt+1..9` | Jump to agent N (indexed `focus_agent`) | + +Copy mode's internal keys (`v`/`space` select, `y`/`Enter` copy, `q`/`Esc` cancel) aren't configurable. Edit `home/.config/herdr/config.toml` to change any of these — changes apply live via `herdr server reload-config` or the `reload_config` keybinding (default `prefix+shift+r`), no rebuild needed. + +--- + +## Default Keybindings (unconfigured actions) + +Everything below is herdr's out-of-the-box binding for actions this repo hasn't overridden. See `herdr --default-config` for the full annotated list. + +| Key | Action | +|---|---| +| `prefix+?` | Help | +| `prefix+s` | Settings | +| `prefix+q` | Detach | +| `prefix+shift+r` | Reload config | +| `prefix+o` | Open notification target | +| `prefix+shift+n` | New workspace | +| `prefix+shift+g` | New worktree | +| `prefix+shift+w` | Rename workspace | +| `prefix+shift+d` | Close workspace | +| `prefix+shift+t` | Rename tab | +| `prefix+p` / `prefix+n` | Previous / next tab | +| `prefix+1..9` | Switch tab by index | +| `prefix+shift+p` | Rename pane | +| `prefix+e` | Edit scrollback | +| `prefix+tab` / `prefix+shift+tab` | Cycle pane next / previous | +| `prefix+z` | Zoom pane (alias: fullscreen) | +| `prefix+r` | Resize mode | +| `prefix+b` | Toggle sidebar | + +Indexed bindings and navigate-mode movement keys are opt-in — see the commented block in `herdr --default-config`. This repo now sets `focus_agent` (see [Prefix Keybindings](#prefix-keybindings-this-repos-config) above); `switch_workspace` remains unset. + +Indexed bindings only accept a modifier (`alt`/`ctrl`/`shift`/`cmd`) before `1..9` — plain letters like `prefix+w+1..9` are rejected at reload (`invalid keybinding: ...; disabling binding`). + +--- + +## Workspaces + +```bash +herdr workspace list +herdr workspace create [--cwd PATH] [--label TEXT] [--focus] +herdr workspace get +herdr workspace focus +herdr workspace rename