Why OMP feels slow: measured diagnostic

Local evidence audit · window Jun 17 – Jul 30, 2026 · generated Jul 30, 2026

520,183 model calls 481,209 tool calls 11,297 user turns 5,918 agent session logs 91 runtime logs / 37.2 MB

Verdict

The slowdown is real and concentrated in subagent work. Provider APIs are not the main cause.

Ordinary tasks: median +10.4%, p90 +48.3% work time — modestly slower, much more variable.
Subagent tasks: median +79.5%, p90 +170.1% work time — categorically slower.
Cause: OMP performs roughly twice the work per task (agent turns, tool calls, coordination waits), not slower model responses.
Live aggravator: 39 OMP processes and 35.3 GB of swap in use right now.
Subagent task p50
+79.5%
12.7 → 22.8 min work time
Subagent task p90
+170.1%
40.3 → 108.8 min work time
Child session p90
+92.4%
9.9 → 19.1 min work time
Child active model time p90
+95.3%
6.4 → 12.5 min
Coordination density
+100.5%
56.2 → 112.7 /1k tools
Main call duration p50
+2.8%
8.63 → 8.87 s
Main TTFT p50
-5.1%
4.55 → 4.32 s
Subagent TTFT p50
+24.8%
1.65 → 2.06 s
Call error rate
-36.0%
3.69% → 2.36%
Reading the two headline numbers together: per-call latency is roughly flat, yet end-to-end task time doubled. The extra time is spent doing more steps, not waiting longer per step.

Method and provenance

Sources

~/.omp/stats.db520,183 calls · 481,209 tool calls · 11,297 user turns
~/.omp/agent/sessions236 projects · 796 run dirs · 5,918 jsonl
~/.omp/logs91 files · 37.2 MB · incl. 26 gzipped
~/.omp/agent/history.db6,593 history rows
live host snapshotps / vm_stat / sysctl / uptime

Windows

Prior 3 weeksJun 17 – Jul 7 (21 days)
Recent 3 weeksJul 8 – Jul 28 (21 days)
Live tailJul 29 – Jul 30 (logs only)
stats.db ends Jul 28 07:10 UTC, so Jul 29–30 appear only in runtime logs and the live snapshot.

Definitions

verified means recomputed directly from local data in this session. inference marks interpretation beyond the measurement.

Weekly trend: where it broke

Subagent task duration was stable through Jul 7, then spiked hard in the week of Jul 15 — the same week the coordination layer switched from job/irc to hub.

Subagent tasks (minutes)

p90p50

Tasks without subagents (minutes)

p90p50

Weekly subagent tasks

Median main-agent calls per subagent task

Week of Jul 15: median 151 calls per subagent task, versus 40–48 in June.
The Jul 15 week is the worst measured week: p50 46.8 min, p90 209.4 min (n=133). The Jul 22 week partially recovered to 15.8 / 89.3 min, still above the June baseline. inference the cutover coincides with, but is not proven to cause, the spike.

End-to-end task latency

Full percentile distributions, prior versus recent, split by whether the task used subagents.

Subagent tasks (minutes)

priorrecent

Tasks without subagents (minutes)

priorrecent
Median task text length was unchanged (11 → 10 words for simple tasks, 15 → 15 for subagent tasks), so the regression is not explained by you asking for more per message. verified

Child subagent sessions

Each individual subagent runs about twice as long and issues about twice as many model calls. Percentiles here exclude idle time: gaps longer than 5 minutes between a child's calls are clipped, because 303 of the 317 sessions over 30 minutes were parked and later resumed rather than working continuously.

Child session work time (minutes)

priorrecent

Model calls per child session

priorrecent
Raw span versus work time. Raw span p90 rose 11.0 → 41.6 min (+277.3%), but that figure counts parked idle time. With idle clipped, p90 rose 9.9 → 19.1 min (+92.4%) and active model time rose 6.4 → 12.5 min (+95.3%). The regression is a clean doubling, not a fourfold blowup. verified

Work volume per task

