---
name: lobe-diagnose
description: Diagnose HTTP performance issues from a lobe capture session. Use when the user says their API is slow, mentions lobe, or points at a `/tmp/lobe-capture-session-*.json` file. Returns a ranked, phase-by-phase triage report against grounded baseline thresholds.
---
# lobe-diagnose
You are analyzing a captured HTTP session produced by the `lobe` tool — a local performance proxy that measures every request's DNS, TCP, TLS, TTFB, and download phases. Your job is to systematically check utilization hotspots, saturation signals, and errors — in that priority order — then explain what's slow and what to fix first.
## Step 1 — Locate the session file
Priority order:
1. If the user provided a path, use it.
2. Otherwise, find the most recent capture:
```bash
ls -t /tmp/lobe-capture-session-*.json 2>/dev/null | head -1
```
3. If no capture exists, tell the user to run:
```bash
lobe capture <upstream>
```
Then re-invoke this skill.
## Step 2 — Understand the file shape
The file is JSON. You care about the `events` array:
```json
{
"version": 1,
"listen_addr": "127.0.0.1:7878",
"upstream": "http://localhost:3000",
"exported_at_ms": 1704000000000,
"event_count": 42,
"events": [
{
"request_host": "localhost",
"request_method": "GET",
"request_path": "/api/users",
"response_status_code": 200,
"response_bytes": 1234,
"report": {
"dns_ms": 0,
"tcp_ms": 1,
"tls_ms": 0,
"ttfb_ms": 45,
"download_ms": 3,
"total_ms": 49
},
"error_message": null,
"created_at_ms": 1704000000000
}
]
}
```
Read only what you need; do not print raw JSON back at the user.
## Step 3 — Apply the (Utilization Saturation Errors) method (this priority order)
### 3a. Utilization (do this first)
Sum `total_ms` per `(method, path)`. Rank routes by **cumulative wall-clock time**, not by individual latency. The routes at the top of this list are burning the most session time in aggregate — they're where optimization has the most leverage.
### 3b. Saturation
For each unique `(request_method, request_path)` group:
- Compute **P50, P90, P99** of `report.total_ms`.
- **Long tail**: if `P99 > 5 × P50`, the tail is unusually long — a signal that something occasionally goes wrong for this route.
- **TTFB dominance**: if median `ttfb_ms > 60% of total_ms`, the upstream is doing slow work before it starts writing the response. This is the most common finding in real captures.
- **Download dominance**: if median `download_ms > 60% of total_ms`, the response body is large relative to bandwidth (or the upstream is streaming slowly).
- **Bimodal distribution**: sort the total_ms values. If they cluster into two clearly separated bands (e.g., most around 4ms, another cluster around 47ms), flag it as bimodal — this is classic cache hit vs. miss, or a fast-path/slow-path branch.
### 3c. Errors
Count events where `response_status_code` is `null` OR outside `200..=299`. Group by `(status_code, method + path)`. Report the top patterns with counts and share of total requests.
If zero errors: write "No errors observed."
## Step 4 — Cross-check against baseline thresholds
Classify each request's host and compare to the rule-of-thumb baselines:
| **loopback** | `localhost`, `127.x.x.x`, `::1` | ≤ 50ms | ≤ 80ms |
| **LAN** | 10.x, 192.168.x, 172.16-31.x, `*.local` | ≤ 100ms | ≤ 200ms |
| **remote** | anything else (public internet) | ≤ 500ms | ≤ 1.5s |
Anything meaningfully over these is worth calling out. A localhost API returning in 340ms is 4× baseline — a big deal. A remote API returning in 340ms is fine.
## Phase interpretation cheatsheet
When a phase is anomalously high, use this to explain *why*:
- **DNS excess** → resolver issue, cold DNS lookup, custom `/etc/hosts` entries
- **TCP excess** → saturated network path or upstream at capacity
- **TLS excess** → old TLS version, deep certificate chain, slow ALPN negotiation
- **TTFB excess** → almost always slow DB queries, missing indexes, N+1 queries, or CPU-bound work before writing the response. This is 80% of real findings.
- **Download excess** → large response body relative to bandwidth, streaming slowly, or missing compression
## Step 5 — Output format
Return a markdown report with **these exact sections in this order**:
### Summary
2–3 sentences. Lead with the number that matters most. Example: *"412 requests captured over 3 minutes. Zero errors. GET /api/users P99 is 340ms — 4× the loopback baseline. TTFB dominates."*
### Utilization
Which endpoints burn the most cumulative time. Be specific: `GET /api/users burned 4.2s of the session (34% of total)`.
### Saturation
Tail behavior, TTFB dominance, bimodal patterns. Cite specific numbers, not generalities.
### Errors
Top error patterns with counts. If none, one line: "No errors observed."
### Recommendations
Exactly **3–5** specific, actionable items, ranked by expected impact. Each item must be concrete enough that a developer could act on it without asking follow-up questions.
**Good**: *"Add an index on `users.email`. GET /api/users P99=340ms with TTFB dominating (280ms of 340ms); the endpoint likely does a full-table scan by email."*
**Bad**: *"Look at your database performance."*
## Rules
- **Be concrete**. Cite specific endpoints, specific numbers, specific phase names.
- **Do not fabricate causes**. If the phase breakdown doesn't uniquely point at a root cause, say "insufficient evidence — recommend running `lobe explain` again with a larger capture" rather than guessing.
- **Prioritize wall-clock impact over ratio**. A phase that's 5× over baseline but only adds 3ms matters less than one that's 2× over but adds 200ms.
- **Do not print the raw session JSON back at the user**. They already have it.