Repository navigation
Closed
Conversation
…okens and honest cost Codex sessions were already noticed — a Bash shell-out to the Codex CLI is detected from inside the Claude transcript — but what that produced was a stub: apiCalls 0, all-zero tokens, cost always $0.00 / "n/a". Nothing had ever read Codex's own record of what the session actually did. This adds a Codex provider that reads Codex's own on-disk stores, the same direction atlas already reads Claude's transcript: it asks nobody to write anything for it. A Codex session now discovers, builds and renders with real turns, real tool calls, a real per-class token breakdown, and a cost computed exactly the way a Claude session's is. - src/providers/codex.mjs — discover/buildTree/refFromPath over Codex's session-metadata and turn stores plus its rollout log - src/providers/index.mjs — a registry dispatching both providers by ref.provider, replacing the direct claude.* calls at 7 sites in cli.mjs and server.mjs - src/providers/node.mjs — the node shape, authored in one place instead of two - src/prices.mjs — a CODEX price table and priceCodex(), sibling to the Claude pricer - thread_spawn_edges is honoured for native Codex-to-Codex nesting; the table is empty everywhere it could be checked, so the empty case is what is proven Cost carries no notion of how anyone is billed. Billing mode is not read, and there is no "subscription" state: list price times tokens when the model has a price row, n/a when it does not — the same two outcomes priceClaude() has always had. What the tokens would cost is the number that transfers to a metered account; what a flat plan happens to charge is not a property of the session. Fixes the $0.00 that read as "free" where it meant "unknown", at all three unconditional money sites — treeTerminal(), the list command, and indexHTML()'s session-list column. The third was not in the original report. A host without Codex is unaffected byte for byte on every machine-readable surface, and node:sqlite stays behind an existence gate so its experimental warning never reaches an existing user.
Owner
Author
|
Superseded by #22, which is now merged and provides the same first-class Codex provider, provider registry, turns, token and cost ingestion, plus the React index-worker integration and the empty-corpus test isolation fix. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15
What was asked
A Codex provider, so Codex sessions are first-class sessions in atlas — their own turns, tools, tokens and cost — the way Claude sessions already are.
The transcript-side detection shipped in #14 already places a Codex node in the tree. What it places is a stub:
apiCalls: 0, all-zero tokens,cost.confidence: "n/a", with the only real number stranded inreported.tokensUsed. Nothing had ever read Codex's own record of what the session did.What changed
src/providers/codex.mjs— new provider.discover()/buildTree()/refFromPath()over Codex's own session-metadata store, its turns/tool-calls store, and its rollout log. Read-only, no network.src/providers/index.mjs— a registry dispatching byref.provider, replacing the directclaude.*calls at the 7 sites incli.mjsandserver.mjs.src/providers/node.mjs— the node shape, authored in one place instead of two.src/prices.mjs— aCODEXprice table andpriceCodex(), sibling to the existing Claude pricer.src/render.mjs,src/cli.mjs,src/server.mjs— the money-rendering fix, below.thread_spawn_edgesis honoured for native Codex→Codex nesting. The table is empty everywhere it could be checked, so the empty case is what is actually proven; the populated case is exercised against a fixture.A Codex session now lists, builds and renders on the same footing as a Claude one, with no provider-specific flag or route.
Cost: a correction to the issue's own premise
The issue asked for a
subscriptionstate that withholds a dollar figure. That is not what shipped, by explicit decision, because it contradicts what atlas already does:priceClaude()has never had any notion of billing mode — it is a pure function of model, timestamp and usage — and subscription-billed Claude sessions have always rendered a plain list-price figure.The useful number is what the tokens would cost, because that is what transfers when the same workload moves to a metered account. What a flat plan happens to charge is not a property of the session.
So billing mode is not read at all, and there is no third state. Cost has the same two outcomes
priceClaude()has always had: a figure flaggedcomputedwhen the model has a price row,n/awhen it does not.The
$0.00fixA cost of exactly
$0.00read as "free" where it meant "unknown". Fixed at all three sites that rendered a money value unconditionally:treeTerminal(), thelistcommand, andindexHTML()'s session-list column. The third was not named in the issue and was found while specifying this.Verification
n/aon live data — one appeared mid-review and is unpriced by design.list --json,tree --json,/api/sessionsand/api/treeare byte-identical to the pre-change tree, with the two scans run concurrently to avoid a false diff on a live corpus.node:sqlitestays behind an existence gate, so its experimental warning never reaches an existing Claude-only user — stderr is empty on such a host.$0.00fix landing — 56 of 1469 terminal rows and 43 HTML rows. Sort keys, row counts and aggregate totals are unchanged.Follow-ups, deliberately not done here
Centralising price data into its own module, a price-refresh mechanism, per-effort price rows, and subscription-utilisation reporting. All deferred by decision; worth their own issues.