DEV Community

Yusuke Shiki
Yusuke Shiki

Posted on

Tracking Codex Astra costs took more than updating a price table

I updated agent-cost, a CLI I maintain, to version 0.1.1 because I wanted to measure Codex's GPT-6 Astra usage too. It reads local Claude Code and Codex CLI logs and reports token usage and estimated costs, not actual billed amounts.

Fast mode was where I ran into trouble.

After adding Astra to the price table, I tested it with synthetic logs. Usage marked as Fast was still being priced at the Standard rate. The multiplier was in the catalog, but the log reader wasn't recognizing the setting.

The fix involved both detecting the mode and deciding what to do when the logs didn't give me enough information.

What the synthetic tests showed

I used synthetic data with two million uncached input tokens, two million cached input tokens, and two million output tokens: six million tokens in total.

Here are the results for Standard, Fast, and unknown settings, using the rate catalog bundled with 0.1.1. This is a test fixture, not real usage or a list of current official prices.

Setting identified from the log Estimated USD Estimated credits Unpriced tokens
Standard 122 3,050 0
Fast 305 7,625 0
Unknown 0* 0* 6,000,000

The zero in the unknown row means none of that usage could be priced. **It does not mean the usage was free.*

The same token counts produce an estimate of $122 at Standard rates and $305 at Fast rates. During development, the Fast case was incorrectly returning the Standard estimate.

The already-published 0.1.0 release didn't have Astra rates at all, so it treated Astra usage as unpriced. This was a problem found while implementing Astra support, not a report that 0.1.0 had shown users the wrong Fast amount.

The changes are in PR #8. The synthetic fixture and tests are public too. The table above summarizes test results; it isn't a copy of the CLI's output.

Does "not known to be Fast" mean Standard?

I checked the public source for Codex 0.153.4.

For this Astra support, agent-cost reads service_tier as well as the model name. It checks that the settings belong to the same session and match the target turn and model. An explicit default selects Standard; priority selects Fast.

But a setting can be missing. It can also conflict with the information recorded for a turn. In those cases, the mode isn't clear.

Treating everything that isn't recognized as Fast as Standard would still produce a number. It would also assign Standard prices to usage whose settings the reader simply couldn't establish.

Instead, usage stays unpriced when the reader can't determine which rate applies. Knowing Astra's rates doesn't establish whether a particular piece of usage was Standard or Fast.

This is based on the request settings recorded in the log. It doesn't confirm the processing mode actually used by the server or what was billed. The source references and attribution rules are in the implementation notes.

Keep the tokens even when the price is unknown

Dropping an unpriced row would hide the fact that the usage happened. Keeping only a zero amount would make it look free.

So the output carries pricing_status, which describes the pricing state, and unpriced_tokens, which counts tokens that couldn't be priced, separately from the amount.

Checking those fields alongside the total shows whether any usage was left out of the calculation. The unknown row above doesn't just say $0: it preserves all six million tokens as unpriced.

priced doesn't mean a confirmed charge either. It means the usage could be calculated using the selected rate catalog.

Which usage gets the new setting when Fast is switched on?

Settings can also change during a session.

Suppose a session starts in Standard, uses Fast for the next turn, then switches back to Standard. Pricing the entire session with its final setting would treat the Fast portion as Standard too.

When settings change between completed turns, the reader applies the new settings only to subsequent usage. The log contains cumulative token counts, so it takes the increase since the previous count and prices that increase using the turn's settings.

An update while a turn is still running leaves an ambiguous interval: the reader can't safely assign that usage to the old or new settings. Those tokens stay unpriced as well.

This behavior was added in 0.1.1 for logs containing Astra. It doesn't fully reconstruct missing history, concurrent updates, or alternative storage formats. The supported scope is limited to the reader implementation and the cases checked with synthetic data.

Trying it locally

With uvx available, you can run the published 0.1.1 package with the commands below.

Astra coverage in this version: the model ID must be exactly gpt-6-astra, and usage must be at or after September 5, 2026, 17:18:23 UTC (September 6, 02:18:23 JST). Earlier usage remains unpriced, even when Standard or Fast can be identified.

This is a catalog boundary based on when the rates were checked, not an official launch or tariff start time. This release also does not update every model's rates: known discrepancies in the GPT-5.6 family remain.

uvx --from coding-agent-cost==0.1.1 agent-cost doctor
uvx --from coding-agent-cost==0.1.1 agent-cost report
Enter fullscreen mode Exit fullscreen mode

doctor checks things such as the configured input locations. report actually reads the local logs and aggregates usage. Running doctor alone doesn't verify that every log is valid.

The CLI doesn't send the logs anywhere. The uvx package runner may use the network to download the package. To see output before reading your own logs, use the README's synthetic output example. That example remains pinned to 0.1.0 as a record of an earlier verification.

For use from another program, there is JSON output and the measure/v1 interface. The output includes the rate catalog's version and SHA-256, so a result can be traced back to the catalog used to calculate it. The README covers installation requirements and the timezone-data caveat on Windows.

The additional Astra checks used synthetic data. I haven't validated compatibility against real Astra logs or measured a cost reduction from using the tool. API-specific tariffs and actual charges under individual contracts are outside this calculation. The 0.1.1 release notes record the scope and verification results at publication.

Where I landed

An unknown price isn't a particularly satisfying result when you ran the tool to find out the cost.

But assigning a Standard rate when the settings couldn't be read would hide that uncertainty from the person using the result. For this Astra update, I kept the tokens even when they couldn't be priced, so the output shows how much usage the calculation actually covers.


This is the English version of my article on Zenn.

Top comments (0)