Skip to content

Modernize shell + editor: framework-free zsh, Neovim, idempotent installer#1

Merged
arunraman merged 2 commits into
masterfrom
modern-zsh
Jul 3, 2026
Merged

Modernize shell + editor: framework-free zsh, Neovim, idempotent installer#1
arunraman merged 2 commits into
masterfrom
modern-zsh

Conversation

@arunraman

@arunraman arunraman commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Replaces the Prezto-based setup with a framework-free stack: plain zsh + antidote + powerlevel10k (starship as a one-step swap), Neovim + lazy.nvim, and an idempotent install.sh. All legacy files are kept and mapped in the README — master behavior is not removed, just superseded.

Highlights

  • zsh (.zshrc): antidote (brew copy preferred, git-clone fallback), compinit, fzf-tab with previews, fzf Ctrl-R/Ctrl-T/Alt-C, zoxide, 100k shared/deduped history.
  • exports/aliases: guarded virtualenvwrapper, dropped deprecated GREP_OPTIONS + bash-only history vars; eza-based ls family with plain-ls fallback.
  • Neovim (nvim/): catppuccin, blink.cmp, lspconfig+mason, treesitter, telescope+neo-tree, lualine, gitsigns+fugitive, aerial. Vundle vimrc archived to vim/.vimrc.legacy.
  • install.sh: dry-run by default, --apply to act, backs up to ~/.dotfiles-backup/<ts>/, never touches ~/.zprezto or runs chsh.
  • iTerm2 (iterm2/DynamicProfiles.json): Gargantua/Default recovered from the legacy plist; stale /usr/local/bin/zsh command and typo'd home dir fixed; font → MesloLGS NF.
  • Brewfile: superset of old brew_list.txt + modern toolchain + Nerd Font.
  • CI (.github/workflows/ci.yml): shellcheck, zsh -n, installer dry-run/idempotency, interactive-load smoke test, headless nvim plugin sync.

Testing

Every piece was exercised on an Apple-Silicon Mac, mostly in isolated ZDOTDIR/XDG_CONFIG_HOME sandboxes: zsh loads with zero completion errors, installer is idempotent (0 backups on re-apply), Neovim installs all plugins headlessly and loads catppuccin, shellcheck passes.

Open follow-ups (tracked in README)

  • Full brew bundle end-to-end (tools were installed piecemeal during bring-up)
  • First interactive nvim launch (mason installs pyright/lua_ls)
  • .gitconfig management + delta pager
  • Prune the legacy file table in a later PR

🤖 Generated with Claude Code

Summary by Sourcery

Modernize the dotfiles repo around a framework-free zsh + Neovim setup with an idempotent installer and CI coverage.

New Features:

  • Introduce a framework-free zsh configuration using antidote-managed plugins, powerlevel10k/starship prompts, and enhanced history, navigation, and fzf-based workflows.
  • Add a Neovim configuration powered by lazy.nvim with LSP, Treesitter, Telescope, Neo-tree, Aerial, statusline, git integrations, and editing QoL plugins.
  • Provide an idempotent install.sh script that dry-runs by default, symlinks dotfiles, and safely backs up existing user configuration.
  • Add a Brewfile defining the modern shell and Neovim toolchain plus legacy package set, and a starship prompt configuration for easy prompt switching.
  • Add iTerm2 dynamic profiles and fonts integration to recreate Gargantua/Default profiles with compatible Nerd Fonts.

Enhancements:

  • Rewrite README to document the new zsh/Neovim stack, installer workflow, migration checklist, and legacy file mapping while preserving prior behavior for reference.

CI:

  • Introduce a macOS GitHub Actions workflow that shellchecks install.sh, syntax-checks zsh config, verifies installer idempotency, smoke-tests interactive zsh, and headlessly syncs Neovim plugins.

…aller

Replace the Prezto-based flow with plain zsh + antidote + powerlevel10k
(starship as a documented one-step swap), migrate vim/Vundle to
Neovim + lazy.nvim, and recover the legacy iTerm2 profiles as a Dynamic
Profile. All legacy files are kept and mapped in the README.

- .zshrc: antidote (brew copy preferred), compinit, fzf-tab with
  previews, fzf Ctrl-R/Ctrl-T/Alt-C, zoxide, 100k shared history
