Customization#
Make the shell yours: prompts, themes, completions, dotfile management.
Prompts#
Modern prompts are usually managed by a cross-shell tool rather
than hand-coded. The tools below all handle async git status,
language version pickers, command duration, and exit codes without
slowing the prompt down, the kind of thing a hand-rolled PS1
struggles with.
Starship, the default in 2026; one binary, one
starship.toml, works in Bash / Zsh / Fish / PowerShell / Nu / Cmd / Tcsh.Powerlevel10k, Zsh only; extremely fast; configurable wizard on first run.
Oh My Posh, cross-shell, theme-driven, popular on Windows.
pure, minimal Zsh prompt.
Why a tool over hand-rolling: async git status, language-version indicators, command duration, exit code, jobs, all without slowing the prompt to a crawl.
A minimal Starship config:
# ~/.config/starship.toml
format = "$directory$git_branch$git_status$character"
add_newline = false
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✗](bold red)"
Fonts#
Many prompts use icons (git branch glyph, OS logo, language version markers) that the default monospace fonts do not contain. A Nerd-Font-patched terminal font fills those glyph slots so the prompt renders correctly across every shell and host you set up:
Nerd Fonts, patched fonts with programming ligatures and icon glyphs.
Common picks: FiraCode Nerd Font, JetBrainsMono Nerd Font, Hack Nerd Font, Iosevka.
Theming Terminals#
The terminal emulator’s color scheme matters as much as the shell’s – many “shell themes” are really terminal themes plus a matching prompt. Most modern terminals support theme files in a common format and converge on the same dozen popular schemes:
Plugins#
Each shell has its own plugin culture, with frameworks for the beginner-friendly path and lighter managers for users who want to keep the config tight. The picks below are the names that come up most in 2026:
Bash:
bash-it, framework with themes and aliases.
bash-completion, the baseline.
Zsh:
Top plugins:
zsh-autosuggestions,zsh-syntax-highlighting,zsh-history-substring-search,zsh-completions,fzf-tab.
Fish:
Plugin managers: Fisher, Oh My Fish.
Top plugins:
z(jump to recent dirs),done(notify on long commands),puffer(text expansion).
Nu and PowerShell have plugin / module systems but smaller ecosystems.
Universal Tools#
These work in any shell and are usually the highest-impact upgrades you can make. Most of them are Rust- or Go-binary replacements for the classic Unix tools, with sensible colored output, faster execution, and ergonomic flag defaults:
fzf, fuzzy finder. Once installed, the default keybinds are:
Keybind
Effect
Ctrl-RFuzzy search shell history.
Ctrl-TFuzzy search files under the working directory; insert the pick on the prompt.
Alt-CFuzzy search directories and
cdinto the pick.zoxide, smarter
cd;z foojumps to the most-frecent directory matching “foo”.eza, a modern
lswith colors and Git integration.bat,
catwith syntax highlighting.ripgrep (
rg), much fastergrep.fd, friendlier
find.delta, prettier
git diff.direnv, per-directory environment variables.
Most of these install in seconds and pay back many times.
Completion Sources#
Most CLI tools ship completion scripts that you generate from the
tool itself and source from the shell’s completion directory.
carapace-bin generates completions for hundreds of tools from
a single source, which is the cleanest path if you want consistent
completion across many shells:
$ kubectl completion bash > ~/.bash_completion.d/kubectl
$ gh completion -s zsh > ~/.zfunc/_gh
$ docker completion fish | source
Tools like carapace-bin provide completions across many shells from
one source.
Dotfiles#
Manage shell config (and the rest of the user environment) in a Git repo so it travels with you. The tools below all do the same job, get a fresh laptop into your preferred configuration, but differ on templating, secrets handling, and how much they hide the underlying Git operations:
Plain Git + symlinks,
ln -s ~/dotfiles/.zshrc ~/.zshrc.chezmoi, declarative, supports templating per host / OS / user; the popular choice in 2026.
yadm, yadm = “yet another dotfiles manager”; Git wrapper that uses
$HOMEas the work tree.dotbot, YAML-driven installer.
GNU Stow, the classic symlink farm manager.
Common patterns:
Per-machine
~/.local.zshrcsourced from the main file.Templated values for hostnames, work-vs-personal differences.
Encrypted secrets via age / GPG / SOPS.
Bootstrap script that sets up everything fresh.
History Across Machines#
Standard shell history lives in one file on one machine. The tools
below replace Ctrl-R with a sync layer that follows you between
hosts, useful for operators who switch between laptop, jump host,
and a couple of long-running VMs throughout a day.
Atuin, self-hosted, end-to-end encrypted shell history sync; replaces
Ctrl-R.mcfly, neural-network ranked history search.
Not for everyone, but life-changing if you switch between machines a lot.
Performance#
A slow-starting shell is paid for on every new terminal, every
ssh, every script -c, every container exec. The fixes
below are the standard ones, profile to find the offenders, then
defer or remove the slowest plugins and language-version managers:
Profile, Bash:
PS4='+$EPOCHREALTIME ' bash -lixc exit; Zsh:zmodload zsh/zprofthenzprof; Fish has built-in startup profiling.Lazy load completions and language-version managers (nvm, rbenv).
Pin slow plugins behind
asyncloaders or remove them.Smaller prompt, prompt managers are usually the slowest single thing, but they’re tunable.
Aim for sub-100ms shell startup; sub-50ms is achievable with care.
Aliases vs. Functions vs. Scripts#
A useful hierarchy for “where does this code go?” Each tier hides its predecessor from view, once a function exists, you reach for the function name, not the underlying commands; once a script exists, you stop maintaining the function form. The complexity of the task picks the tier:
Alias, one-liner shorthand.
alias gs='git status'.Function, multi-line logic, takes arguments.
Script, complex enough to deserve its own file in
$PATHand source control.
When a function grows past ~30 lines, promote it to a script with proper argument parsing.