Four Claude models, one workflow

Which model, which job
Opus 4.8 · Opus 5 · Fable 5 · Sonnet 5

Opus 4.8 runs the session. Opus 5 builds. Who’s good at what.

Opus 4.8 orchestrates, Opus 5 builds. The chart sets Opus 4.8 at zero. One catch: Opus 5’s numbers come from when it drove sessions itself, before it stopped too often and deleted too much of its own work. See the two measures that matter.

Of the sixteen underlying measures, Fable 5 leads eight, Opus 5 leads seven, the two tie on one, and Opus 4.8 leads none.

Fable 5 ran 2–20 July and was dropped when a 2× usage promotion ended. Opus 5 became available on 25 July. The two never ran concurrently, and Opus 4.8 was in use throughout. Claude Code offers no configuration in which Opus 4.8 orchestrates Opus 5: across the 3,925 subagents recorded under those two models, none pairs them in either direction.

Appendix

A1 Output against handbacks

Code delivered against handbacks

Edits per session against handbacks per hour, each model across its full corpus.

Per handback: 18.1 edits for Fable, 8.7 for Opus 4.8, 12.0 for Opus 5. Per session: 4.4, 10.7 and 16.0 handbacks.

A2 Handback measures

Handback measures

Bars scale within each row against the largest value in that row.

Sessions of six or more spans, split into thirds, showing the share of dispatching turns that ended while subagents were still running: Opus 4.8 goes 23.5%, 20.7%, 12.0%; Opus 5 goes 34.0%, 35.9%, 34.4%. Fable's median session is 4 spans, so its row rests on 16, 5 and 8 turns and is not usable.

Background wakes absorbed per span across the same thirds fall from 0.79 to 0.44 for Opus 5 and from 0.83 to 0.60 for Opus 4.8.

Per-hour rates in this chart are workload-sensitive: Opus 4.8 records 1.08 handbacks per hour across its full corpus and 2.06 within the 2–20 July window alone. Per-turn ratios are the comparable figures across models.

A3 Dispatch and worker management

Orchestration measures

Per-turn and per-session rates across each model's full corpus.

Turns containing a dispatch: 23.7%, 22.7% and 21.3%. Workers that ran more than one round, meaning the orchestrator went back to them: 9.6% of 477 for Fable, 2.5% of 3,112 for Opus 4.8, 5.9% of 813 for Opus 5.

A4 Production and cost

Coding measures

Per session, main loop and all subagents combined, attributed to the driving model.

Cost measures

All four billable token counters at API list rates, against the model that produced each message.

These sessions ran on a subscription, so cost figures are equivalent API spend rather than amounts billed. Cache reads are the majority of tokens in every case, at 176M, 234M and 491M per session. Subagents did 79%, 76% and 87% of all edits.

Edits, characters and commits count volume. Edit-failure rate, rework ratio and reverts are the available proxies for care. No measure here establishes whether the code was correct.

A5 Definitions, corpus and limits

Four extractors walk raw session transcripts, which are JSONL with one file per session and subagent transcripts nested beneath. Each metric is attributed to the model named in the assistant record, so a session that changed models is split rather than assigned to one.

A span runs from one human message to the next. Three kinds of user record are treated differently: a typed message is a handback; a <task-notification> is a background task waking the session and does not close a span; tool results, hook injections and system reminders are not user turns. Across the corpus, 45% of the wakes that close an assistant turn are task notifications rather than typed messages. Time is charged as work while the model is producing and as wait between its last message and the next human one, with waits over four hours discarded.

CorpusFable 5Opus 4.8Opus 5

Opus 4.8, Opus 5 and Sonnet 5 ran the same weeks, so it’s mostly like-for-like. Fable 5 is sparse; Opus 5 stops after early August. Project mix tracks the model. Turns: 2,709 / 1,816 / 526 / 440.

Every recorded turn ran at high reasoning effort, so that stays uncontrolled. Haiku 4.5 is too rare to include.

Limits

  • Volume is not correctness. Nothing here shows whether the code ran. The survival measure shows only whether it was kept.
  • Project mix rides with the model. Each model worked a different spread of repositories, and that cannot be pulled apart from the model itself.
  • Reasoning effort is uncontrolled. Every recorded turn ran at high; none can be identified at another setting.
  • The Opus 5 column is Opus-5-as-orchestrator. It covers the weeks Opus 5 drove sessions directly. In the current workflow it runs as a worker under Opus 4.8, and its output there counts toward Opus 4.8 sessions.
  • Fable 5 and Sonnet 5 are thin. Both sit near the floor for drawing a line, so read their columns as indicative rather than settled.