- zsh/.zexports: guard virtualenvwrapper, drop GREP_OPTIONS and
  bash-only HISTCONTROL/HISTIGNORE
- zsh/.zalias: eza-based ls family with plain-ls fallback
- nvim/: lazy.nvim, catppuccin, blink.cmp, lspconfig+mason, treesitter,
  telescope+neo-tree, lualine, gitsigns+fugitive, aerial
- install.sh: dry-run by default, idempotent, backs up to
  ~/.dotfiles-backup/<ts>/, never touches ~/.zprezto or chsh
- iterm2/DynamicProfiles.json: Gargantua/Default from the old plist,
  stale /usr/local/bin/zsh command and typo'd home dir removed,
  font -> MesloLGS NF 16
- Brewfile: superset of brew_list.txt + modern toolchain + Nerd Font
- CI: shellcheck, zsh -n, installer dry-run/idempotency, interactive
  load smoke test, headless nvim plugin sync

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Replaces the legacy Prezto-based dotfiles with a framework-free zsh + Neovim stack, wired through an idempotent installer and backed by CI that smoke-tests shell and editor setup, while keeping legacy files in-place but superseded.

Sequence diagram for CI shell and Neovim smoke tests

sequenceDiagram
  participant GitHubActions
  participant install_sh as install.sh
  participant zsh
  participant nvim

  GitHubActions->>install_sh: ./install.sh (dry run)
  GitHubActions->>install_sh: ./install.sh --apply
  GitHubActions->>install_sh: ./install.sh --apply (idempotency check)
  GitHubActions->>zsh: zsh -n .zshrc
  GitHubActions->>zsh: zsh -i -c 'echo LOADED_OK'
  zsh-->>GitHubActions: stderr.log (checked for errors)
  GitHubActions->>nvim: nvim --headless "+Lazy! sync" +qa
  GitHubActions->>nvim: nvim --headless -c 'lua print("colorscheme=" .. vim.g.colors_name)' -c qa
  nvim-->>GitHubActions: colorscheme name
Loading

Flow diagram for install.sh idempotent installer

flowchart LR
  A[Start install.sh] --> B{APPLY flag?}
  B -->|--dry-run| C[Print DRY RUN message]
  B -->|--apply| D[Set APPLY=1]
  C --> E[Iterate LINKS array]
  D --> E
  E --> F[link_one]
  F --> G[backup_if_needed]
  G --> H{APPLY==1?}
  H -->|yes| I[mkdir -p BACKUP_DIR and mv target]
  H -->|no| J[Echo would back up]
  I --> K{APPLY==1?}
  J --> K
  K -->|yes| L[mkdir -p dest dir and ln -s src dest]
  K -->|no| M[Echo would link]
  L --> N{More LINKS?}
  M --> N
  N -->|yes| F
  N -->|no| O[Print Brewfile suggestion]
  O --> P[Print iTerm2 Dynamic Profile info]
  P --> Q[Print shell change notice]
  Q --> R[End]
Loading

File-Level Changes

Change Details Files
Introduce an idempotent installer script that symlinks the new dotfiles layout and backs up existing files.
  • Add Bash-based install.sh that supports dry-run mode by default and an --apply flag to perform changes.
  • Define a centralized LINKS mapping for zsh, Neovim, starship, iTerm2, and font files to their home-directory targets.
  • Implement backup_if_needed and link_one helpers to move pre-existing files into timestamped ~/.dotfiles-backup directories before linking.
  • Ensure installer never touches ~/.zprezto or changes the login shell, and prints brew bundle hints instead of running Homebrew.
install.sh
Replace Prezto with a framework-free zsh configuration driven by antidote and parameterized prompt choice (powerlevel10k vs starship).
  • Add a new .zshrc that sources shared exports/aliases/functions, configures large shared history, and removes bash-only history settings.
  • Bootstrap antidote from a Homebrew install when available, with a git-clone fallback, and load plugins from .zsh_plugins.txt.
  • Initialize zsh completion via compinit and configure fzf integration (Ctrl-R/T, Alt-C) plus fzf-tab-specific zstyles and previews.
  • Wire zoxide initialization when present, and structure prompt configuration so starship is the documented default and powerlevel10k is a toggle via ~/.p10k.zsh and plugin changes.
  • Update zsh/.zalias and zsh/.zexports to add eza-based ls aliases, guarded virtualenvwrapper, removal of deprecated GREP_OPTIONS, and other modern shell tweaks.
  • Add .zsh_plugins.txt describing the plugin set managed by antidote.
