--low-token cost benchmark — a controlled comparison between default and low-token modes on ZO’s canonical MNIST end-to-end reference run.
Status: measured on 2026-04-27 against the canonical MNIST plan. Result: low-token mode landed at $7.75 end-to-end (Sonnet lead $4.48 + Sonnet sub-agents $3.27, captured via
npx ccusage --instances) vs. the historical default-mode reference of ~$11. That’s a ~30% reduction, not the 70-80% projected before measurement. The structural reason is below — see Why the savings ceiling is structural. The earlier 70-80% projection assumed every agent would swap from Opus to Sonnet; in practice only the lead is Opus by default (sub-agents already run on Sonnet via their .md frontmatter), so --low-token only affects the lead’s ~30-40% cost share.Why benchmark MNIST
MNIST is ZO’s canonical reference because:- Stable oracle — the must-pass tier (95% test accuracy) is well within the architecture’s capability
- Six full phases — exercises Phase 1 (data) through Phase 6 (packaging), the full lifecycle
- Phase-4 iterations matter — non-trivially, the autonomous loop matters for cost
- Reproducible — the plan, data, and oracle don’t drift between runs
- Documented baseline — session-005 gave us a precise cost ($11) and wall-time (~50min) anchor point
Methodology
The benchmark runszo build against the MNIST plan twice in identical environments:
- Default run —
zo build plans/mnist-digit-classifier.md— Opus lead, max-iterations 10, supervised gates auto-PROCEED-ed via--gate-mode full-auto - Low-token run —
zo build plans/mnist-digit-classifier.md --low-token— Sonnet lead, 2 iterations, full-auto gates, no headlines
--gate-mode full-auto so the only differences are the low-token knobs themselves. Results are logged to ~/.claude/projects/*.jsonl; per-session totals are extracted via npx ccusage --json (one of ZO’s planned optional integrations).
Measured dimensions
Controlled variables
- Same machine (Mac M-series, 32GB RAM)
- Same Claude Code version
- Same MNIST plan, unmodified between runs
- Same delivery scaffold (fresh
zo init) - Both runs
--gate-mode full-auto(default would have beensupervisedfor the default-mode run; we override to keep gate behaviour identical)
Run frequency
The benchmark is single-shot per release. Re-running on every PR would cost ~$13 each cycle and provide minimal signal — variance is dominated by stochastic agent decisions, not measurement noise.Measured results (2026-04-27)
First completed end-to-end bench against the MNIST plan, captured vianpx ccusage --instances --since "$(date -u +%Y%m%d)":
The headline number — 30% — is materially smaller than the 70-80% projected before measurement. The next two sections explain why.
Why the savings ceiling is structural
The earlier 70-80% estimate assumed--low-token would swap every agent from Opus to Sonnet (~5× cheaper per token), so the savings would be ~80% across the board.
That assumption was wrong. Default mode never had every agent on Opus:
So
--low-token only affects the lead’s cost share (~30-40% of total). At ~5× cheaper-per-token on Sonnet, that’s a ceiling of ~25-30% savings on the total — which is exactly what we measured.
The original projection extrapolated the per-token ratio (5×) to the whole run. The whole run was already mostly Sonnet. There was no 5× savings hiding in the sub-agents because their cost rate wasn’t changing.
What --low-token actually moves
The 30% breaks down across the preset’s seven knobs:
For plans that hit the iteration cap on default mode (harder problems), the iteration knob would matter more. MNIST is too easy — it converges in iteration 1, so the cap → 2 saving is essentially zero.
What would push savings higher
The first bench measured ~30% with the lead-only swap. Two additional levers shipped post-bench target a ~50-60% ceiling without an SDK refactor; three further architectural levers target ~70-80%.Shipped post-first-bench (target: ~50-60%)
A second bench post-PR-C is required to confirm whether the 50-60% target is hit. The headline number on this page updates when that bench lands.
Architectural — not yet shipped (target: ~70-80%)
To break past the ~50-60% ceiling, the path forward requires moving ZO fromclaude CLI subprocess to direct Anthropic SDK so ZO can control caching, batching, and file uploads programmatically:
The 70-80% figure was always achievable — just not via the v1 preset alone. The SDK refactor is multi-week and lands in v1.1.
Findings from the first measured run (2026-04-27)
Beyond the headline cost number, the first bench surfaced material findings: Confirmed working:- Lead orchestrator runs on Sonnet under
--low-token.ps auxduring the run showedclaude --model sonnet --max-turns 200for the lead. - Sub-agent model override works. All three spawned sub-agents (data-engineer, code-reviewer, test-engineer) ran on
claude-sonnet-4-6perps aux. The orchestrator’s_prompt_low_token_overrides()instruction to passmodel="claude-sonnet-4-6"to everyAgent()call is honoured by Claude Code 2.1.107. The earlier “Claude Code 2.1.92 ignores the param” hypothesis is no longer load-bearing — either the bug was version-specific or the prompt-level override always was sufficient. No SDK refactor needed for this piece.
zo watch-trainingrendered “Waiting for training to start…” for the entire run despite training completing at 98.83% test accuracy. Three stacked contract violations: (a)model-builder.mdhad two contradictory paths for training metrics (.zo/experiments/<exp_id>/vslogs/training/); (b)wrapper.pyandcli.py:watch_traininghardcoded the wrong path; (c) the Phase 4 gate was aspirational — only checkedresult.md, not the actualZOTrainingCallbackartifacts. Sonnet (low-token) ignored both contradictory instructions and wrote a vanilla PyTorch JSON dump to a third invented path.- Fix shipped: new
resolve_active_experiment_dir()helper as canonical resolver;cli.pyandwrapper.pyconsume it; orchestrator’s gate now hard-fails whenmetrics.jsonlandtraining_status.jsonare missing alongsideresult.md. Captured in PRIORS.md as PR-035: aspirational agent contracts get ignored under sub-optimal models — hard gate enforcement is mandatory.
Caveats and known limitations
-
MNIST is an easy benchmark. The convergence-iteration cap (10 → 2) doesn’t bite on MNIST because the model converges in iteration 1. On a harder problem, the iteration cap matters more — and
--low-tokenmay fail to converge where default would have succeeded. Re-run without--low-tokenifzo statusshowsBUDGET_EXHAUSTED. - Lead model swap doesn’t show MNIST quality regression. MNIST is well within Sonnet’s capability for plan decomposition. On novel research-grade plans, Opus may catch nuances Sonnet misses.
-
Wall-time savings are not all from tokens. ~30% of the wall-time saving comes from skipped human-loop overhead (
--gate-mode full-autodefault in low-token), not from compute savings. If you keep--gate-mode supervised, wall time savings shrink even though token savings remain. - Cost depends on the Anthropic rate card at benchmark time. Pricing changes ripple through the total. The methodology measures token counts primarily; cost in USD is derived.
- Pro-plan caps measure messages, not tokens. Anthropic Pro subscribers hit a daily message cap, not a token cap. Low-token mode reduces both per-message tokens AND total messages (no Haiku ticker, no end-of-session summary). The cap savings are roughly proportional but not identical to token savings.
Reproducing the benchmark
The harness lives atscripts/benchmark_low_token.sh. Usage:
- Runs
zo init mnist-bench-default --no-tmux ...to scaffold a fresh delivery repo - Captures pre-build ccusage snapshot
- Runs
zo buildin default mode + waits for completion - Captures post-build ccusage snapshot — diff = default-mode tokens
- Runs
zo init mnist-bench-low --no-tmux ...for the low-token delivery - Pre-build ccusage snapshot
- Runs
zo build --low-token+ waits - Post-build ccusage snapshot — diff = low-token tokens
- Writes
benchmark-results-{timestamp}.jsonwith the comparison - Prints a summary table