{"slug": "your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where", "title": "Your codex exec is wasting ~900 ms per turn. I measured where.", "summary": "A developer rebuilt the JavaScript harness of OpenAI's Codex CLI on Bun and found that a telemetry exporter adds about 900 ms per turn, which can be disabled with a config line. The persistent-process design delivers significant speedups on both Bun and Node 22, and the toolchain benefits include faster test startup and install times.", "body_md": "I spent a weekend rebuilding the JavaScript harness of OpenAI's Codex CLI on Bun. I expected a runtime story. I got an architecture story — and one config line you can use today without touching my fork.\n\nCodex is a Rust engine with a thin JavaScript layer on top: an npm launcher, a TypeScript SDK, and a pnpm/jest/tsup toolchain. I swapped that layer to Bun, added a client that keeps one codex app-server process alive instead of spawning a fresh process per turn, and measured everything with hyperfine and mitata, p50 and p99.\n\nTen short turns, same Rust engine, wall clock on my machine:\n\n```\n10 turns total          telemetry on    telemetry off\nprocess per turn.         12.5 s          0.76 s\none process, kept up      1.6 s           0.31 s\n```\n\nRead it down: the persistent-process design wins in both columns. Read it across: something is eating a second per process.\n\nThe surprise\n\nEvery release build of codex enables a telemetry exporter that debug builds silently disable. It flushes metrics over HTTPS while the process shuts down. Your answer prints, the turn is done — and the process lives ~900 ms longer to upload metrics. Spawn a process per turn, and you pay it per turn.\n\nThe fix for stock codex, no fork required:\n\n```\n# ~/.codex/config.toml\n[otel]\nmetrics_exporter = \"none\"\n```\n\nPrompt comes back as soon as the answer does.\n\nThe multi-turn win is not a Bun result. I ran the same client through the built package under Node 22: identical numbers. The architecture — one long-lived process speaking JSON-RPC instead of a spawn per turn — delivers the win on either runtime.\n\nBun's own wins are in the toolchain: test startup 1.2 s → 22 ms, warm install 1.4 s → 13 ms, the JSON-lines parser ~2x faster on unchanged code.\n\nAnd one number went the wrong way before it went right: generated protocol types blew the published package from 61 KB to 475 KB. Rolling the declarations into a single tree-shaken index.d.ts brought it to 75 KB — without hand-writing a single type. There's a CI gate now so it can't creep back.\n\nThe complete article has the sequence diagrams, the p99 tables, the lifecycle story (what happens when the persistent process crashes mid-turn), the second exit-tax I found after telemetry (MCP session teardown), and the parts where my first conclusions were wrong:\n\n→ [Read the full article on Substack](https://praveenvijayan.substack.com/p/i-rebuilt-the-codex-cli-harness-on)\n\nCode, benchmarks, and the runnable side-by-side demo: github.com/praveenvijayan/codex, branch bundex-bench — bench/demo-turns.mjs reproduces the table above in two commands", "url": "https://wpnews.pro/news/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where", "canonical_source": "https://dev.to/praveenvijayan/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where-1iip", "published_at": "2026-08-24 16:04:51+00:00", "updated_at": "2026-08-24 16:13:47.719823+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-infrastructure"], "entities": ["OpenAI", "Codex CLI", "Bun", "Node 22", "Praveen Vijayan"], "alternates": {"html": "https://wpnews.pro/news/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where", "markdown": "https://wpnews.pro/news/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where.md", "text": "https://wpnews.pro/news/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where.txt", "jsonld": "https://wpnews.pro/news/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where.jsonld"}}