Newer eza (clap) treats --hyperlink as taking an optional value, so the oh-my-zsh plugin's bare --hyperlink eats the next path arg (la / -> invalid value '/'). The previous fix glued --hyperlink=always to avoid that. But Debian ships an older eza where --hyperlink is a pure boolean that rejects a value, so --hyperlink=always errors with 'Flag --hyperlink cannot take a value'. Detect the installed eza's behavior via 'eza --help | grep <WHEN>': - newer eza: use --hyperlink=always (glued, avoids path-eating) - older eza: use bare --hyperlink (boolean, doesn't eat tokens so the original bug doesn't apply) Apply the chosen form to every eza alias. Both paths keep hyperlinks on and paths working.
7.8 KiB
Zsh Config
A reproducible, self-configuring Zsh setup managed from a remote git repo. The zshrc auto-updates itself and the Starship prompt config on every interactive shell start, and a versioned bootstrap script installs all missing dependencies across distros. Drop ~/.zshrc in place once and every machine stays in sync automatically.
Design
- Reproducible — one
zshrcdrives an identical environment across every machine and distro. - Self-configuring — tool integrations are guarded by
command -v, so the shell works degraded-but-fine when a tool is absent, and lights up automatically once the bootstrap installs it. - Self-updating — on each interactive shell start,
zshrcandstarship.tomlare re-pulled from the repo and applied if changed (downloaded files are validated withzsh -nbefore replacing anything, so a 502 error page or corrupted content can't break the shell). - Network-resilient — all remote calls use
--fail+--connect-timeout/--max-time, so an unreachable server silently no-ops instead of hanging the shell.
Files
| File | Description |
|---|---|
zshrc |
Main config. Path setup, history options, oh-my-zsh + plugins, eza theme, tool integrations, aliases, and the auto-update logic. Sources ~/.zshrc.local at the end for per-machine overrides. |
zshrc-bootstrap.zsh |
One-shot setup script run by zshrc when the bootstrap version changes. Installs all dependencies across distros and clones oh-my-zsh + custom plugins. |
starship.toml |
Starship prompt config — two-line prompt with directory, git status, command duration, Nerd Font symbols, and an error indicator. Synced to ~/.config/starship.toml by the auto-update logic. |
tmux.conf |
Tmux config with GitHub Dark theming, Vim-style pane navigation (h/j/k/l), TPM plugin manager, Nerd Font auto-install, and a built-in cheatsheet (prefix + ?). Installed to ~/.config/tmux/tmux.conf on first shell start. |
Getting Started
Point ~/.zshrc at the remote zshrc:
curl -fsSL https://git.jeremymcclure.com/jeremy/scripts/raw/branch/master/zsh/zshrc -o ~/.zshrc && exec zsh
On first start, zshrc bootstraps missing dependencies (oh-my-zsh, plugins, and all CLI tools below) over the next shell starts. To force a re-bootstrap (e.g., after adding new tool installs to the bootstrap script), the bootstrap version is bumped in zshrc and every machine re-runs it automatically — or run manually:
BOOTSTRAP=true exec zsh
Dependencies
All installed automatically by the bootstrap across brew / apt / dnf / pacman / cargo:
| Tool | Purpose |
|---|---|
| starship | Prompt (configured via starship.toml) |
| fzf | Fuzzy finder — powers fzf-tab completion and zi |
| eza | ls replacement with icons, git status, hyperlinks |
| bat | cat replacement + colored man pages |
| zoxide | Frecency directory jumping (z, zi) |
| git-delta | Pretty git diff/log/show pager |
| fastfetch | System info on shell start |
| lazydocker | TUI for Docker |
| rsync / tmux / git | Core utilities |
Debian/Ubuntu renames handled: batcat→bat, fdfind→fd (symlinked into ~/.local/bin).
Oh-My-Zsh Plugins
git, sudo, extract, eza, history, kitty, docker, docker-compose, archlinux, encode64, universalarchive, zsh-autosuggestions, fast-syntax-highlighting, fzf, fzf-tab, systemd, vscode, rsync, starship.
Tool Integrations
Each is enabled only when the binary is present (command -v):
- zoxide —
z <substring>jumps to frecency-ranked dirs;ziopens the fzf picker.cdstill works. - bat —
alias cat='bat',BAT_THEME=Monokai Extended, andMANPAGERset somanpages are colored and paginated by bat. - delta —
GIT_PAGER=deltasogit diff/log/showrender side-by-side with syntax highlighting. (Not aliased todiff— delta is a pager reading diff input on stdin, not adiff a breplacement.)
History & Shell Options
SHARE_HISTORY, HIST_IGNORE_DUPS, HIST_IGNORE_ALL_DUPS, HIST_REDUCE_BLANKS, HIST_FCNTL_LOCK, HIST_VERIFY, EXTENDED_HISTORY, AUTO_CD, AUTO_LIST, INTERACTIVE_COMMENTS, AUTO_PUSHD, PUSHD_IGNORE_DUPS, PUSHD_SILENT.
AUTO_PUSHD maintains an automatic directory stack, so cd -<TAB> and dirs let you navigate recent locations without pushd/popd muscle memory.
Aliases
| Alias | Action |
|---|---|
c |
clear |
q |
exit |
open-ports |
ss -tulpn | grep LISTEN |
nbstat |
Netbird peer status as a TSV table |
yeet |
yay -Rcs (remove + deps + config on Arch) |
Keybindings
| Shortcut | Action |
|---|---|
Ctrl+R |
fzf history search (via fzf plugin) |
Ctrl+T |
fzf file finder |
Alt+C |
fzf cd |
Tab |
fzf-tab completion menu |
Esc twice |
Toggle sudo prefix (via sudo plugin) |
Eza Hyperlinks — Implementation Note
zshrc does not set the oh-my-zsh eza plugin's hyperlink zstyle (the plugin's bare --hyperlink causes issues). Instead, after oh-my-zsh loads, the aliases are rewritten to append the correct hyperlink flag for the installed eza version:
- Newer eza (help shows
--hyperlink [<WHEN>]): the oh-my-zsh plugin's bare--hyperlinkis treated by clap as taking the next token as its optional value, sola /fails withinvalid value '/'. We append the glued--hyperlink=alwaysform, which can't eat a following path argument. - Older eza (e.g. Debian's, where
--hyperlinkis a pure boolean):--hyperlink=alwaysis rejected withFlag --hyperlink cannot take a value. We detect this viaeza --helpand fall back to the bare--hyperlink, which is safe here because boolean flags don't consume the next token (the path-eating bug doesn't apply).
Detection runs once at shell start via eza --help | grep '<WHEN>'; the right form is applied to every eza alias. Hyperlinks stay on and paths keep working across eza versions.
Auto-Update Behavior
On every interactive shell start:
- zshrc — re-downloaded, validated with
zsh -n, and applied viaexec zshonly if it differs from~/.zshrc. - starship.toml — re-downloaded and moved to
~/.config/starship.tomlif changed (applied live on the next prompt render; no shell reload needed). - tmux.conf — downloaded once on first shell start if
~/.config/tmux/tmux.confand~/.config/byobu/.tmux.confare both absent. - bootstrap — runs (
zshrc-bootstrap.zsh) whenZSHRC_BOOTSTRAP_VERSIONinzshrcdoesn't match~/.config/zsh/.bootstrapped.
All downloads use --fail so a 502/HTML error page is never written over a working config, and --connect-timeout/--max-time so an unreachable server never hangs startup.
Per-Machine Overrides
~/.zshrc.local is sourced at the very end of zshrc (created empty if missing). Put machine-specific aliases, env vars, or PATH additions there — they survive repo updates since zshrc doesn't manage that file.
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
ZSHRC_GIT |
.../scripts/raw/branch/master/zsh/ |
Base URL for all remote config files |
ZSHRC_BOOTSTRAP_VERSION |
4 |
Bump to force a re-bootstrap on all machines |
FFENABLED |
(unset → enabled) | Set to false to disable the fastfetch system info on shell start |
BAT_THEME |
Monokai Extended |
Override before the bat block to use a different bat theme |
GIT_PAGER |
delta (when installed) |
Override to use a different git pager |
Helper Functions
update_zshrc # Manually re-pull and reload the zshrc
fix_btopbg # Disable btop theme_background (workaround for transparency)
install_opencode # Install the opencode CLI
BOOTSTRAP=true exec zsh # Force a re-bootstrap