Terminal Productivity skill for Claude Code

A fast shell where everything is a few keys away. Claude measures shell startup before changing anything, profiles slow plugins, and builds a lean setup: shared deduplicated history, fzf pickers for files, history and branches, zoxide jumps, tmux sessions that survive disconnects, and a minimal starship prompt. Aliases come from your most-repeated commands, and secrets stay out of rc files and history.

  • nameterminal-productivity
  • size212 lines · ≈2,150 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Tunes a developer's terminal workflow — zsh or bash configuration, history settings, aliases versus functions, fzf fuzzy finding for files, history, and git, zoxide for directory jumping, tmux sessions, windows, and persistent layouts, a fast prompt with starship, direnv for per-project environments, modern CLI tools like ripgrep, fd, bat, and eza, and shell startup time profiling. Use when setting up or speeding up a shell, writing a .zshrc or .tmux.conf, adding fzf or zoxide, creating useful aliases and functions, or making the terminal faster to navigate.

Try asking

  • My zsh takes 1.5 seconds to start, profile it and make it fast
  • Set up fzf and zoxide with previews and a git branch picker
  • Write me a sensible .tmux.conf with session restore and a project switcher

Use it when

  • Setting up a new shell or terminal environment
  • Shell startup is slow
  • You want fuzzy search for files, history and branches
  • You work across many projects or remote hosts with tmux

Skip it when

How to check the result

Startup time drops to roughly 200 ms or below across five runs, Ctrl-R, Ctrl-T and z work in a new shell, and history typed in one pane is searchable in another.

The common mistake it prevents

Installing a plugin framework with dozens of plugins and nvm hooks, which adds a second or more to every new shell.

~/.claude/skills/terminal-productivity/SKILL.md

--- name: terminal-productivity description: Tunes a developer's terminal workflow — zsh or bash configuration, history settings, aliases versus functions, fzf fuzzy finding for files,… license: MIT ---

Done well means: the shell starts in under ~200 ms, history is shared and searchable, any file, directory, branch, or past command is a few keystrokes away, long-running work lives in named tmux sessions that survive disconnects, and every customization is in version-controlled dotfiles with a comment explaining it.

Hard rules

  • Measure before and after. Optimizations that are not measured tend to make startup slower.
  • Do not alias over standard commands with different semantics in ways that break scripts or muscle memory on other machines (alias rm='rm -i' trains habits that fail elsewhere). Aliases are for interactive shells only; scripts never rely on them.
  • Never put secrets in shell rc files or history. Use a password manager CLI, direnv with an untracked .envrc, or the OS keychain; set HISTORY_IGNORE/HISTIGNORE or prefix commands with a space (with HIST_IGNORE_SPACE) when passing a secret inline.
  • Install tools through the system package manager (Homebrew, apt, dnf) so they update; avoid curl | sh installers without checking the script.
  • Change one thing at a time in rc files, and keep a working shell open while editing in case a typo breaks login.

Workflow

- [ ] 1. Baseline: startup time, current plugins, pain points (what do you type most?)
- [ ] 2. History: size, sharing, dedupe, search
- [ ] 3. Navigation: zoxide + fzf
- [ ] 4. Aliases and functions for top repeated commands
- [ ] 5. tmux for sessions (if working on remote hosts or many projects)
- [ ] 6. Prompt: fast, shows git branch, exit status, duration
- [ ] 7. Re-measure startup; commit to dotfiles

1. Baseline

for i in 1 2 3 4 5; do /usr/bin/time zsh -i -c exit; done     # target < 0.2 s
# find what is slow: add to the TOP of ~/.zshrc temporarily
zmodload zsh/zprof     # ...and `zprof` at the very bottom
history | awk '{ $1=""; print $0 }' | sort | uniq -c | sort -rn | head -30   # most repeated commands (bash; zsh: fc -l 1)

Common slow spots: nvm initialization (use lazy loading, or fnm/mise), compinit running on every start (cache it), heavy frameworks with dozens of plugins, brew --prefix or pyenv init subshells. Prefer mise for language versions: one fast hook instead of several.

2. History (zsh)

HISTFILE=~/.zsh_history
HISTSIZE=100000
SAVEHIST=100000
setopt SHARE_HISTORY          # share across sessions (implies incremental append)
setopt HIST_IGNORE_ALL_DUPS   # drop older duplicates
setopt HIST_IGNORE_SPACE      # leading space = not saved
setopt HIST_REDUCE_BLANKS
setopt EXTENDED_HISTORY       # timestamps

bash equivalent: HISTSIZE=100000; HISTFILESIZE=100000; HISTCONTROL=ignoreboth:erasedups; shopt -s histappend; PROMPT_COMMAND="history -a; ${PROMPT_COMMAND:-}".

Optional: atuin stores history in SQLite with context (directory, exit code, duration) and optional encrypted sync; replaces Ctrl-R.

3. Navigation: fzf and zoxide

# ~/.zshrc
source <(fzf --zsh)            # fzf 0.48+: Ctrl-T files, Ctrl-R history, Alt-C cd
eval "$(zoxide init zsh)"      # z <partial>, zi for interactive picker