A6 Run this on your own logs

The figures above come from four extractors run over raw session transcripts. Rather than distributing them as scripts to execute against a full session history, the specification is given below. Handed to Claude, it produces the extractor and runs it locally.

It fixes the parts that determine comparability: where the transcripts live, what counts as a turn, which regexes are applied, how subagent work is attributed, and the exact JSON shape the charts read.

Measure how different models actually behave in my own Claude Code logs, then build
a metrics.json I can drop into https://3dl.dev/coding-vs-orchestration.html to
redraw its charts with my numbers.

Write the extraction script yourself. Python 3, standard library only, no installs.
Run it, sanity-check the output, and tell me what it says.

── WHERE THE DATA IS ──────────────────────────────────────────────────────────
  ~/.claude/projects/<slug>/<session-id>.jsonl              one JSON object per line
  ~/.claude/projects/<slug>/<session-id>/subagents/**/*.jsonl   subagent transcripts
Each record has: type ("user" | "assistant" | ...), timestamp, sessionId,
isSidechain, message.model, message.usage.output_tokens, and message.content as a
list of blocks typed "text" | "thinking" | "tool_use" (with .name, .input) |
"tool_result" (with .tool_use_id, .is_error, .content).
Transcripts rotate after ~30 days. If I use more than one machine, run this on each
and merge — my laptop held a quarter of what my build box did, and the small slice
gave the opposite answer on two metrics.

── WHAT COUNTS AS A TURN ──────────────────────────────────────────────────────
One human message plus every assistant message before the next human message.
A "user" record is NOT human if isSidechain or isMeta is set, if its content list
contains a tool_result, or if its text begins with "<system-reminder>",
"<local-command" or "Caveat:". Text beginning "[Request interrupted" ends the turn
and marks it interrupted. Attribute a turn to the first assistant model in it.
Skip the model "<synthetic>". Record the "effort" field if present — it is a
confound and I want to be able to filter on it.

── WHAT TO MEASURE ────────────────────────────────────────────────────────────
Per turn: total tool calls and per-tool counts; whether any dispatch tool ran
(Agent, Workflow, Task); and how many tool calls came AFTER the last dispatch.
That last one is the follow-through signal — zero means the turn ended the instant
the workers reported back. Also output tokens, and whether my next message was a
bare nudge ("continue", "keep going", "why did you stop").