The clearest signal in the dataset: more steps per task, at the same request complexity.

priorrecent
Median coordination/wait operations inside a subagent task rose from 0 to 4. Waiting became a routine part of the critical path. verified

Coordination traffic and the protocol cutover

Coordination calls per 1,000 main-session tool calls doubled. The mechanism changed mid-July.

Coordination call mix

task job hub irc

Cutover timeline verified

taskJun 17 06:44 → Jul 28 05:252,664
jobJun 17 06:47 → Jul 17 14:088,215
ircJun 17 08:52 → Jul 17 14:099,156
hubJul 16 23:17 → Jul 28 07:016,006
First and last observed use, all agent types. The job/irc pair stops within 15 hours of hub appearing.

Fan-out width

Fewer tasks use subagents, but heavy tasks spawn far more children. The regression lives in that tail.

priorrecentJul 29-30
Counted from parent run directories, so this is cumulative children per task rather than peak concurrency. Median fell 3 → 2 while p90 rose 19 → 32.6. verified

Model-call latency

Per-call latency is close to flat for the main agent. Subagent calls got moderately slower, mostly through routing mix.

By agent type, prior versus recent

By model, whole six weeks

TTFT p50rest of duration p50
Routing shifted from gpt-5.5 to reasoning-oriented gpt-5.6-sol: subagent TTFT p50 1.66 s → 2.26 s and duration p50 5.28 s → 5.59 s. Flash subagent calls complete in 1.43 s p50. Workloads differ per model, so this compares routing cost, not model quality. inference

Weekly per-agent detail

Context inflation

Typical calls barely grew. Long sessions grew a lot, which is where compaction overhead appears.

Context tokens p50 (thousands)

priorrecent

Context tokens p90 (thousands)

priorrecent
Observed live compactions fire at roughly 231k–318k context tokens against 272k–372k windows. Main p90 context rose 24.3%, advisor p90 rose 45.3%. verified

Errors and retries

Reliability improved. Provider failures do not explain the slowdown.

Prior 3 weeks — 3.69% of calls

Recent 3 weeks — 2.36% of calls

Usage-limit errors remain the top failure class in both windows. Errored calls fail fast, so they inflate step count more than wall-clock latency. inference

UI event-loop stalls

Chronic in both windows, not a new regression. The severe tail is happening right now.

Stall severity mix

<500 ms 0.5-1 s 1-5 s ≥5 s

Retention makes totals incomparable

Stalls per MB of retained log, by day. Mid-July logs were largely rotated away, so window totals measure retention as much as behavior.
Correction to the earlier chat summary: ui.loop-blocked instrumentation is not new. Scanning all 91 log files including gzipped rotations yields 29,777 events from Jun 16 onward, with 14,620 inside the prior window. The earlier figure of 14,489 "recent only" came from uncompressed files alone. verified

Subagent launch cost

Spawn overhead is negligible historically and pathological today.

priorrecentJul 29-30
Invoke-to-first-chat p90 is 521 ms (prior) and 206 ms (recent), but 3,540 ms on Jul 29–30 with a p99 of 145.7 s. Launch cost is not a historical driver; it is a live symptom of host pressure. verified

Live host pressure

Measured during this diagnostic. This is not a historical trend, it is the current operating condition.

OMP processes
39
20 older than 24 h
Swap used
35.3 GB
of 36.0 GB
Load average
9.13
10.49 / 10.40 (5m / 15m)
Free memory
29%
of 25.8 GB
OMP resident set
2.6 GB
direct processes only
OMP CPU aggregate
199%
sum across processes
Compressor pages
5.12 M
462k pages occupied
Worst live stall
73 min
single loop-block event
A 1-second sample showed 74–529 MB/s of memory decompression and continuous page reactivation. Twenty OMP processes older than a day each retain session state, caches, MCP children, and terminal buffers beyond that 2.6 GB direct figure. verified

Chronic issues that predate the window

These are not part of the recent regression. They were present across the whole six weeks and are worth fixing regardless.

