Repository navigation
Claude models read the way Claude Code lists them: Fable 5.2, not fable - #216
Merged
Merged
Conversation
A card, the quick prompt, the model submenu, the Agents tab and a preset all printed the id nebula stores and passes to `--model` — `fable`, which says nothing about which Fable. They now print the name Claude Code's own `/model` picker lists: `Fable 5.2`, `Opus 5.5 (1M context)`. The names are not hardcoded. Claude Code caches the catalog its picker is drawn from under `<config dir>/cache/model-catalog/`; the TUI reads the newest file at start and again every ten minutes, off the event loop, and maps alias -> id -> name through it, following the provider Claude Code is pointed at. The stored id is untouched, so `--model`, resume, config.json and type-ahead are as before. An id the catalog does not name, and every id on a machine with no catalog, prints as it is. Other harnesses' ids are never renamed. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
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.
Every place nebula printed a Claude model showed the id it stores and passes to
--model—fable, which says nothing about which Fable — and now shows the name Claude Code's own/modelpicker lists:Fable 5.2.Contents: 🔁 Before / After · 📸 Screenshots · 🧭 What moved ·⚠️ Risk · 🔧 Technical overview · 📝 Notes
🔁 Before / After
claude fable highclaude Fable 5.2 highclaude opus[1m]claude Opus 5.5 (1M context), the wording/modelprintsmodel fable ^Omodel Fable 5.2 ^O^O, the NEW SESSION PICKER)fable·opus·sonnet·haikuFable 5.2·Opus 5.5·Sonnet 5.5·Haiku 5.5Settings › Agents › ModelfableFable 5.2claude · fable · highclaude · Fable 5.2 · highclaude · fableclaude · Fable 5.2--modelgets, what a resume passes, whatconfig.jsonholds, what type-ahead matches (fablestill finds the row)📸 Screenshots
How these were taken, since the stock SCREENSHOT HARNESS cannot show the change: it sets
NEBULA_AGENT_CMD, under which the TUI reads none of Claude Code's files.scripts/shot/shot.shstarts the TUI alone without that switch, withCLAUDE_CONFIG_DIRon a fixture directory holding a four-model catalog (the ids and names of the real one). The DAEMON still launches the stand-in agent.origin/mainhas, and the fallback this PR keeps. It is not anorigin/mainbuild.🧭 What moved
flowchart LR cc["Claude Code"] -- "refreshes while it runs" --> cache["cache/model-catalog/*.json"] subgraph tui["TUI"] boot["bootstrap: at start, then every 10 min on a thread"] --> names["ModelNames: alias → id → name"] names --> label["model_label(kind, id)"] label --> cards["cards · columns · nested strip"] label --> box["QUICK PROMPT · model submenu"] label --> rest["Agents tab · presets · metrics"] end cache --> boot row["AGENT row: model = fable"] --> label row -- "unchanged" --> flag["claude --model fable"] classDef new fill:#bbf7d0,stroke:#166534,color:#111 classDef same fill:#e5e7eb,stroke:#374151,color:#111 class boot,names,label new class row,flag,cc,cache same🎯 Attack surface
<Claude config dir>/cache/model-catalog/— the user's own account, the same trust assettings.json, which the TUI already reads. Held by: a 4 MB per-file cap, a plain JSON parse where a malformed file is skipped, and use of two string fields only (id,name) as display text — never passed to a CLI, a shell or the DAEMON, and ratatui drops control characters from span text. Not held: the length of a name; a very long one is drawn and truncated the way a very long model id already is.settings.json'senvblock, read for seven provider switches. Same file and same reach as above. Held by: only whether aCLAUDE_CODE_USE_*key is non-empty is used, to pick which catalog target an alias means. Not held: nothing further — the value itself goes nowhere.Verdict: 🟢 Low risk — display only; the id that is stored, matched and passed to the CLI does not change.
claude_catalogue.rs, which already reads Claude Code's settings at TUI start for the MODEL list, and is skipped underNEBULA_AGENT_CMDexactly as that is; one sharedmodel_labelrather than a rename per surfaceRollback:
git revertof the merge restores the ids on every surface; nothing is stored, migrated or versioned, so there is nothing a revert leaves behind.🔧 Technical overview
modelstable (claude-fable-5-2→Fable 5.2) andprovider_alias_targets(fable→claude-fable-5-2, with per-provider overrides).ModelNames::in_catalogreads both out of either shape Claude Code writes — the served catalog and the signed fallback document — for theccsurface only;names_fromtakes the newest file by itsfetchedAt.config::model_label(kind, id)maps a Claude id through it and returns the id itself on a miss, and the nine call sites that formatted a model now call it.crates/nebula-tui/src/claude_catalogue.rs— the reader, the process-global names, the refresh thread, and its tests;crates/nebula-tui/src/config.rs—model_label/model_label_inand the Agents tab value;ui/launcher_view.rs,ui/launcher_view/nested.rs,ui/overlay.rs,quick_prompt.rs,event_loop/actions.rs,agent_presets.rs,preset_overlays.rs— one call each;docs/how-it-works.md,docs/configuration.md.fable → Fable 5.2compiled into nebula is wrong the day 5.3 ships, and wrong today on Foundry or a gateway, where the catalog points the same alias at an older model. With no catalog on disk the alias is printed, which is true.modelattachment carries a marketing name, but only for a session that has taken a prompt; the pickers and the Agents tab need a name before any session exists.[1m]mapping, provider overrides, newest-file selection with broken and foreign files beside it, and one wiring test that draws a card, the QUICK PROMPT row and a preset line with a name installed. Existing tests are untouched because nothing installs names in them.cargo fmt --all -- --check,cargo clippy --workspace --all-targetsandcargo test -p nebula-tui(1379 passed, 7 ignored) were green on the tree this was written on. That tree was a localmainone commit offorigin/main; the branch here is the same patch placed onorigin/main(a clean three-way, identical patch-id) and was not re-run locally — CI on this PR is the gate for it. The daemon and e2e suites were not run; no daemon or protocol code changed.📝 Notes
origin/main, no conflicts.🤖 Generated with Claude Code