Release notes

FEATURE

The TUI launches from the macOS app bundle again, packing complete character width tables without crashing

When launching the terminal text user interface from the macOS app bundle, the screen no longer crashes on the spot due to missing character width data.

The packaging tool py2app previously listed rich under includes, collecting only files reachable by static import scans. However, rich/_unicode_data/__init__.py dynamically loads per-version Unicode width tables via import_module() at render time, causing the packaged app to carry only __init__ and _versions and crash immediately upon drawing the first table:

usage --tui  # throws ModuleNotFoundError: No module named 'rich._unicode_data.unicode17-0-0'

Menu bar mode, which does not render through rich, is unaffected. rich is now listed under packages so the entire directory is copied directly rather than only scanned fragments, restoring the text user interface (TUI) to normal.

BUGFIX

Fable 5.1 gains offline fallback pricing, and the audit script no longer skips the entire family

Claude Code 2.1.257 set Fable 5.1 (claude-fable-5-1) as the default, and the offline pricing gap is now filled. The hard-coded fallback price table previously only contained claude-fable-5, so whenever the downloaded price table was missing or expired, every Fable 5.1 token was costed at $0. Its cache-read price is 0.25e-6, only a quarter of Fable 5's, so inheriting older data would also be incorrect. This gap went unnoticed in the past because scripts/check_fallback_pricing.py only matched opus|sonnet|haiku, skipping the Fable family regardless of whether models were old or new. Now Fable 5.1 has its offline price added, and the audit script includes it in checks.

BUGFIX

Dated models no longer fall back to newer version pricing, adding five active models

When querying offline prices for older dated models, the program no longer mistakenly falls back to the cheaper price of a newer version.

Previously, _resolve_model_key counted any key starting with the query string followed by a hyphen as a hit. This caused claude-opus-4-20250514 to resolve to claude-opus-4-6, costing $5 per million tokens offline instead of the actual $15—only one-third of the real cost. When a query carries its own version number, candidates with an appended trailing digit are no longer accepted. Generic names without version numbers like claude-sonnet still resolve as before, picking the newer version among equally specific keys, while named variants (gpt-5 to gpt-5-pro) remain unaffected. Five models still in service that were previously missing from the table have been added, and Bedrock version suffixes are stripped so queries price correctly:

claude-opus-4
claude-opus-4-1
claude-opus-4-5
claude-sonnet-4
claude-sonnet-4-5
claude-sonnet-4-5-20250929-v1:0  # prices correctly after stripping Bedrock suffix (v1:0)
BUGFIX

Fallback pricing audit switches to resolution matching, eliminating false positives and persistent error exit codes

The audit script checking fallback pricing tables now only reports models that actually fail to resolve, rather than outputting a confusing list that no one could act on. Previously, compare_pricing diffed raw literal keys in both directions, even though the fallback table deliberately omits date suffixes. This caused models that could calculate prices perfectly well (such as claude-haiku-4-5 and claude-opus-4-7-20260416) to be flagged as missing. Three of the 12 reported gaps were false, keeping the script's exit code at 1 persistently and making real gaps indistinguishable from the noise. Both directions now evaluate models through _resolve_model_key.

FEATURE

Usage table displays short names for Opus 5 and Fable 5.1 instead of raw model IDs

When opening the terminal to view usage tables, the screen should display short, readable names for each model to help grasp usage distribution at a glance. However, the short-name dictionary MODEL_SHORT previously lacked entries for Opus 5 and Fable 5.1, forcing the table to print long raw model IDs and making the layout cluttered and difficult to read. The usage table now includes mapping entries for both models, displaying clean short names properly.

FEATURE

Quota warnings fire earlier at 50% usage, sending at most one notification per reading

Your quota alerts now trigger earlier, and a single reading never sends two consecutive duplicate notifications. Starting with Codex 0.153.0, Plus and Team users are warned once less than half of the five-hour window remains. However, usage previously waited until 90% before alerting, meaning the monitored tool warned earlier than the monitor itself. The default threshold is now consistently set to [50.0, 90.0] across macOS and Windows, while remaining customizable via quota_notification_thresholds. A single reading can cross both thresholds at once, such as when the app launches with quota already at 95% or during a single large usage jump. In this situation, only the highest crossed threshold sends a notification while the rest are latched as notified, ensuring one observation never generates two duplicate alerts.

