Personal macOS development environment. Homebrew owns binaries; this repo owns config files through direct symlinks.
This repo has three responsibilities:
- Install binaries with Homebrew via
Brewfile. - Keep app and CLI config in repo-owned source files.
- Link those source files into macOS config locations.
For a new machine:
cd ~/ghq/github.com/nwiizo/dotfiles
./scripts/bootstrap.shFor an existing machine, edit the source and reload the owning app. Run rtk proxy ./scripts/link.sh only when installation paths change, and run the Fish plugin installer or Homebrew bundle only when that layer changes.
Read this file for the overall model. Use the subdirectory docs when changing a specific tool:
| Area | Start here | Edit mostly |
|---|---|---|
| Packages | Brewfile |
Brewfile |
| Linking/bootstrap | scripts/link.sh, scripts/bootstrap.sh |
scripts/ |
| Fish | fish/README.md |
fish/config.fish, fish/functions/, fish/fish_plugins |
| Neovim | nvim/README.md |
nvim/lua/config/, nvim/lua/plugins/ |
| Ghostty | ghostty/README.md |
ghostty/config |
| Git / GitHub CLI | git/README.md |
git/config, git/power_pull.sh, gh/config.yml |
| Small CLI configs | this README | bat/, atuin/, tealdeer/ |
| Agent config | .agents/README.md |
reusable agents, rules, docs, and skills |
| Claude Code entrypoints | .claude/README.md |
symlinks into .agents/ |
| Codex entrypoints | .codex/README.md |
symlinks into .agents/codex/ |
| Releases | releases/ |
versioned release notes |
Contributor and agent-facing repository rules are in AGENTS.md. CLAUDE.md imports the same guide so Claude Code and Codex share the base rules. Global preferences describe how to work; this repository's guide describes where to edit and how to verify the result. Conditional procedures live in skills; see the agent config guide.
| Layer | Owner | Files |
|---|---|---|
| Packages | Homebrew | Brewfile |
| Shell | Fish + Fisher | fish/config.fish, fish/functions/, fish/fish_plugins |
| Editor | Neovim + LazyVim | nvim/ |
| Terminal | Ghostty | ghostty/config |
| GitHub / Git | gh, git-delta, lazygit | gh/config.yml, git/config, git/power_pull.sh |
| CLI config | bat, atuin, tealdeer | bat/config, atuin/config.toml, tealdeer/config.toml |
| Linking / bootstrap | Shell scripts | scripts/bootstrap.sh, scripts/link.sh |
| Agent config | Claude Code, Codex, Agents | .agents/, .claude/, .codex/ |
dotfiles/
βββ Brewfile # Homebrew formulae and casks
βββ scripts/
β βββ bootstrap.sh # brew bundle + symlink + fish plugin install
β βββ link.sh # symlink repo config into target locations
β βββ install-fish-plugins.fish
βββ fish/ # Fish init, functions, plugins, conf.d patch
βββ nvim/ # LazyVim based Neovim config
βββ ghostty/ # Ghostty terminal config
βββ git/ # Git config and helper scripts
βββ gh/ # GitHub CLI config
βββ .agents/ # Source for reusable agents, rules, docs, and skills
βββ .claude/ # Claude Code project entrypoint symlinks
βββ .codex/ # Codex project custom-agent symlinks
βββ bat/ # bat config
βββ atuin/ # atuin config
βββ tealdeer/ # tealdeer config
βββ releases/ # versioned release notes
βββ archive/ # retired configs, reference only
Bootstrap a new machine after installing Homebrew:
cd ~/ghq/github.com/nwiizo/dotfiles
./scripts/bootstrap.shThe bootstrap script runs:
brew bundle --file Brewfile
./scripts/link.sh
fish scripts/install-fish-plugins.fishRun individual steps when you only need one layer:
brew bundle --file Brewfile
./scripts/link.sh
fish scripts/install-fish-plugins.fishscripts/link.sh leaves already-correct links untouched and backs up any conflicting path, including an unrelated symlink, under ~/.dotfiles-link-backups/pre-dotfiles-link-* before linking.
| Repo path | Target path |
|---|---|
fish/config.fish |
~/.config/fish/config.fish |
fish/conf.d/*.fish |
~/.config/fish/conf.d/*.fish |
fish/functions/*.fish |
~/.config/fish/functions/*.fish |
nvim/ |
~/.config/nvim |
ghostty/config |
~/.config/ghostty/config |
ghostty/claude-notification.sh |
~/.local/bin/ghostty-claude-notification |
bat/config |
~/.config/bat/config |
atuin/config.toml |
~/.config/atuin/config.toml |
tealdeer/config.toml |
~/.config/tealdeer/config.toml |
git/config |
~/.config/git/config |
gh/config.yml |
~/.config/gh/config.yml |
git/power_pull.sh |
~/.local/bin/power_pull |
| Homebrew Docker Compose plugin | ~/.docker/cli-plugins/docker-compose |
scripts/audit-agent-config.sh |
Local validation helper |
scripts/apply-ghostty-ai-notifications.sh |
Merge Ghostty notification settings into Claude Code and Codex |
.agents/CLAUDE.md |
~/.claude/CLAUDE.md |
.agents/RTK.md |
~/.claude/RTK.md, ~/.codex/RTK.md |
.agents/claudeignore |
~/.claude/.claudeignore |
.agents/agents/ |
~/.claude/agents |
.agents/docs/ |
~/.claude/docs |
.agents/rules/ |
~/.claude/rules |
.agents/skills/* |
~/.claude/skills/*, ~/.agents/skills/* |
.agents/codex/AGENTS.md |
~/.codex/AGENTS.md |
.agents/codex/agents/*.toml |
~/.codex/agents/*.toml |
.claude/agents, .claude/rules, .claude/skills |
project symlinks into .agents/ |
.codex/agents |
project symlink into .agents/codex/agents |
~/.agents is reserved for cross-client assets. This repository currently publishes only Agent Skills there; Claude Code and Codex subagents, rules, and tool-specific documentation stay in their product-specific home directories.
Most edits happen in the repo, then the owning app or shell is restarted.
| Change | Apply |
|---|---|
| Existing Fish config or function | Open a new shell, or run exec fish |
Add/remove fish/functions/*.fish |
Run ./scripts/link.sh |
| Fish plugins | Edit fish/fish_plugins, then run fish scripts/install-fish-plugins.fish |
| Neovim config | Restart Neovim |
| Ghostty, Git, gh, bat, atuin, tealdeer config | Restart the app or open a new shell |
| Homebrew packages | Edit Brewfile, then run brew bundle --file Brewfile |
| Agent assets | Edit .agents/, .claude/, .codex/, then run ./scripts/link.sh and ./scripts/audit-agent-config.sh |
The update_all Fish function updates common tools sequentially by default and streams updater output so confirmation prompts are visible. Use --parallel or --non-interactive when prompts should be disabled. Mac App Store updates are skipped by default.
update_all
update_all --parallel
update_all --non-interactive
update_all --no-brew
update_all --no-rust
update_all --no-nvim
update_all --with-mas
update_all --help| You want to change ... | Edit | Apply |
|---|---|---|
| Shell env, PATH, abbreviations, fzf defaults | fish/config.fish |
new shell or exec fish |
| Fish helper command | fish/functions/*.fish |
./scripts/link.sh if adding/removing files |
| Fisher plugins | fish/fish_plugins |
fish scripts/install-fish-plugins.fish |
| Neovim plugin or keymap | nvim/lua/... |
restart Neovim |
| Ghostty / AI notifications | ghostty/, scripts/apply-ghostty-ai-notifications.sh |
./scripts/link.sh, then reload Ghostty |
| Git / gh | git/config, gh/config.yml |
new shell or next command invocation |
| Homebrew package | Brewfile |
brew bundle --file Brewfile |
| Shared agent config | .agents/, .claude/, .codex/ |
./scripts/link.sh |
fish/config.fish defines XDG paths, Homebrew paths, language tool paths, environment variables, abbreviations, fzf defaults, and integrations for zoxide, mise, carapace, atuin, and direnv.
Notable bindings:
| Key | Action |
|---|---|
Ctrl+G |
Select a ghq repository |
Alt+J |
Select a Git/ghq repository |
Ctrl+B |
Select a Git branch |
Ctrl+F |
fzf directory search |
Ctrl+L |
Clear screen |
Tab |
History completion on empty command line |
Common abbreviations:
g=git gst='git status' gaa='git add --all'
gc='git commit -v' gcm='git commit -m'
gp='git push' gpl='git pull'
d=docker dc='docker compose' k=kubectl
cat=bat grep=rg ls='eza --icons --group-directories-first'
find=fd du=dust
sed=sd ps=procs top=btm ping=gping
http=xh hex=hexyl bench=hyperfine
c='claude --dangerously-skip-permissions' cc=claude
cbare='claude --bare' csafe='claude --safe-mode'
cdoc='claude doctor' cagents='claude agents'
cx='codex --dangerously-bypass-approvals-and-sandbox'
cxs='codex --sandbox workspace-write --ask-for-approval on-request'
cxro='codex --sandbox read-only' cxe='codex exec'
cxr='codex resume' cxrev='codex review --uncommitted'
v=nvim lg=lazygit repo=git_fzf_ghq
gwl='git worktree list' gwa='git worktree add'
actx=ai_context actxc='ai_context | pbcopy'c and cx intentionally start unrestricted sessions. Use cl for normal Claude Code permissions, or cxs / cxro for constrained Codex sessions.
See fish/README.md for configuration and workflow details.
nvim/ is a LazyVim based configuration for Rust, Go, TypeScript, Python, Terraform, Lua, Bash, Zig, HTML/CSS, and AI-assisted coding.
Configuration layout:
nvim/lua/config/: LazyVim bootstrap, options, keymaps, autocmdsnvim/lua/plugins/: feature-grouped plugin specs- UI: catppuccin mocha, no statusline,
incline.nvim,noice.nvim,snacks.nvim,oil.nvim,overlook.nvim - Completion:
blink.cmp - AI: CopilotChat, Avante, Signalbox, Codex, Claude Code
- Search: Snacks, fff
- Git: gitsigns, CodeDiff, Diffview, LazyGit, Snacks gitbrowse
- Rust: rustaceanvim, crates.nvim, neotest, DAP
See nvim/README.md for plugin layout, LazyVim Extras, and keymaps.
Ghostty is the primary terminal config in ghostty/config.
- Hack Nerd Font Mono, 24pt
- Catppuccin Mocha palette
- Fish shell integration
- Vim-style pane navigation with
Ctrl+H/J/K/L - AI-friendly scrollback and screen dump bindings
- Split zoom, split equalization, and resize-mode bindings
Warp settings are preserved in archive/warp/. Bootstrap no longer installs Warp; link.sh removes the former repo-managed links without deleting the app or local settings.
Run the checks that match the files you changed.
./scripts/link.sh
fish scripts/install-fish-plugins.fish
brew bundle check --file Brewfile
./scripts/audit-agent-config.shFor AI-history-derived changes, start with a bounded local aggregate from the installed Rust nippo CLI. Follow home-history-distill for redaction and evidence review; do not commit raw logs.
rtk proxy nippo collect --days 7 --stats-onlyfish -n fish/config.fish
for f in fish/functions/*.fish; do fish -n "$f" || exit 1; donestylua --check nvim/lua
nvim --headless '+lua print("nvim-config-ok")' +qartk proxy nvim --headless '+lua require("lazy").load({ plugins = { "CopilotChat.nvim", "avante.nvim", "signalbox.nvim", "codex.nvim", "claudecode.nvim" } }); print("ai-plugins-loaded")' +qaLoading plugins checks their setup, not provider authentication or live AI requests.
These files are intentionally not tracked:
~/.config/fish/fish_variables~/.config/fish/local.fish- shell history and Atuin databases
- Warp
settings.toml - tool caches, runtime state, and secrets
exec fish
fish --profile-startup /tmp/fish.prof -c exit
nvim --startuptime /tmp/nvim.logInside Neovim:
:Lazy restore
:Mason
:checkhealth
:LspInfo