# Your codex exec is wasting ~900 ms per turn. I measured where.

> Source: <https://dev.to/praveenvijayan/your-codex-exec-is-wasting-900-ms-per-turn-i-measured-where-1iip>
> Published: 2026-08-24 16:04:51+00:00

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.

Codex 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.

Ten short turns, same Rust engine, wall clock on my machine:

```
10 turns total          telemetry on    telemetry off
process per turn.         12.5 s          0.76 s
one process, kept up      1.6 s           0.31 s
```

Read it down: the persistent-process design wins in both columns. Read it across: something is eating a second per process.

The surprise

Every 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.

The fix for stock codex, no fork required:

```
# ~/.codex/config.toml
[otel]
metrics_exporter = "none"
```

Prompt comes back as soon as the answer does.

The 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.

Bun'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.

And 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.

The 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:

→ [Read the full article on Substack](https://praveenvijayan.substack.com/p/i-rebuilt-the-codex-cli-harness-on)

Code, 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