1. Context size is the dominant per-call latency lever

Same model, same agent role, whole period. Holding gpt-5.6-sol fixed removes model mix as an explanation.

TTFT p50duration p50
Between the 50-100k and 250k+ buckets, TTFT p50 rises 2.22 → 6.98 s (+214%) and duration p50 rises 4.53 → 11.74 s (+159%). Meanwhile 66.8 percent of all main-agent calls carry more than 150k context tokens, 32.8 percent exceed 200k, and 11.8 percent exceed 250k. Prompt caching is already healthy at a 95 percent cache-read share, so this is raw prefill volume, not a cache miss problem. verified

2. Tool output caps are inconsistent, and read is unbounded

Across 481,209 tool calls, results total roughly 1.53 billion characters, about 383 million tokens. read alone accounts for 908 M characters, 59 percent of all tool output. Several tools clamp near 51k characters with zero results above that line, but read reached 460k characters in a single result, roughly 115k tokens, about 42 percent of a 272k window. verified

3. Fan-out stops paying off past about ten dispatches

Task duration is flat at roughly 700 s median for 1-2, 3-5, and 6-10 dispatch calls, then doubles to 1,755 s at 11 or more, with p90 reaching 12,103 s. Observational only: harder tasks dispatch more. Still, no benefit appears in the 3-10 range, which argues for a cumulative dispatch budget rather than only a concurrency cap. inference

4. Advisor was a quarter of all model calls

Advisor calls
142,674
27.4% of all calls
Advisor tokens
6.42 B
vs 39.35 B main
Status now
off
advisor.enabled=false
The advisor ran a second opinion alongside the main agent, adding 142,674 calls and 6.42 billion tokens over six weeks. It is already disabled in the current config, which is most of why recent-window call volume dropped. Keep it off unless a specific review need justifies it. verified

5. Tool calls carry no duration, so attribution is impossible

The tool_calls table records timestamp, args_chars, result_chars, and is_error, but no duration. End-to-end task time therefore cannot be split into model time, tool execution, child critical path, coordination wait, and compaction. Every latency question has to be reconstructed from message timestamps, which is exactly why the idle-versus-work correction on this page was needed. verified by source reading.

6. Event-loop stalls and a sleep-counting bug

29,777 ui.loop-blocked events since Jun 16, present in both windows. The watchdog compares a 250 ms timer against monotonic time, which keeps advancing during system sleep, so a suspended laptop is recorded as one enormous stall. That is where the 4,379,642 ms event came from. Both the chronic stalls and the false measurement are worth fixing, and the second one is a few lines. verified by source reading.

7. Failure taxonomy is stable and provider-driven

3.2 percent of all 520,183 calls errored. Usage limits dominate, and 48 bursts of three or more consecutive usage-limit failures were recorded, totalling about 4,090 s of wasted call time. Errored calls fail fast, so they cost step count and retries more than raw latency. verified

8. Runtime cap is per invocation, not per session

task.maxRuntimeMs is set to 30 minutes locally and is armed per runSubagent call, not across a child's whole life. A child that parks and resumes gets a fresh timer each turn, which is why session spans reach two hours with only 7.8 percent of that span in active model time. There is also no cumulative cap on children per parent run. verified by source reading.

Confounders and limitations

Corrections to the earlier summary

Earlier claimVerified finding
14,489 ui.loop-blocked events, recent window only29,777 events total; 14,620 in the prior window, 3,035 recent, 11,952 on Jul 29–30
Instrumentation activated in the recent windowPresent from Jun 16 onward; earlier count missed gzipped rotations
Launch timing from 150 events, p90 345 ms1,064 events; p90 521 ms prior, 206 ms recent, 3,540 ms live
Event-loop stalls framed as a recent driverChronic in both windows; only the live tail is exceptional
Child session p90 +277.4% (11.0 → 41.6 min)That span counted parked idle time. Work time p90 rose 9.9 → 19.1 min (+92.4%); active model time 6.4 → 12.5 min (+95.3%)
Subagent task p50 +90.6%, p90 +248.5%Work time p50 +79.5%, p90 +170.1% after clipping gaps over 5 minutes
Child sessions exceed the 30-minute maxRuntimeMs capThe cap is per invocation, not per session; long spans are parked-and-resumed children, 7.8% active
Fan-out, per-call latency, coordination density, context, work-volume, and error metrics were all reproduced independently and stand unchanged. The direction of every conclusion holds; two magnitudes were overstated and are corrected above.