export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_ALT_C_COMMAND='fd --type d --hidden --exclude .git'
export FZF_CTRL_T_OPTS="--preview 'bat --color=always --line-range :200 {}'"
export FZF_DEFAULT_OPTS='--height 40% --layout reverse --border'

bash: eval "$(fzf --bash)" and eval "$(zoxide init bash)". Put zoxide init near the end of the rc file (after other prompt hooks).

Useful fzf functions:

# switch git branch (local + remote) with preview of recent commits
fbr() {
  local b
  b=$(git branch --all --sort=-committerdate --format='%(refname:short)' | grep -v HEAD |
      fzf --preview 'git log --oneline --color=always -20 {}') || return
  git switch "${b#origin/}"
}
# open a file found by content in the editor at the matching line
fif() {
  local hit
  hit=$(rg --line-number --no-heading --color=never "${1:?usage: fif pattern}" |
        fzf --delimiter : --preview 'bat --color=always --highlight-line {2} {1}') || return
  ${EDITOR:-vim} "+${hit#*:}" "${hit%%:*}"     # note: +line works for vim/nvim; VS Code uses -g file:line
}
# kill a process interactively
fkill() { ps -ef | sed 1d | fzf -m | awk '{print $2}' | xargs -r kill -"${1:-15}"; }

xargs -r skips the command when nothing was selected (GNU and the BSD xargs on macOS both accept it).

4. Aliases vs. functions

  • Alias: a fixed text substitution with no arguments in the middle (alias gs='git status -sb').
  • Function: anything with arguments, logic, or pipes (mkcd() { mkdir -p -- "$1" && cd -- "$1"; }).
  • Git-specific shortcuts belong in ~/.gitconfig [alias] so they work in every shell.
  • Keep a small, memorable set derived from the history analysis, not a 300-alias plugin.
alias ll='eza -l --git --group-directories-first'   # falls back: alias ll='ls -lah'
alias cat='bat --paging=never'                      # interactive only; scripts call /bin/cat
alias ..='cd ..'
alias k='kubectl'
alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'

Modern tool set (all in Homebrew/apt): ripgrep (rg), fd, bat, eza, git-delta (pager for git diffs), jq/yq, btop, tldr, direnv.

5. tmux

# ~/.tmux.conf
set -g prefix C-a
unbind C-b
bind C-a send-prefix
set -g mouse on
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
set -g history-limit 50000
set -sg escape-time 10              # no lag on Esc in vim
set -g default-terminal "tmux-256color"
set -as terminal-features ",xterm-256color:RGB"
setw -g mode-keys vi
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind r source-file ~/.tmux.conf \; display "reloaded"
# plugins via TPM (git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm)
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'     # save/restore layouts: prefix C-s / C-r
set -g @plugin 'tmux-plugins/tmux-continuum'     # automatic saves
run '~/.tmux/plugins/tpm/tpm'

Session habits:

tmux new -A -s api            # attach if exists, else create
tmux ls; tmux switch -t web   # or prefix s for a picker
# project session picker
tp() { local d; d=$(zoxide query -l | fzf) || return; local n=${d:t}; n=${n//./_}
       tmux new -A -d -s "$n" -c "$d"; [ -n "$TMUX" ] && tmux switch -t "$n" || tmux attach -t "$n"; }

${d:t} is zsh syntax (basename); in bash use n=$(basename "$d"). On remote hosts, always work inside tmux so a dropped SSH connection does not kill jobs.

6. Prompt

starship (eval "$(starship init zsh)") is fast and cross-shell. Keep modules minimal: directory, git branch/status, language version only when relevant, command duration over 2 s, and exit status. Disable modules that shell out slowly in large repos (git_status can be slow in huge monorepos; set [git_status] disabled = true or use the scan timeout).

direnv

eval "$(direnv hook zsh)"
# in a project: .envrc
#   use mise          (or: layout python, source_up, dotenv)
#   export DATABASE_URL=postgres://localhost/app_dev
direnv allow

Add .envrc to .gitignore if it holds secrets; commit an .envrc.example.

Verification

  • Startup time measured before and after, under ~200 ms (or explain what remains).
  • New shell: Ctrl-R fuzzy history, Ctrl-T file picker with preview, z jumps work.
  • History is shared: a command run in one pane is searchable in another.
  • tmux kill-server; tmux then prefix C-r restores the saved layout (if resurrect is used).
  • shellcheck passes on any shell functions moved into standalone scripts.

Gotchas

  • Order matters in .zshrc: PATH setup first, then completion (compinit), then plugins, then prompt and zoxide.
  • .zshrc runs for interactive shells, .zprofile/.zshenv for login/all shells; put PATH in .zprofile (macOS Terminal opens login shells) or .zshenv, and keep .zshenv minimal because scripts load it too.
  • Aliases do not expand in scripts or after sudo (use alias sudo='sudo ' to enable expansion of the following word, if you must).
  • Ctrl-A as tmux prefix conflicts with beginning-of-line in emacs mode; press it twice or pick another prefix.
  • Heavy plugin frameworks cost hundreds of milliseconds; a plain rc file with a few sourced tools is usually faster.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc