$curl -o .claude/agents/perf.md https://raw.githubusercontent.com/Rune-kit/rune/HEAD/agents/perf.mdPerformance regression gate — detects N+1 queries, sync-in-async, missing indexes, memory leaks, bundle bloat. Investigate only, does NOT fix. Use before commit or deploy.
| 1 | # perf |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Performance regression gate. Analyzes code changes for patterns that cause measurable slowdowns — N+1 queries, sync operations in async handlers, unbounded DB queries, missing indexes, memory leaks, and bundle bloat. Not a profiler — a gate. Finds performance bugs with measurable/estimated impact before production, so developers fix them at the cheapest point in the cycle. |
| 6 | |
| 7 | ## Triggers |
| 8 | |
| 9 | - `/rune perf` — manual invocation before commit |
| 10 | - Called by `cook` (L1): Phase 5 quality gate |
| 11 | - Called by `review` (L2): performance patterns detected in diff |
| 12 | - Called by `deploy` (L2): pre-deploy regression check |
| 13 | - Called by `audit` (L2): performance health dimension |
| 14 | |
| 15 | ## Calls (outbound) |
| 16 | |
| 17 | - `scout` (L2): find hotpath files and identify framework in use |
| 18 | - `browser-pilot` (L3): run Lighthouse / Core Web Vitals for frontend projects |
| 19 | - `verification` (L3): run benchmark scripts if configured (e.g. `npm run bench`) |
| 20 | - `design` (L2): when Lighthouse Accessibility BLOCK — design system may lack a11y foundation |
| 21 | |
| 22 | ## Called By (inbound) |
| 23 | |
| 24 | - `cook` (L1): Phase 5 quality gate before PR |
| 25 | - `audit` (L2): performance dimension delegation |
| 26 | - `review` (L2): performance patterns detected in diff |
| 27 | - `deploy` (L2): pre-deploy perf regression check |
| 28 | - `adversary` (L2): scalability stress test when bottleneck patterns detected in plan |
| 29 | |
| 30 | ## References |
| 31 | |
| 32 | - `references/cost-reference.md` — Cost priority hierarchy, quick wins checklist, instance right-sizing, data transfer traps, serverless optimization, observability cost control, managed vs self-hosted matrix, unit economics tracking. Load when cost analysis or FinOps context detected. |
| 33 | - `references/scalability-reference.md` — Bottleneck identification flow, performance thresholds, API patterns (cursor pagination, rate limiting, circuit breaker, graceful shutdown), caching strategies, queue-based load leveling, concurrency patterns, K8s HPA, CDN headers, load testing. Load when scaling or infrastructure optimization context detected. |
| 34 | - `../deploy/references/observability.md` — Instrumentation discipline (RED/USE metrics, percentiles-not-averages, cardinality bounds, structured logs, correlation IDs). Load when establishing the *measurement basis* for an optimization — you cannot optimize what you do not measure. |
| 35 | |
| 36 | **Measure before optimizing.** A perf finding without a metric behind it is a guess. Before recommending a fix, confirm the hotpath actually emits the signal that proves it is slow: RED latency as a **histogram** (read p95/p99 — averages hide the slow tail), bounded label cardinality, and a correlation ID to tie a slow trace to its logs. If the instrumentation does not exist yet, that absence is itself a finding (`UNMEASURED_HOTPATH`). See `../deploy/references/observability.md` for the instrumentation contract. |
| 37 | |
| 38 | ## Executable Steps |
| 39 | |
| 40 | ### Step 1 — Scope |
| 41 | |
| 42 | Determine what to analyze: |
| 43 | - If called with a file list or diff → analyze those files only |
| 44 | - If called standalone → invoke `scout` to identify top 10 hotpath files (entry points, routes, DB access layers, render-heavy components) |
| 45 | - Detect project type: **frontend** (React/Vue/Svelte) | **backend** (Node/Python/Go) | **fullstack** | **CLI** |
| 46 | |
| 47 | ### Step 2 — DB Query Patterns |
| 48 | |
| 49 | Scan all in-scope files for: |
| 50 | |
| 51 | **N+1 pattern** — loop containing ORM call: |
| 52 | ``` |
| 53 | # BAD: N+1 |
| 54 | for user in users: |
| 55 | orders = Order.objects.filter(user=user) # N queries |
| 56 | |
| 57 | # GOOD: prefetch |
| 58 | users = User.objects.prefetch_related('orders').all() |
| 59 | ``` |
| 60 | Finding: `N+1 DETECTED — [file:line] — loop over [collection] with [ORM call] inside — use prefetch/JOIN` |
| 61 | |
| 62 | **Unbounded query** — no LIMIT/pagination: |
| 63 | ``` |
| 64 | # BAD |
| 65 | db.query("SELECT * FROM events") |
| 66 | |
| 67 | # GOOD |
| 68 | db.query("SELECT * FROM events LIMIT 100 OFFSET ?", [offset]) |
| 69 | ``` |
| 70 | Finding: `UNBOUNDED_QUERY — [file:line] — missing LIMIT on [table] — add pagination` |
| 71 | |
| 72 | **SELECT \*** — fetching all columns when only some are needed: |
| 73 | Finding: `SELECT_STAR — [file:line] — select only needed columns` |
| 74 | |
| 75 | ### Step 3 — Async/Sync Violations |
| 76 | |
| 77 | Scan for synchronous operations in async contexts: |
| 78 | |
| 79 | **Blocking I/O in async handler:** |
| 80 | ```javascript |
| 81 | // BAD: blocks event loop |
| 82 | async function handler(req) { |
| 83 | const data = fs.readFileSync('./config.json') |
| 84 | } |
| 85 | |
| 86 | // GOOD |
| 87 | async function handler(req) { |
| 88 | const data = await fs.promises.readFile('./config.json') |
| 89 | } |
| 90 | ``` |
| 91 | Finding: `SYNC_IN_ASYNC — [file:line] — [readFileSync|execSync|etc] in async function — blocks event loop` |
| 92 | |
| 93 | **Missing await:** |
| 94 | ```javascript |
| 95 | // BAD: fire-and-forget |
| 96 | async function save() { |
| 97 | db.insert(record) // no await |
| 98 | } |
| 99 | ``` |
| 100 | Finding: `MISSING_AWAIT — [file:line |