On the final assistant text block of each turn — the part a human actually reads —
measure length, words per sentence, unique-word ratio, and per-1000-character
counts of bullets (^\s*[-*] ), headers (^#+ ), bold pairs, table rows (^\|),
backticks and digits, plus regex hits for:
  permission  want me to|should i|shall i|let me know|do you want|would you like|your call
  limitation  i (did not|didn't|have not|can't|cannot)|not verified|out of scope|deferred|blocked|untested
  caveat      caveat|worth flagging|to be clear|note that|heads.up|strictly speaking
  hedge       likely|probably|appears to|seems to|may be|might be|unclear|ambiguous

Per session: how many subagent transcripts were spawned, split into Workflow runs
(subagents/workflows/<run>/agent-*.jsonl — count the runs too, so you can get
agents per wave) versus plain Agent calls, and their total output tokens.

Coding, counted across the main loop AND every subagent beneath it, attributed to
the session's dominant model: Edit/Write calls, characters written, failed tool
results (is_error, or text starting "Error:", or containing "String to replace not
found"), Bash commands matching a test runner, a git commit, or a git revert, and
repeat edits to the same file path (rework). Counting only the orchestrator's own
edits will badly understate a model that delegates its typing — that mistake
reversed one of my conclusions.

── PICK THE MODELS ────────────────────────────────────────────────────────────
Find what is actually in my logs and how much of each:
    grep -ho '"model":"[^"]*"' ~/.claude/projects/*/*.jsonl | sort | uniq -c | sort -rn
Compare the two to four with the most turns. Treat anything under ~300 turns as too
small to draw a line from, and say so rather than quietly including it.

── OUTPUT SHAPE ───────────────────────────────────────────────────────────────
Write metrics.json exactly like this, or the page will not read it:

{
  "corpus": [ {"key":"turns","label":"Turns analysed","unit":"turns",
               "better":"high","note":"","v":{"model-a":3027,"model-b":1370}} ],
  "orch":  [ ... ], "esc": [ ... ], "prose": [ ... ], "code": [ ... ],
  "index": { "code": {"model-a":67.4,"model-b":91.2},
             "persist": {"model-a":83.6,"model-b":60.0} }
}

Five arrays — corpus, orch, esc, prose, code — each a list of metric rows with
key, label, unit, better ("high" or "low", meaning which direction is good), note,
and v mapping each model id to its value. Model keys must be identical everywhere.
Put cold-stop rate, work after last dispatch, agents per wave, subagents per
session, dispatch rate, tool calls per turn, dead turns and worker tokens in
"orch"; the question and phrase-density metrics in "esc"; the writing metrics in
"prose"; the edit and test metrics in "code".

For the two indices: score every model on each metric against the best performer —
100 x value / best where higher is better, 100 x best / value where lower is better
— then take the unweighted mean. "persist" is built from cold-stop rate, work after
last dispatch, agents per wave and subagents per session. "code" from edits,
characters, edit-failure rate, tool-error rate, rework, tests per edit, commits and
reverts.

── THEN TELL ME ───────────────────────────────────────────────────────────────
Which model ends the most delegated turns cold, which writes the most code per
session, and whether they are the same model. Flag every confound you can see:
models used in different months, on different projects, or at different reasoning
effort. Say which comparisons are too thin to trust. If a result contradicts what I
expected, say so plainly — do not smooth it over. Volume is not quality: edits and
commits measure throughput, and nothing here knows whether the code was correct.

About 20 seconds over a couple of gigabytes. The records hold counts, not transcript text, so they are safe to copy off a remote box.

Two shortcuts

Seeing your own numbers on these charts

Drop the metrics.json the prompt produces and every chart on this page re-renders from your file, baseline chart included. The file is read in the browser; nothing is uploaded and no account is involved. The page is complete without sharing anything.

Drop metrics.json or
Charts show the reference corpus: 5,491 turns, 10 Jul – 11 Aug 2026.

Model IDs, legend and colours follow the loaded file. The baseline chart needs fable-5, opus-4-8 and opus-5 in the data; every other chart follows whatever models the file contains.

Sharing them

One operator's logs answer some questions; a distribution across operators answers more. If you are willing to share yours, a community dataset at github.com/3dl-dev/model-telemetry accepts the same file as a pull request, wrapped with a short meta block its skill prepares for you. Submissions are counts only, carry no transcript text or project names, and are licensed CC0. Inclusion in the published aggregate is a separate, allowlist-based curation step recorded in the repository, so what is in and what is out stays auditable. Sharing is optional; the charts above work either way.

The extractors as run

The scripts used to produce the figures on this page. The prompt above generates equivalent output.

A7 Output, and output that lasts

Two measures need a second look. Both are about work that doesn’t stick.

Opus 5 writes the most, keeps the least

Most edits, most characters per session. Also the most stops and the most reverts. That’s why it builds as a worker now, not the driver.

Who has to be pushed

A turn ending right after dispatch might be a clean hand-off or an early quit. The tell: did you have to type “continue”? Per 100 turns:

Times you had to push itFable 5Opus 4.8Opus 5Sonnet 5
nudges per 100 turns, lower is better0.570.811.820.23

Opus 5, two to eight times as often as the rest. Sonnet 5 almost never, but it does the least.

How much of the code lasts

The charts count what a model types, not what it deletes. Characters written then removed the same session (rm, git restore, git revert):

Code killed same-sessionFable 5Opus 4.8Opus 5Sonnet 5
% of written chars killed, lower is better43%27%61%27%
net surviving code, MB per model5.216.310.91.8

Opus 5 writes the most and deletes the most. Net of waste, Opus 4.8 leaves the most standing. Real source, not scratch. Read it as a waste ratio, not line counts.

The summary score still lies

Fold survival in and Opus 5 still tops the code index. Eight of its nine parts are just volume. The rows tell the truth; the score doesn’t.

Sonnet 5 takes the light work

Shortest replies, fewest edits, most do-nothing turns. Too few sessions to rank.

The numbers track the workflow. Opus 5 driving meant more code and less of it kept. It builds better as a worker.