.zshrc
zsh/.zalias
zsh/.zexports
.zsh_plugins.txt
Add a modern Neovim configuration using lazy.nvim and a curated plugin set for LSP, completion, navigation, and UI.
  • Introduce nvim/init.lua to load options, keymaps, and lazy.nvim setup from lua/config.
  • Configure core Neovim options (leader, UI settings, indentation, search behavior, undo, etc.) in config.options.
  • Bootstrap lazy.nvim in config.lazy and declare plugin specs via lua/plugins modules.
  • Add plugin definitions for LSP (mason, mason-lspconfig, nvim-lspconfig with blink.cmp capabilities), completion (blink.cmp), treesitter, colorscheme (catppuccin), telescope, neo-tree, aerial, lualine, git integrations (gitsigns, fugitive), and editing QoL (Comment.nvim, nvim-autopairs, vim-better-whitespace).
  • Lock plugin versions with nvim/lazy-lock.json to ensure reproducible installs.
nvim/init.lua
nvim/lua/config/options.lua
nvim/lua/config/keymaps.lua
nvim/lua/config/lazy.lua
nvim/lua/plugins/lsp.lua
nvim/lua/plugins/completion.lua
nvim/lua/plugins/treesitter.lua
nvim/lua/plugins/colorscheme.lua
nvim/lua/plugins/neo-tree.lua
nvim/lua/plugins/aerial.lua
nvim/lua/plugins/editing.lua
nvim/lua/plugins/statusline.lua
nvim/lua/plugins/telescope.lua
nvim/lua/plugins/git.lua
nvim/lazy-lock.json
Define a Brewfile that supersedes the old brew_list.txt and captures both legacy tools and the new shell/Neovim toolchain.
  • Add modern shell-related packages (antidote, starship, eza, fzf, zoxide, bat, git-delta, gh, lazygit).
  • Add Neovim-related packages (neovim, ripgrep, fd, node) plus vim as a fallback editor.
  • Carry forward packages from the previous brew_list/brew_list.txt into the Brewfile.
  • Add a cask for font-meslo-for-powerlevel10k and document that zsh plugins like zsh-completions are managed by antidote, not Homebrew.
Brewfile
Add a Starship prompt configuration that matches the new shell setup and supports an easy swap with powerlevel10k.
  • Create starship.toml with a minimal but informative prompt layout (directory, git, Python, Node.js, command duration, character).
  • Customize formatting and styling for directory, git, Python, Node.js, and command duration to integrate cleanly with the zsh configuration.
  • Align prompt symbols and Nerd Font usage with the Meslo font installed via Brewfile.
starship.toml
Introduce CI to lint the shell installer and smoke-test the zsh and Neovim setups in isolation.
  • Add a GitHub Actions workflow that runs on pushes and PRs to master/modern-zsh.
  • Install and run shellcheck against install.sh.
  • Run zsh -n on .zshrc and zsh helper files to catch syntax errors.
  • Execute install.sh in an isolated HOME, validate idempotency by ensuring a second --apply produces no backups.
  • Spawn an interactive zsh in a sandboxed HOME/ZDOTDIR wired to the repo config and fail on common load-time errors.
  • Install Neovim via Homebrew on CI and run headless plugin sync and colorscheme verification using XDG_* sandbox directories.
.github/workflows/ci.yml
Document the new framework-free setup, migration path, and legacy-file mapping while keeping old behavior available for reference.
  • Rewrite README.md to describe the new zsh + antidote + powerlevel10k/starship stack, Neovim with lazy.nvim, and the idempotent installer.
  • Add a quick-start section for fresh machines, including Homebrew install, repo clone, brew bundle, and installer usage.
  • Document the zsh, prompt swap, Neovim plugin/keymap, and iTerm2 Dynamic Profile behavior in detail.
  • Capture a migration checklist showing what changed from Prezto and which behaviors were fixed or removed.
  • Add a legacy section mapping old files (setup.py, Prezto configs, iTerm plist, vimrc, fonts, bash-era tooling) to their modern replacements and outline follow-up tasks.
