Benchmark runner for local performance regression testing and monitoring hot paths.
Install
mkdir -p .claude/skills/bench-oysteinamundsen && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18729" && unzip -o skill.zip -d .claude/skills/bench-oysteinamundsen && rm skill.zipInstalls to .claude/skills/bench-oysteinamundsen
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Run @toolbox-web benchmarks as local regression testing during development — either current-vs-previous-run (`bun run bench`) or current-vs-tag (the bundled bench-vs-tag.ts orchestrator). Covers writing `.bench.ts` files as part of issue development, running the suites, locating artifacts, and interpreting regressions. Use when implementing a perf-sensitive change, before opening a PR that touches hot paths, or when asked to benchmark.Key capabilities
- →Run benchmarks to detect performance regressions
- →Compare current code performance against previous runs
- →Compare current code performance against a released tag
- →Write `.bench.ts` files for hot paths
- →Interpret benchmark results and identify regressions
How it works
The skill uses `bun run bench` for current-vs-previous comparisons and `bench-vs-tag.ts` for current-vs-tag comparisons, running benchmarks and generating reports to identify performance deltas.
Inputs & outputs
When to use bench
- →Benchmark hot code paths
- →Catch performance regressions
- →Compare performance vs tags
- →Optimize plugin dispatch
About this skill
Benchmarking & Local Regression Testing
Benchmarks are the project's guard against silent performance regressions. Treat them like
unit tests for speed: write a .bench.ts when you add or change a hot path, and run the
suite to confirm a change didn't make things slower before you open a PR.
Invoke manually as /bench [tag|version] [report-only], or autonomously during issue development.
For fixing a confirmed regression, hand off to the perf-fix skill (one hotspot, end-to-end)
or the debug-perf skill (profiling reference).
Argument handling (slash-command use)
The text after /bench may contain:
- A git tag or bare version (
grid-2.7.0,2.7.0,grid-react-1.2.0) → current-vs-tag run. Resolve per Tag resolution, echo the resolved tag, then runbun .github/skills/bench/bench-vs-tag.ts --ref <tag>. - Nothing →
bun run bench(current-vs-previous-run). - The literal
report-only(alone or after the tag) → produce the report but skip the fix plan.
If a run fails, report the error verbatim and stop.
When to write a .bench.ts
Add or extend a benchmark as an integral part of issue development whenever you:
- Touch a hot path — render scheduler, virtualization, config merge, sort/filter, plugin hook dispatch, large-dataset row building, adapter reconciliation.
- Add a new feature or plugin that runs work per-row, per-frame, or per-keystroke.
- Fix a performance bug — add a bench that would have caught it, so it can't silently return.
Bench files live next to the code under test as *.bench.ts and are picked up by each project's
bench target (vitest bench, include: ['src/**/*.bench.ts']). Keep each bench() case
focused on one operation; avoid mixing setup cost into the measured body (use the bench harness's
setup hooks only for immutable fixture construction). Mirror the style of existing benches under
libs/*/src/**/*.bench.ts.
Stateful benchmark rules
- Do not treat Tinybench
setupas a per-invocation reset. A stateful callback can become a cache hit or no-op after its first invocation. Restore or alternate the relevant state inside every timed invocation, and include that reset only when it is part of the operation being measured. If reset cost would contaminate the result, use prebuilt alternating fixtures. - Prove that every invocation performs real work. Add a control case that exposes the expected algorithmic shape where practical, such as first/middle/last position updates.
- Use deterministic fixtures. Derive values and hit rates from indexes; never use
Math.random()ornode:cryptoin fixture construction or timed callbacks. Current-vs-tag comparisons are meaningful only when both sides process the same data distribution. - Keep unrelated work outside the callback. Prebuild rows, caches, and column definitions. If the operation under test requires invalidation, mutation, or cloning, include only the minimum reset that preserves a real operation on every invocation.
Two ways to run
| Mode | Command | Compares | Use when |
|---|---|---|---|
| Current vs previous run | bun run bench | HEAD now vs the last local bench output | Iterating on a branch; quick "did my last edit slow this down?" |
| Current vs tag | bun .github/skills/bench/bench-vs-tag.ts --ref <tag> | HEAD vs a released tag, same-runner methodology | Validating a branch against a shipped baseline before a PR |
bun run bench runs nx run-many --target=bench across the bench-enabled projects
(grid, grid-react, grid-vue) and writes per-project JSON to the bench output directory.
The bench-vs-tag.ts orchestrator materialises the baseline ref in a sibling git worktree,
runs vitest bench on both sides on this machine (same CPU / kernel / thermal state — the
whole point of the methodology), merges max-of-N per side via tools/merge-bench-runs.ts, and
compares via tools/compare-benches.ts. Artifacts land under tmp/ (bench-current-*.json,
bench-baseline-*.json).
bench-vs-tag flags (most useful)
bun .github/skills/bench/bench-vs-tag.ts # default: last tag, all projects, 1 iter
bun .github/skills/bench/bench-vs-tag.ts --ref grid-2.7.0 # explicit tag/SHA baseline
bun .github/skills/bench/bench-vs-tag.ts --project grid # subset (repeatable)
bun .github/skills/bench/bench-vs-tag.ts --iterations 3 # max-of-N per side (noisy suites)
bun .github/skills/bench/bench-vs-tag.ts --threshold 0.20 # tighter regression gate (default 0.30)
bun .github/skills/bench/bench-vs-tag.ts --keep-worktree # don't delete ../base on exit
bun .github/skills/bench/bench-vs-tag.ts --fail-on-regression # exit non-zero on regression (CI-style; off by default)
bun .github/skills/bench/bench-vs-tag.ts --help # full flag list
Run with mode=sync and a generous timeout — bench runs are long. Do not pipe through
tail/head/2>&1 (terminal hangs on this machine — see copilot-instructions.md).
Tag resolution
The user may pass a bare version like 2.7.0 instead of a fully-qualified tag. Resolve before
invoking bench-vs-tag.ts:
- If the input is already a tag (
git rev-parse --verify "refs/tags/<input>"), use it verbatim. - If it looks like semver (
^\d+\.\d+\.\d+), prepend the flagship prefixgrid-and re-check (2.7.0→grid-2.7.0). - Otherwise
git tag --list "*<input>*" --sort=-creatordate. One match → use it. Multiple (e.g.1.6.0could begrid-vue-1.6.0orgrid-react-1.6.0) → stop and ask; do not guess. - Nothing resolves → surface the failure and candidate list; do not fall back silently.
Echo the resolved tag back before starting (e.g. "Resolved 2.7.0 → grid-2.7.0.").
Reading the results
Read the JSON / comparison-Markdown artifacts directly for precise numbers — do not parse console
output. For each suite compare current vs baseline mean and flag any regression above the script's
threshold (default 0.30 for vs-tag). When asked for a report, produce:
-
Check comparability before diagnosing a flagged row. Diff the benchmark file and compare the Git blob hashes of the implementation and dependency lockfile against the baseline. If the implementation and lockfile are identical but fixture generation, lookup order, or measured work changed, classify the row as non-comparable benchmark drift rather than a code regression. Confirm with
--iterations 3; do not optimize unchanged production code to compensate for fixture noise. -
Verdict — one line: Faster / Slower / Mixed vs the named baseline (
grid-2.7.0orprevious local run @ <timestamp>), with the headline delta. -
Per-suite table —
Suite | Baseline mean | Current mean | Δ | Regression?, sorted by |Δ%|. -
Hotspots — map each regressed suite to its
*.bench.tsand the code under test; usegit log --oneline <baseline>..HEAD -- <path>to surface the top 1–3 suspect commits. For grid-core, cross-reference.github/knowledge/grid-render-pipeline.md,.github/knowledge/grid-data-pipeline.mdand.github/knowledge/data-flow-traces.md. -
Fix plan (skip under
report-only) — per hotspot: Hypothesis (what's slower and why) · Investigation (minimal next step —debug-perf, microbench, bisect) · Candidate fix (concrete change, file + symbol) · Risk/scope (public API, plugin compat, bundle size). Order by impact-to-effort ratio.
Print the report inline (no Markdown file unless asked). End with the one-line verdict and the
exact command to reproduce the run. If regressions exist, point to /perf-fix (executes one
fix-plan item end-to-end: profile → patch → re-bench → verdict).
Constraints
- Never push, never commit. Benchmarking is read + analyze.
- Cite numbers; do not paraphrase deltas. Flag noisy-below-threshold suites explicitly.
- If a tag cannot be resolved, surface the error and stop — do not fall back silently.
- Do not "fix" the bench harness unless explicitly asked.
- Respect the bundle and perf invariants in
.github/knowledge/build-and-deploy.md.
When not to use it
- →When pushing or committing changes during benchmarking
- →When paraphrasing delta numbers in reports
- →When fixing the bench harness without explicit request
Limitations
- →Does not push or commit changes during benchmarking
- →Requires citing exact numbers in reports
- →Does not allow fixing the bench harness without explicit request
How it compares
This skill provides two distinct benchmarking modes for local regression testing, allowing comparison against previous runs or released tags, unlike simple performance profiling.
Compared to similar skills
bench side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| bench (this skill) | 0 | 4mo | Review | Intermediate |
| chrome-devtools | 41 | 9mo | Review | Intermediate |
| azure-monitor-opentelemetry-ts | 1 | 6mo | Review | Intermediate |
| agent-refinement | 1 | 8mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by OysteinAmundsen
View all by OysteinAmundsen →You might also like
chrome-devtools
mrgoonie
Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.
azure-monitor-opentelemetry-ts
microsoft
Instrument applications with Azure Monitor and OpenTelemetry for JavaScript (@azure/monitor-opentelemetry). Use when adding distributed tracing, metrics, and logs to Node.js applications with Application Insights.
agent-refinement
ruvnet
Agent skill for refinement - invoke with $agent-refinement
dependency-upgrade
wshobson
Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.
playwright-browser-automation
lackeyjb
Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing.
bullmq-specialist
davila7
BullMQ expert for Redis-backed job queues, background processing, and reliable async execution in Node.js/TypeScript applications. Use when: bullmq, bull queue, redis queue, background job, job queue.