Original changelog

Original changelogThe TUI launches from the macOS app bundle again, packing complete character width tables without crashing
**The TUI launches from the app bundle again.** `rich` was listed in py2app's `includes`, which collects only what its static import graph can see — but `rich/_unicode_data/__init__.py` loads its per-version Unicode width tables through `import_module()` at render time, so the bundle shipped that package carrying `__init__` and `_versions` alone and `usage --tui` died with `ModuleNotFoundError: No module named 'rich._unicode_data.unicode17-0-0'` on the first table it drew. Menu bar mode, which never renders through `rich`, was unaffected. `rich` is now a `packages` entry, which copies the whole tree instead of the reachable parts of it. Reported by @dvakatsiienko in #125.
Original changelogFable 5.1 gains offline fallback pricing, and the audit script no longer skips the entire family
**Fable 5.1 has an offline price, and the fallback table's own audit no longer skips the entire Fable family.** Claude Code 2.1.257 made Fable 5.1 (`claude-fable-5-1`) the default of the Fable line, but the hard-coded fallback table only carried `claude-fable-5`, so whenever the downloaded price table was missing or stale every Fable 5.1 token was costed at $0. Its cache-read price is `0.25e-6` — a quarter of Fable 5's — so inheriting the older entry would not have been correct either. The gap went unreported because `scripts/check_fallback_pricing.py` matched only `opus|sonnet|haiku`: no `fable` model, old or new, was ever in scope for the audit that exists to catch exactly this.
Original changelogDated models no longer fall back to newer version pricing, adding five active models
**A dated model no longer falls back to a newer version's pricing.** `_resolve_model_key` matched any table key that started with the queried name followed by a hyphen, so `claude-opus-4-20250514` resolved to `claude-opus-4-6` and was costed at $5/M instead of $15/M — a third of the real figure — whenever the offline table was in use. A query that already carries its own version number now rejects a candidate that merely appends another digit, while a version-less name like `claude-sonnet` still resolves, and among equally specific keys the newest version wins. Named variants (`gpt-5` → `gpt-5-pro`) are unaffected. The five models still in service that the table had never carried — `claude-opus-4`, `claude-opus-4-1`, `claude-opus-4-5`, `claude-sonnet-4`, `claude-sonnet-4-5` — were added, and a Bedrock version suffix is now stripped so `claude-sonnet-4-5-20250929-v1:0` prices correctly.
Original changelogFallback pricing audit switches to resolution matching, eliminating false positives and persistent error exit codes
**The fallback pricing audit reports what actually fails to resolve, instead of a list nobody could act on.** Both directions of `compare_pricing` diffed raw dictionary keys, but the fallback table drops date suffixes on purpose — so models that price perfectly well, such as `claude-haiku-4-5` and `claude-opus-4-7-20260416`, were reported as missing. Three of the twelve reported gaps were false, the script's exit code had been 1 for as long as that was true, and a real gap was indistinguishable from the noise. Both directions now resolve through `_resolve_model_key`.
Original changelogUsage table displays short names for Opus 5 and Fable 5.1 instead of raw model IDs
**The usage table shows a name for Opus 5 and Fable 5.1.** `MODEL_SHORT` had no entry for either, so both were printed as their raw model IDs.
Original changelogQuota warnings fire earlier at 50% usage, sending at most one notification per reading
**Quota warnings now fire at 50% as well as 90%, and one reading sends at most one notification.** Codex 0.153.0 began warning Plus and Team users once a five-hour window is less than half remaining; usage waited until 90%, so the tool it monitors warned earlier than the monitor did. The default is now `[50.0, 90.0]` on macOS and Windows alike, still overridable through `quota_notification_thresholds`. Because a single reading can cross both thresholds at once — the app launching when quota is already at 95%, or a single large jump — only the highest crossed threshold sends a notification and the rest are latched, so one observation never produces two alerts saying the same thing.