Which model actually answered your coding agent, from your own machine.
npx --allow-git=root github:agentwares/which-modelThe picture is the real output of npx --allow-git=root github:agentwares/which-model demo, which runs on
synthetic history generated for the demo, not anyone's usage. It is regenerated by pnpm screenshot
and a test fails if it drifts from what the CLI prints.
which-model reads the transcripts Claude Code and Codex already keep on your machine and tells you:
- which model answered Codex, as far as Codex records it: its rollouts name only the model it requested, so which-model reads the one place Codex writes the model the server reported, its own log, and lists a Codex reroute only where that log shows one (see below);
- which models answered, by day and by session;
- switches nothing you did explains: a Claude Code session whose responses moved to another
model with no
/modelfrom you, and what the transcript records just before it (a fallback notice the client wrote, a client update, or nothing), plus how many responses and hours the other model then served; - the reasoning-token distribution per model, with spikes at fixed values such as the 516 / 1,034 / 1,552 clusters people found in Codex;
- step changes in reasoning tokens per response, tokens per task, the largest prompt of the day and Claude Code's auto-compaction point, and every change in the context window Codex reports, with the date and the client version where each starts.
It is MIT, makes no network request, has no telemetry and needs no account. Its output holds model ids, client versions, dates, counts and session ids, never a prompt, a response, a file path or a project name, so you can paste it into an issue as it is.
npx --allow-git=root github:agentwares/which-model # all history on this machine
npx --allow-git=root github:agentwares/which-model --since 30d # or --since 2026-07-01, --since 12w
npx --allow-git=root github:agentwares/which-model --session 1a2b3c4d # one session in order (any unique prefix of its id)
npx --allow-git=root github:agentwares/which-model --client claude-code # or codex
npx --allow-git=root github:agentwares/which-model --json # the whole report, machine-readable
npx --allow-git=root github:agentwares/which-model demo # the report on synthetic history (reads nothing of yours)Also --claude-dir, --codex-dir, --no-cache and --quiet.
| Client | Where | Model it writes | Also read |
|---|---|---|---|
| Claude Code | ~/.claude/projects/**/*.jsonl (or $CLAUDE_CONFIG_DIR/projects) |
message.model: the model that answered each response |
output_tokens_details.thinking_tokens; isSidechain/agentId (subagents); your /model output; model_refusal_fallback notices; compact_boundary points |
| Codex CLI | ~/.codex/sessions/** and archived_sessions/ (or $CODEX_HOME) |
turn_context.model: the model it requested, never the answer's |
reasoning_output_tokens; model_context_window; a model_reroute event, should a version ever write one to a rollout |
| Codex's log | ~/.codex/logs_*.sqlite (read-only; Node 22.13 or later) |
server reported model X, and while requested model was Y |
only those lines: the two model ids, the time and the thread id |
Checked on 8 October 2026 against Claude Code transcripts written by 2.1.170–2.1.286, Codex
rollouts written by 0.144–0.159 and Codex's source at
rust-v0.162.0, reading key names, model ids,
counts and dates only. The usage, models, versions and sessions come from
seatledger's readers, which which-model depends on
rather than copies; which-model adds only the fields in the last column. The Claude Agent SDK
writes its sessions into the same transcripts as Claude Code (entrypoint sdk-ts, sdk-py or
sdk-cli), so they are read and counted the same way.
Three things follow:
- A Claude Code reroute is visible: the model field changes between two responses of one session. Subagents run on their own models by design, so only the main thread counts. The same holds for the Claude Agent SDK's sessions.
- A Codex reroute is not visible in a rollout. Codex 0.162.0 has a reroute event
(
model_reroute: the model requested, the model that answered, and the reason,high_risk_cyber_activity), but its rollout policy drops it as transient. What Codex keeps is one log line per turn in its log database:server reported model X (matches requested model), or, when they differ,server reported model X while requested model was Y. which-model reads only those lines, keeps their model ids past Codex's pruning, and lists a reroute only where one is logged. When the log has none, or cannot be read, it says so. - The OpenAI Agents SDK keeps no local log by default: its default exporter sends traces to
OpenAI's dashboard (
@openai/agents0.20,openai-agents0.23), so there is nothing to read.
- Claude Code documents that a session can fall back to another model, and shows a notice naming both models when it does (model configuration). Recent versions improved that notice (2.1.286: it says when a fallback dropped the context window from 1M to 200K tokens). There is no documented per-response label of the model that answered, and nothing that counts how long a session stayed on the other model. anthropics/claude-code#78888 (18 July 2026, open on 8 October) asks for a persistent indicator.
- Codex records the model it requested and the context window it was given in its rollouts. It checks the model the server reports on every turn, warns you when it differs, and logs that line to its own log database, which it prunes; it writes no answering model to a rollout.
which-model adds the history: when, on which version, for how many responses, across every session on the machine.
- A switch is two consecutive main-thread responses in one Claude Code session answered by
different models. It is labelled by what the transcript records between them: your
/model(not listed as a finding), a fallback notice, a client relaunch on another version, or nothing. "Nothing recorded" is not proof of a reroute: a model picked in a way the transcript does not record looks the same, and the output says so. - Answered by a different model than requested counts responses after a requested model is
recorded (your
/model, or a fallback notice's original model) whose model differs from it. - A reasoning spike is an exact count of at least 64 tokens that holds at least 1% of a model's responses (and at least 10) and at least 8x the average count of the values within 5% either side. It is consistent with a cap or budget at that value; it cannot show that reasoning was cut short.
- Step changes use seatledger's rolling baseline (
detectSteps, the method behindseatledger rates): complete days with at least 20 responses, the median of up to 7 active days before against up to 7 from the day, at least 30% apart, three quarters of the days on their own side, and more than 3x the day-to-day spread. Each says what moved and what it is consistent with, and whether it started on the first day of a new client version. It never names a cause: it sees your machine, not the vendor's servers.
- openai/codex#30364, opened 27 June 2026: a user aggregated Codex's own token metadata and found gpt-5.5 reasoning output clustered at exactly 516, 1,034 and 1,552 tokens. Closed as completed on 23 August 2026; later comments ask why. 289 👍 and 188 comments on 8 October.
- anthropics/claude-code#78888, opened 18
July 2026: after a fallback notice a session moved from
claude-fable-5toclaude-opus-4-8for about 840 messages over about 23 hours while the UI still showed Fable 5, found from the transcripts' per-message model field. Open on 8 October. - openai/codex#32806, 13 July 2026: the context window Codex reported for gpt-5.6-sol fell from 353,400 to 258,400 tokens.
- anthropics/claude-code#83510, 3 August 2026: a measured quality-regression report that includes under-disclosed fallback from Fable 5 to Opus 4.8. #68780, 16 June 2026: a reasoning-degradation report on Opus 4.8 and 5.
Each was found by hand from the same fields which-model reads.
which-model is one machine. seatledger's
hosted team ledger shows the whole team's model mix, by model and by day, free for up to 3
developers. After the human output a terminal shows one dim line pointing there, at most once a
day per machine, never with --json or --session. --quiet or WHICH_MODEL_QUIET=1 turns it
off. It is text printed on your screen: nothing is sent.
- Writes only to
~/.which-model(or$WHICH_MODEL_HOME):cache-v1/(seatledger's counts per transcript),signals-v2/(reasoning counts, model ids, each session's entrypoint and the times of model changes and fallback notices per transcript),codex-served-v1.json(the model ids, times and thread ids of Codex's "server reported model" lines, kept past Codex's pruning) andhint.json(the day the team line was last shown). The caches mean a second run reads only what changed, and keep history the clients have since deleted. Delete the directory to forget it. - Never stores or prints prompt, response, tool or file content.
import { collect, analyze, whichModelHome } from "which-model";
import { sourceDirs } from "seatledger";
const input = await collect({ dirs: sourceDirs(), home: whichModelHome(), now: Date.now() });
const { switches, reasoning, steps, windows } = analyze(input);pnpm install && pnpm test
node dist/cli.js demo
pnpm screenshot # regenerate docs/screenshot.svg after changing the output
pnpm icon # redraw the plugin icon after changing distribution/icon.svgMIT © agentwares contributors.