Next steps

Group 1 is local configuration you can change today. Group 2 is upstream work in the harness source, with file targets from a read-only source audit.

Group 1 — local OMP config

#SettingNowChange toWhy, from the data
1process hygiene39 omp, 20 over 24 hclose stale sessions, then restartLive launch p99 145.7 s and swap at 35.3 / 36.0 GB. Biggest immediate win, no config edit.
2task.softRequestBudget200 (force-stop 300)60-80Child calls p50 36, p90 85. The current budget never fires, so a runaway child is only stopped at 300 requests.
3task.maxRuntimeMs1,800,000600,000-900,000Per-invocation cap. 30 min is far above child work-time p95 of 1,620 s, so it rarely bounds anything.
4task.agentModelOverrides.session-evidence-auditorgemini-3.6-flash:lowa mid-tier reasoning modelThis exact route produced two wrong log figures in this investigation. Evidence work needs care, not speed.
5scout routingflash:lowkeepFlash subagent duration p50 1.43 s versus 5.59 s for sol. Correct for discovery; keep reasoning models off scouting.
6advisor.enabledfalsekeep falseAdvisor was 27.4 percent of all calls and 6.42 B tokens over six weeks.
7session hygiene per taskp50 176k ctxnew session past ~200kSame model, TTFT p50 2.22 s at 50-100k versus 6.98 s at 250k+. 32.8 percent of calls already run above 200k.
8task.maxConcurrency4keep 4Concurrency is not the problem; cumulative dispatch count is. Keep the cap and limit total waves by habit until a budget exists upstream.
9dispatch habitp90 32.6 childrenstop at ~10 per taskNo duration benefit measured between 3 and 10 dispatches; past 11 the median doubles.

Group 2 — upstream contributions

Repository targets verified by reading the source. Tagged by whether they address the recent regression or a long-standing defect.

#ChangeTargetClassEvidence
1Record tool-call duration; add a per-turn attribution breakdown (model, tool, child, wait, compaction)packages/stats/src/db.ts, parser.ts, meta key tool_calls_v2chronicNo duration column exists today, so no latency question can be answered without reconstruction
2Ignore suspension in the loop watchdog: compare monotonic delta against wall-clock delta, or drop samples over ~30 spackages/tui/src/loop-watchdog.tschronic4,379,642 ms recorded as one stall; 29,777 events total pollute any trend
3Cumulative child and wave budget per parent run, not just a concurrency semaphorepackages/coding-agent/src/task/index.ts (TaskTool.execute), semaphore at ~line 620regressionp90 children per run 19 → 32.6; duration doubles past 11 dispatches
4Make task.maxRuntimeMs session-scoped as well as per invocation, or add a separate session cappackages/coding-agent/src/task/executor.ts ~line 1118chronicTimer re-arms per turn; spans reach 2 h at 7.8 percent active
5Apply the artifact spill threshold to read as it already applies elsewhere; make the cap uniform and configurablespill wrapper at packages/coding-agent/src/sdk.ts ~line 2519chronicgrep/search/hub clamp near 51k with zero exceptions; read reached 460k in one result
6Convergence guard: detect repeated verify/repair loops and force a wrap-up before request budget exhaustionsoft budget machinery in executor.ts (SOFT_REQUEST_BUDGET, buildBudgetNotice)regressionWeek of Jul 15: median 151 main calls per subagent task, p90 209 min
7Batch terminal, log, and session-append work off the render path; add backpressure during heavy subagent activitypackages/tui render path; native offload seam in crates/pi-nativeschronicStalls in both windows; live p90 3.37 s with 908 events over 5 s
8Prefetch or warm the launch path so modelRegistry.refresh() and SessionManager.open() do not sit on the critical pathexecutor.ts ~lines 2583 and 2697regressioninvoke-to-first-chat p90 521 ms historically, 3,540 ms and p99 145.7 s under pressure
9Latency-aware routing defaults per agent role using existing catalog metadatapackages/coding-agent/src/config/model-resolver.ts, packages/catalog/src/models.jsonchronicCatalog already carries contextWindow, cost, and reasoning fields; nothing consults measured latency
10Per-child context budget and cheaper repeat compaction; surface compaction cost in telemetrypackages/coding-agent/src/session/session-maintenance.ts (PRUNE_CACHE_WARM_SUFFIX_TOKENS at line 141)chronicMain p50 context 175.6k across the whole period; observed compactions at 231k-318k
11Retain one rolled log per day per PID so warning trends survive; today stale pruning keeps only five files globallypackages/utils/src/logger.ts (pruneStaleProcessLogs, RETAINED_STALE_LOG_FILES)chronicJul 12-27 retained almost no log content, making counts untrendable
12Propagate cancellation to child processes and reap orphans when a parent diespackages/coding-agent/src/task/executor.ts, task/index.tschronic20 omp processes older than 24 h alongside 35.3 GB swap
Items 1, 2, 5, and 11 are small and self-contained. Items 3, 4, 6, and 12 change orchestration semantics and need tests plus a maintainer conversation before any patch. Source claims above come from reading the named files; behavior under load was not re-executed. inference on expected effect sizes.

