edmundmiller/dotfiles/zbench

Claude Code and agent skill by edmundmiller/dotfiles

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Measures interactive zsh latency with zsh-bench. Use for slow-shell diagnosis, performance comparisons, or regression bisection.

Install

npx vskill@latest install edmundmiller/dotfiles/zbench

SKILL.md

zsh-bench Integration

Proper benchmarking of interactive zsh using romkatv/zsh-bench. Measures real user-visible latency, NOT time zsh -lic exit (which is meaningless).

Commands

bash
hey zbench # Run + display with threshold indicators (auto-compares if baseline exists)
hey zbench-save # Run + save as baseline + append history
hey zbench-compare # Run + explicit diff against baseline
hey zbench-check # Exit non-zero if over threshold (for git bisect)
hey zbench-baseline # Show saved baseline (no run)
hey zbench-history # Show TSV history

All commands accept extra zsh-bench args: hey zbench --iters 4 for quick runs. Run from the intended checkout: both installed hey and ./bin/hey execute that project's mise tasks. No host rebuild is needed for task edits. The Nushell entrypoints in bin/hey.d/zbench/ use def --wrapped ... [...args] so flags such as --iters pass through to zsh-bench.

Metrics & Thresholds

From romkatv's blind perception study — values at or below threshold are indistinguishable from zero:

MetricThresholdWhat it means
first_prompt_lag_ms50msTime to see prompt after opening terminal
first_command_lag_ms150msTime until first command can execute
command_lag_ms10msDelay between Enter and next prompt
input_lag_ms20msKeystroke-to-screen latency

Indicators: 🟢 ≤50% (headroom) · 🟡 ≤100% (imperceptible) · 🟠 ≤200% (noticeable) · 🔴 >200% (sluggish)

exit_time_ms is shown but not used for thresholds — it doesn't measure interactive performance.

Git Bisect Workflow

Find which commit made the shell slow:

bash
git bisect start
git bisect bad HEAD
git bisect good <known-good-commit>
git bisect run hey zbench-check

zbench-check exits non-zero when any metric exceeds its threshold.

File Layout

benchmarks/zsh-bench/
├── <Host>.json # Current baseline per host
└── history/
└── <Host>.tsv # Append-only history (timestamp, git_rev, metrics)
packages/zsh-bench/ # Nix package (romkatv/zsh-bench with internal/ helpers)
bin/hey.d/zbench/ # Project-local task entrypoints
bin/hey.d/.lib/zbench.nu # Shared Nushell benchmark implementation
bin/zbench-report # Python — parse, compare, format results

Baselines are per-host (MacTraitor-Pro.json, Seqeratop.json) because hardware varies.

Typical Workflow

bash
# 1. Establish baseline on a clean build
hey zbench-save
# 2. Make zsh config changes
vim config/zsh/.zshrc
hey rebuild
# 3. Check for regressions
hey zbench # Shows comparison vs baseline
# 4. If satisfied, update baseline
hey zbench-save

Autoresearch Optimization Prompt

For a multi-iteration optimization loop, use pi-autoresearch to drive small zsh config experiments and zsh-bench to measure whether each experiment helped. Do not use autoresearch instead of zsh-bench; use it as the edit → benchmark → keep/revert loop around zsh-bench.

Run the local prompt template with pi-autoresearch:

bash
pi -e npm:pi-autoresearch "$(cat .pi/prompts/zbench-autoresearch.md)"

If you prefer to install the extension persistently first:

bash
pi install npm:pi-autoresearch
cat .pi/prompts/zbench-autoresearch.md

Canonical prompt file: .pi/prompts/zbench-autoresearch.md.

Debugging Slow Startup

Phase Timing Script

Don't guess — measure. Paste this into zsh -c '...' to time each phase of startup:

