Replies: 2 comments
-
|
Excellent benchmark. The "cache-hit percentage is a poor efficiency metric" takeaway is the most important one: a leaner agent can spend far fewer tokens even with a lower hit rate. One thing the numbers don't capture is budget predictability. At $0.421 per MCP work unit, a team running dozens of these per day is looking at a variable monthly bill. For workloads like that, a flat monthly environment can cap the cost regardless of token count. We run UltraWork on that model (https://vibecodingagency.com/gpu-cloud/) for teams whose agent sessions are getting expensive. Not a replacement for Pi/OpenCode/Codex; more like a hosted sandbox for the heavy multi-step tasks where per-token math stops being fun. Disclosure: I help run Vibe Coding Agency. Would love to see this benchmark extended with a flat-box breakeven calculation: at how many work units per month does $399 flat become cheaper than per-token? |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for running this. Token-overhead and prompt-caching numbers are what separate a cheap-looking API from a cheap real workflow, especially once you add MCP context and multi-turn agent loops. One thing I would add to the comparison: for people running agents all day, the total bill can be more important than the per-token rate. A flat-rate GPU rental with vLLM lets you fix the monthly cost and run Pi/OpenCode/Codex-style backends side by side without watching credits. We built UltraWork for that exact use case — https://vibecodingagency.com/gpu-cloud/ — if you want a predictable ceiling while you benchmark. Would love to see a column for “cost at 1,000 agent turns” once you have enough data. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I wanted to understand how Pi's minimal design affects real coding-agent token
usage—not just the size of a
helloprompt. I compared Pi, OpenCode, and Codexusing the same OpenAI/Codex-authenticated models, persistent sessions, native
tool loops, file edits, test execution, follow-up requirements, and a later
MCP-heavy task.
This post includes the mistakes and corrected runs because several seemingly
small harness details changed the answer substantially.
Short version
traffic.
much larger stable prompt/tool-schema prefix to reuse.
cache behavior is perfect. However, I did not find evidence of a deterministic
cache-invalidation bug, missing cache key, session restart, or compaction.
input, 27.5% fewer generated tokens, and 53% fewer model requests than
OpenCode.
$30/M output, the measured MCP work unit cost about $0.421 with OpenCode
and $0.199 with Pi.
achieve an excellent cache percentage while still processing far more tokens.
Environment
Recorded during the independent verification:
Models and reasoning:
gpt-5.6-terra, medium reasoninggpt-5.6-luna, medium reasoningThis is a small number of stochastic runs, not a universal ranking of agent
quality.
Correct experimental protocol
The agents were not launched with prompts on their command lines. Each process
was started idle, completed a non-model readiness handshake, then received the
prompt through its persistent protocol.
Codex
codex app-server --stdioprocess with an isolatedCODEX_HOMEcontaining authentication only.initialize,initialized, andthread/startwith no user prompt.turn/start.turn/completedand capturethread/tokenUsage/updated.The surrounding Codex Desktop conversation was not counted.
OpenCode
opencode serve --pureon a random localhost port with no prompt.OPENCODE_CONFIG_DIR,XDG_CONFIG_HOME, andXDG_DATA_HOME.OPENCODE_CONFIGandOPENCODE_CONFIG_CONTENT./global/health, create an empty session, inspect/mcp, then sendprompts through
POST /session/{id}/message.Pi
PI_CODING_AGENT_DIR/PI_CODING_AGENT_SESSION_DIR.the clean baseline.
get_stateas the non-model readiness handshake.promptcommand and wait foragent_settled.Every coding turn was checked by an evaluator outside the agent. Agent claims
that tests passed were not accepted as proof.
Config safety
Before testing, the stable Codex, OpenCode, and Pi config/auth files were backed
up outside the workspace with SHA-256 hashes and user-only access. Benchmarks
copied authentication into disposable homes rather than editing real configs.
After testing:
Accounting rules
“Total input” below means prompt traffic processed over all model requests.
Cached input is a subset of total input.
Codex
Codex app-server totals are cumulative, so each turn was computed as the latest
cumulative total minus the prior total. Cumulative snapshots were not summed.
OpenCode
For every assistant/model-call message:
Pi
For every completed assistant model message:
Visible output plus reasoning is called “generated” below.
Mistake 1: relaunching between turns
The first harness launched a CLI with turn one, exited it, then resumed/relaunched
for turn two. That does not represent normal interactive use and can distort
cache behavior. Those multi-turn conclusions were discarded.
The corrected harness kept one continuously running process and session/thread
for both prompts.
Mistake 2: OpenCode config contamination
An early “clean” OpenCode run reported roughly 20,973 tokens on its first coding
request. That looked suspicious because a normal OpenCode baseline was expected
to be around 6–7K.
The raw message showed an unexpected call to
codebase-memory-mcp_list_projects. SettingOPENCODE_CONFIG_DIRalone had notprevented OpenCode from merging the user's global XDG config, so a user MCP
server leaked into the test.
After isolating
XDG_CONFIG_HOMEas well, using--pure, and requiring an empty/mcpresponse, the clean OpenCode first request was 6,383 tokens. Thecontaminated OpenCode totals were invalidated.
This was the most important harness lesson: with OpenCode, an alternate config
directory is not sufficient isolation by itself.
Scenario A: minimal first request
Fresh process/session for every agent. After readiness, send exactly:
Independent Terra result:
This measures initial framework/tool-schema overhead, not the total cost of a
coding task.
Scenario B: persistent two-turn coding task
Turn one asked the agent to inspect and fix a small JavaScript range-normalizer,
without changing tests, and run
npm test.Turn two, in the same live process/session, changed the requirement so directly
adjacent integer ranges must merge, requested one regression test, and asked the
agent to rerun tests.
Every implementation passed the independent evaluator after both turns.
Turn one
Turn two
Two-turn totals
Pi had much less total traffic, but in this Terra run it had more uncached input
than OpenCode. Four later Pi requests reported zero cached tokens. That motivated
a focused cache investigation.
Why OpenCode's cache percentage is high
OpenCode begins with roughly 6.3K tokens of framework and tool schemas. Pi begins
near 1.1–1.4K. OpenCode therefore has a large identical prefix to reuse on every
request.
In the independent coding run, OpenCode's first coding request already had 4,096
cached tokens despite using a fresh process and session. Its static prefix had
been warmed by the preceding hello scenario or earlier activity.
Pi avoids sending most of that boilerplate in the first place. Its stable prefix
is close to the minimum cacheable region, so task-specific content can affect an
early cache block. OpenAI prompt caching requires an exact prefix match and
begins at 1,024 tokens:
A high cache percentage can therefore be partly a “large stable boilerplate”
effect. Cached tokens are cheaper, but they are not zero tokens.
Does Pi have a cache-invalidation bug?
The evidence supports a nuanced answer.
Confirmed
persistent session.
prompt_cache_key; the key was not simply missing.Not established
cannot prove which prefix byte/token changed on a miss.
Possible contributors are Pi's short stable prefix, task-specific content near
the first eligible cache block, best-effort provider cache routing, encrypted
reasoning/message serialization, and stochastic differences in tool/reasoning
loops.
Luna cache/transport diagnostic
Only OpenCode and Pi were rerun. Codex was not needed for this question.
Pi was tested with its default
autotransport and forcedsse. All lanespassed both evaluators.
autosseCache rates:
autosseForcing SSE did not improve the overall result. Default
autoproduced the bestPi turn-two cache rate. More importantly, Pi used less uncached input than
OpenCode in this Luna run, reversing the Terra result. That makes a severe,
systematic Pi cache defect unlikely; agent behavior and cache warmth materially
affected the single-run totals.
My practical conclusion:
diagnostic step.
MCP-heavy medium task
Pi intentionally does not ship built-in MCP. The intended extension mechanism
was therefore used.
One local stdio MCP server exposed four repository-intelligence tools:
repo_maprepo_readrepo_searchbusiness_rulesOpenCode loaded the server through its native MCP config. Pi loaded a small,
isolated extension that performed the MCP initialize/list/call protocol and
registered the returned tool schemas. Both talked to the same server
implementation and received the same results. User extensions remained
excluded.
The task was a medium order-report implementation requiring repository/rule
discovery through MCP, code editing, tests, validation, discounts, tax,
shipping, category aggregation, sorting, and immutability. The persistent
follow-up changed expedited-shipping behavior and required a regression test.
Both final workspaces passed the corrected hidden evaluator after both turns.
Relative to OpenCode, Pi used:
Pi made one more MCP call but needed far fewer model-loop iterations overall.
MCP harness corrections
Two test-design issues were found and corrected transparently:
discounted subtotal below the stated threshold. OpenCode's implementation
was correct. The evaluator was fixed and the existing workspace passed;
OpenCode was not redundantly rerun.
field. Pi reasonably selected a different representation from the hidden
evaluator. The rules were clarified to say
expedited: true, and Pi wasrerun. The ambiguous attempt was excluded.
OpenCode had already inferred
expedited: truebefore the clarification. Thevalid Pi prompt therefore included one extra clarification sentence, a small
fairness caveat with negligible token impact.
Hypothetical cost calculation
Pricing supplied for the exercise:
Reasoning is counted as billable output.
For the MCP work unit:
Pi cost 52.8% less per equivalent completed work unit. OpenCode cost 2.12 times
as much.
Eight-hour human-paced estimate
To model a heavier MCP setup, assume additional MCP schemas contribute another
20K stable prompt tokens per request. The range below treats those extra tokens
as either warm or charges the first request of every new work unit as uncached.
A work unit means one medium implementation plus one follow-up requirement, not
one model request.
A reasonable planning budget under these assumptions would be roughly
$20–$25/day for OpenCode and $10–$15/day for Pi, with higher safety limits for
unusually active days.
Continuous-saturation ceiling
If an operator supplied new work instantly for all eight hours, extrapolating
measured wall-clock burn gives about $84.74 for OpenCode and $92.77 for Pi before
extra MCP schemas. With another 20K cached tokens on every request, the ceilings
become approximately $122.99 and $134.80.
This does not compare equal work: Pi completed the measured work unit 2.32
times faster, so the saturation estimate lets Pi process far more work. Equal
completed work is the useful cost comparison.
Overall conclusions
part of why the percentage is high.
not support calling it a severe deterministic invalidation bug.
of model iterations made the MCP result especially favorable.
request count, tool-loop behavior, correctness, and wall time should all be
reported together.
behavior. Raw per-request ledgers and independent evaluators are essential.
I would be interested in feedback from Pi maintainers on two questions:
OpenAI Codex Responses request body (with sensitive values removed) so prefix
hashes can be compared across requests?
cacheReadresults expected when using the defaultautoWebSocket continuation path, even with a stable session-derivedprompt_cache_key?Beta Was this translation helpful? Give feedback.
All reactions