Prioritized actions

Immediate, no code changes

  • Close stale OMP sessions. 20 of 39 processes are older than a day. Highest expected gain per effort.
  • Restart OMP and the terminal host afterwards; if swap stays near 35 GB, reboot to clear compressed state.
  • Start fresh sessions for unrelated work rather than extending sessions already past ~200k context tokens.
  • Route scouting and mechanical collection to a fast model; reserve gpt-5.6-sol and Opus for correctness-critical slices.
  • Use subagents only for genuinely independent slices. A single spawn followed by idle waiting is slower than doing it inline.
  • Keep active fan-out at 2–4. Extra waves add coordination traffic and context, not throughput.
  • Do not poll hub. Dispatch, continue other work, and let completion deliver.
  • Watch the Jul 15 pattern: 151 median main-agent calls per task signals a verification loop that is not converging.

OMP fixes, ranked by measured evidence

#FixEvidenceExpected effect
1Instrument task critical path: active model time, tool time, child critical path, coordination wait, compaction, host snapshotAttribution currently requires reconstruction from timestampsMakes regressions detectable in days, not weeks
2Strictly event-driven subagent completion; no periodic status, wait, or log pollingCoordination density +100.5%; median 4 waits per subagent taskRemoves waiting from the critical path
3Session-level child and wave budget, not just concurrency capp90 fan-out 19 → 32.6; p95 36 → 45.8Bounds worst-case task time
4Convergence guard on repeated verify/repair loopsJul 15 week: 151 median calls, p90 209 minPrevents runaway task expansion
5Batch terminal and subagent output off the UI thread29,777 stalls; live p90 3.37 s, worst 73 minRestores local responsiveness
6Complexity-aware routing defaults per subagent roleFlash 1.43 s vs sol 5.59 s subagent p50Cuts latency on discovery work
7Warn on stale process accumulation and descendant RSS39 processes, 35.3 GB swap, live launch p99 145.7 sPrevents silent host degradation
8Worker poolingLaunch p95 ≤ 521 ms historicallyLow priority; does not explain minute-scale loss
Bottom line. Provider latency did not broadly regress. OMP started doing roughly twice the work per task — more turns, more tool calls, more coordination waits, wider fan-out tails, heavier contexts — and the workstation is now compounding that with severe memory pressure. Ordinary tasks feel somewhat slower and much less predictable; subagent tasks became categorically slower end to end.