zsh
zsh -c '
zmodload zsh/datetime
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export ZDOTDIR="${ZDOTDIR:-$XDG_CONFIG_HOME/zsh}"
export ZSH_CACHE="${ZSH_CACHE:-$XDG_CACHE_HOME/zsh}"
function _source { [[ -f "$1" ]] && source "$1"; }
function _cache {
local cache_dir="$XDG_CACHE_HOME/zsh"; local cache_file="$cache_dir/$1.zsh"
if [[ ! -f "$cache_file" ]] || [[ "$commands[$1]" -nt "$cache_file" ]]; then
mkdir -p "$cache_dir"; "$@" > "$cache_file"; fi
source "$cache_file"
}
t0=$EPOCHREALTIME
source $ZDOTDIR/.zshenv 2>/dev/null; t1=$EPOCHREALTIME
source $ZDOTDIR/config.zsh; t2=$EPOCHREALTIME
# ... add phases matching your .zshrc ...
source $ZDOTDIR/completion.zsh 2>/dev/null; t3=$EPOCHREALTIME
_source $ZDOTDIR/extra.zshrc; t4=$EPOCHREALTIME
printf "zshenv: %4.0fms\n" $(( (t1-t0)*1000 ))
printf "config: %4.0fms\n" $(( (t2-t1)*1000 ))
printf "completion: %4.0fms\n" $(( (t3-t2)*1000 ))
printf "extra: %4.0fms\n" $(( (t4-t3)*1000 ))
printf "TOTAL: %4.0fms\n" $(( (t4-t0)*1000 ))
'

Adapt phases to match the actual .zshrc. The gap between this total and zsh-bench is overhead from /etc/zshrc (nix-darwin generated) and deferred plugin loading.

To drill into extra.zshrc, time each source line individually — one slow alias file can dominate.

Known Culprits (ranked by typical impact)
CulpritTypical costFix
Redundant compinit2000-3000msEnsure compinit runs exactly once. Check EOF of .zshrc, /etc/zshrc, and completion.zsh — easy to end up with 2+ calls. Use compinit -C -d "$cache" with 24h staleness check.
Nix store globs200-400msfor f in /nix/store/*foo*/*.zsh is slow — thousands of dirs. Cache the resolved path to a file.
Shell startup file scanning100-500msFunctions that grep/sed across many files at startup (e.g., fixing session files). Move to on-demand or a cron job.
Uncached `eval "$(tool init)"`40-100ms eachbrew shellenv, direnv hook zsh, fnm env, zoxide init zsh, entire completion zsh. Use _cache pattern to write output to file, re-eval only when binary changes.
Double `brew shellenv`40-80msnix-homebrew adds eval "$(brew shellenv)" to /etc/zshrc. If you handle it in .zshenv, set enableZshIntegration = false in nix-homebrew config.
Plugin manager overhead10-40msAntidote's antidote load does staleness checks. If static file exists, source it directly and skip antidote init entirely.
Deferred plugins0ms startupantidote kind:defer is free at startup but zsh-bench won't detect has_syntax_highlighting/has_autosuggestions. This is fine.
The _cache Pattern

Central to fast startup. Already defined in .zshrc:

zsh
function _cache {
local cache_dir="$XDG_CACHE_HOME/zsh"
local cache_file="$cache_dir/$1.zsh"
if [[ ! -f "$cache_file" ]] || [[ "$commands[$1]" -nt "$cache_file" ]]; then
mkdir -p "$cache_dir"
"$@" > "$cache_file"
fi
source "$cache_file"
}
# Usage:
_cache zoxide init zsh # instead of eval "$(zoxide init zsh)"
_cache direnv hook zsh # instead of eval "$(direnv hook zsh)"
_cache entire completion zsh # instead of source <(entire completion zsh)

Invalidates when the binary changes ($commands[$1] mtime check). Delete ~/.cache/zsh/*.zsh to force regeneration.

Replay Mode

Use zsh-bench --iters 1 --scratch-dir /tmp/zbench-debug then dbg/replay --scratch-dir /tmp/zbench-debug to watch what zsh-bench actually sees. For worktree experiments that should read the repo copy of config/zsh, run with ZDOTDIR=$PWD/config/zsh ZSH_CACHE=$HOME/.cache/zsh; otherwise zsh-bench may exercise the currently installed Home Manager generation.

Key Design Decisions

  • Uses zsh-bench's non-raw output (median of 16 iterations) for stable numbers.
  • `--raw` gives per-iteration arrays — useful for variance analysis but not default.
  • Baselines stored as JSON for easy programmatic comparison.
  • History stored as TSV for easy column -t, awk, or import into spreadsheets.
  • Regression detection: flags changes > 20% or > 5ms (whichever is larger).

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
48
Repository forks
4
7-day trend score
19

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 18 Mar 2026, 7 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/edmundmiller/dotfiles/zbench/badge)](https://verified-skill.com/skills/edmundmiller/dotfiles/zbench)

Something wrong with this skill or its page? Tell us.