| name | self:perf |
|---|---|
| description | Hypothesis-driven performance investigation — analyze, hypothesize, test one theory at a time, measure against baseline. |
Structured performance optimization that forms hypotheses from evidence before changing code. Tests one theory at a time against a stable baseline.
- Benchmark command — command that outputs a measurable metric (required)
- Target — file or directory scope (default: entire project)
- Metric name — what the benchmark measures, e.g. "request latency ms" (required)
- Goal — target metric value, e.g. "< 200" (optional)
- Iterations — max investigation cycles (default: 10)
- Budget — max USD (default: $5)
- Token budget: ~400k tokens. Investigation is more expensive than blind optimization.
- Early exit: Stop when goal is met or no viable hypotheses remain.
- Stuck detection: If 3 consecutive hypotheses fail, escalate to user. See the
stuckskill.
Run the benchmark at least 3 times for stability:
git checkout -b perf/$(date +%Y%m%d-%H%M%S)
echo "=== Baseline Run 1 ===" && {benchmark_command}
echo "=== Baseline Run 2 ===" && {benchmark_command}
echo "=== Baseline Run 3 ===" && {benchmark_command}Record the median result as the baseline. Reject runs with >20% variance — the benchmark isn't stable enough for meaningful optimization.
Save baseline:
mkdir -p .devkit/perf
cat > .devkit/perf/baseline.json << 'BASELINE'
{
"metric": "{metric_name}",
"value": {median_value},
"unit": "{unit}",
"runs": [{run1}, {run2}, {run3}],
"variance_pct": {variance},
"commit": "{commit_hash}",
"timestamp": "{iso8601}"
}
BASELINEBefore forming hypotheses, collect data from multiple sources:
# Find performance-related commits
git log --all --oneline --grep="perf" --grep="slow" --grep="optimize" --grep="cache" --grep="latency" --grep="memory" | head -20
# Find recent changes to hot paths
git log --oneline -20 -- {target}
# Find large commits that may have introduced regressions
git log --oneline --diff-filter=M --stat | head -30Spawn the researcher agent:
Task: Analyze the critical code paths in {target} for performance.
Agent: researcher
Focus on:
- Hot loops and recursive calls
- I/O operations (file, network, database)
- Memory allocation patterns (large objects, frequent allocations)
- Synchronous operations that could be async
- Missing caching opportunities
- N+1 query patterns
- Unnecessary serialization/deserialization
- Redundant computation
Report: list of suspicious code paths with file:line references
# Check for existing profiling tools
command -v perf >/dev/null 2>&1 && echo "perf available"
command -v hyperfine >/dev/null 2>&1 && echo "hyperfine available"
[ -f flamegraph.svg ] && echo "flamegraph found"If profiling tools are available, run a quick profile to identify actual hotspots.
Based on the evidence, form up to 5 ranked hypotheses:
## Hypotheses
| # | Hypothesis | Evidence | Confidence | Expected Impact |
|---|-----------|----------|------------|-----------------|
| 1 | N+1 queries in getUserOrders | researcher found loop with individual DB calls at orders.ts:45 | High | 3-5x faster |
| 2 | Missing cache for config parsing | parseConfig called 12x per request, git shows it was recently changed | Medium | 20-30% faster |
| 3 | Synchronous file reads in middleware | blocking I/O in request path at middleware.ts:23 | Medium | 10-20% faster |
| 4 | Large JSON serialization in logging | JSON.stringify on full request objects at logger.ts:67 | Low | 5-10% faster |
| 5 | Regex compilation on every call | new RegExp() inside loop at validator.ts:12 | Low | 5% faster |
Rules for hypotheses:
- Each must cite specific evidence (file:line, git commit, profiler output)
- Each must predict the expected impact (not just "faster")
- Confidence is based on evidence strength, not gut feel
- Order by confidence * expected impact (highest first)
For each hypothesis, starting from highest-ranked:
Spawn the improver agent:
Task: Optimize {target} based on this hypothesis:
Hypothesis: {hypothesis_description}
Evidence: {evidence}
File: {file_path}:{line}
Agent: improver
Constraints:
- Change ONLY what this hypothesis addresses
- Do not refactor unrelated code
- Preserve all existing behavior
- Keep the change as small as possible
# Run tests first — optimization must not break anything
{test_command} || echo "TESTS FAILED — reverting"If tests fail, revert and move to next hypothesis.
Run benchmark 3 times again:
echo "=== Post-fix Run 1 ===" && {benchmark_command}
echo "=== Post-fix Run 2 ===" && {benchmark_command}
echo "=== Post-fix Run 3 ===" && {benchmark_command}Compare median against baseline:
IMPROVEMENT=$(( (BASELINE - NEW_MEDIAN) * 100 / BASELINE ))Decision:
- Improvement matches or exceeds prediction → Keep. Commit.
git add -A && git commit -m "perf: {hypothesis summary} ({improvement}% improvement)"
- Improvement exists but below prediction → Keep if >5% improvement, otherwise revert.
- No improvement or regression → Revert. Log why hypothesis was wrong.
git checkout -- .
Log the result:
echo "HYPOTHESIS {n}: {PASS|FAIL} — predicted {predicted}%, actual {actual}%" >> .devkit/perf/investigation.log
echo " Evidence: {evidence}" >> .devkit/perf/investigation.log
echo " Lesson: {why it worked or didn't}" >> .devkit/perf/investigation.logIf the fix was kept, the new median becomes the baseline for subsequent hypotheses.
## Performance Investigation Report
**Target:** {target}
**Metric:** {metric_name}
**Baseline:** {baseline_value} {unit}
**Final:** {final_value} {unit}
**Total improvement:** {total_improvement}%
**Goal:** {goal} — {met|not met}
### Hypotheses Tested
| # | Hypothesis | Predicted | Actual | Result |
|---|-----------|-----------|--------|--------|
| 1 | N+1 queries in getUserOrders | 3-5x | 3.2x | PASS — kept |
| 2 | Missing cache for config | 20-30% | 22% | PASS — kept |
| 3 | Sync file reads | 10-20% | 2% | FAIL — below threshold, reverted |
| 4 | JSON serialization | 5-10% | — | SKIPPED — goal already met |
### Investigation Log
{contents of .devkit/perf/investigation.log}
### Commits
| Commit | Hypothesis | Improvement |
|--------|-----------|-------------|
| abc1234 | Batch N+1 queries | 3.2x |
| def5678 | Add config cache | 22% |
### Remaining Hypotheses (untested)
- Large JSON serialization in logging — estimated 5-10%
- Regex compilation on every call — estimated 5%
### Next Steps
- Review: `git diff main...HEAD`
- Merge: `git checkout main && git merge perf/{branch}`
/self:perf --target src/api/ --benchmark "wrk -t4 -c100 -d5s http://localhost:3000" --metric "p99 latency ms" --goal "< 200"
/self:perf --target lib/parser.go --benchmark "go test -bench=. -benchtime=3s" --metric "ns/op" --goal "< 1000"
- Always branch first
- Never skip the evidence-gathering step — blind optimization is guessing
- Test ONE hypothesis at a time — never bundle changes
- Run benchmarks 3x minimum — single runs are unreliable
- Reject benchmarks with >20% variance
- Tests must pass before measuring — broken code isn't faster code
- Log every hypothesis outcome with the lesson learned
- Revert on regression or no improvement — don't keep dead changes
- Stop when goal is met — don't over-optimize
- The improver agent runs in worktree isolation
- The researcher agent runs in worktree isolation for code analysis