README.md
Add iTerm2 dynamic profiles and font files that align with the modern zsh prompt setup while preserving existing user preferences.
  • Create iterm2/DynamicProfiles.json containing Gargantua and Default profiles recovered from the legacy plist, with corrected shell path and home directory.
  • Ensure install.sh links the Dynamic Profile into the user's iTerm2 support directory without overwriting existing prefs.
  • Add Meslo LG font files under fonts/ and wire them into install.sh to place them into ~/Library/Fonts when applying.
iterm2/DynamicProfiles.json
fonts/*
install.sh

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In nvim/lua/plugins/lsp.lua, the mason plugins are referenced as mason-org/... instead of the usual williamboman/mason.nvim and williamboman/mason-lspconfig.nvim, which will prevent lazy.nvim from fetching them; consider correcting the plugin sources.
  • The header comment in .zshrc describes starship as the default prompt, but the file unconditionally sources ~/.p10k.zsh; aligning the comments and actual behavior (or gating p10k with a check) would make the prompt swap flow less confusing.
  • In .zshrc, source ~/.zexports, source ~/.zalias, and source ~/.zfunc will hard-error if those files are missing (e.g., before running install.sh); wrapping these with [[ -f ... ]] && source ... would make the shell config more robust on partial setups.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `nvim/lua/plugins/lsp.lua`, the mason plugins are referenced as `mason-org/...` instead of the usual `williamboman/mason.nvim` and `williamboman/mason-lspconfig.nvim`, which will prevent lazy.nvim from fetching them; consider correcting the plugin sources.
- The header comment in `.zshrc` describes starship as the default prompt, but the file unconditionally sources `~/.p10k.zsh`; aligning the comments and actual behavior (or gating p10k with a check) would make the prompt swap flow less confusing.
- In `.zshrc`, `source ~/.zexports`, `source ~/.zalias`, and `source ~/.zfunc` will hard-error if those files are missing (e.g., before running `install.sh`); wrapping these with `[[ -f ... ]] && source ...` would make the shell config more robust on partial setups.

## Individual Comments

### Comment 1
<location path="nvim/lua/plugins/lsp.lua" line_range="17-19" />
<code_context>
+    "neovim/nvim-lspconfig",
+    dependencies = { "saghen/blink.cmp" },
+    config = function()
+      local capabilities = require("blink.cmp").get_lsp_capabilities()
+      vim.lsp.config("*", { capabilities = capabilities })
+      vim.lsp.enable({ "pyright", "lua_ls" })
+    end,
+  },
</code_context>
<issue_to_address>
**issue (bug_risk):** Using `vim.lsp.config`/`vim.lsp.enable` ties this setup to newer Neovim APIs and may break on current stable releases.

On Neovim 0.10 (current brew stable), these `vim.lsp.config` / `vim.lsp.enable` APIs aren’t available, so this will error at startup and prevent LSP from initializing. To keep this working on more versions, either use the usual `require("lspconfig").pyright.setup{ capabilities = capabilities }` / `lua_ls.setup{ ... }` pattern, or guard the `vim.lsp.*` calls with a `vim.lsp.config` existence check and fall back to `lspconfig` when missing.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread nvim/lua/plugins/lsp.lua
Comment on lines +17 to +19
local capabilities = require("blink.cmp").get_lsp_capabilities()
vim.lsp.config("*", { capabilities = capabilities })
vim.lsp.enable({ "pyright", "lua_ls" })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Using vim.lsp.config/vim.lsp.enable ties this setup to newer Neovim APIs and may break on current stable releases.

On Neovim 0.10 (current brew stable), these vim.lsp.config / vim.lsp.enable APIs aren’t available, so this will error at startup and prevent LSP from initializing. To keep this working on more versions, either use the usual require("lspconfig").pyright.setup{ capabilities = capabilities } / lua_ls.setup{ ... } pattern, or guard the vim.lsp.* calls with a vim.lsp.config existence check and fall back to lspconfig when missing.

Restructure from a PR-style done/open checklist into a reference organized
around what → install → daily use → customize → troubleshoot → layout:

- top-level tool table + safe-by-default install flow
- daily-use cheat sheets (shell keybindings/aliases, nvim leader maps)
- "want to X → edit this file" customization table
- troubleshooting for the issues hit during bring-up (compinit/fzf Tab,
  font tofu, stale iTerm shell path, undo)
- plain repo layout + trimmed legacy table

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arunraman
arunraman merged commit 6dc67a2 into master Jul 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant