Skip to content

question: hardcoded CLAUDE_MODELS allowlist overrides configured models and cannot track the bundled CLI #200

Description

@penradioGables

Summary

utils/agents/detection.py gates agent model selection against a hardcoded CLAUDE_MODELS list, and the detected list overrides whatever is configured. A model the bundled claude binary supports but that postdates the cptr release cannot be selected at all — agent:claude-code/<model> fails to resolve and cptr falls back to an API model silently.

Filing this as a design question rather than a defect; the current behaviour is clearly intentional, and the version gating around it is well built. The issue is only that the list and the CLI ship on independent cadences.

Current shape (v0.9.15, L26–34)

CLAUDE_MODELS = [
    "claude-fable-5",
    "claude-opus-4-8",
    "claude-opus-4-7",
    "claude-opus-4-6",
    "claude-opus-4-5",
    "claude-sonnet-4-6",
    "claude-haiku-4-5",
]
MIN_CLAUDE_FABLE_5 = (2, 1, 169)
MIN_CLAUDE_OPUS_4_8 = (2, 1, 154)

The MIN_CLAUDE_* gates show the intended mechanism is already there and works — a model is offered only when the detected CLI is new enough. The list itself is the part that has to be hand-edited to keep pace; between the v0.9.10 and v0.9.15 tags detection.py is the only one of these files that changed, which is consistent with it needing regular manual maintenance.

Why it bites

The bundled CLI can be updated independently of cptr (and is, frequently). When it gains a model the pinned list doesn't know about, the user's configured agent:claude-code/<model> silently resolves to something else. There is no warning — the fallback to an API model is indistinguishable from having configured an API model in the first place, which makes it hard to notice you are not running the agent you asked for.

Possible directions

  • Let a configured model through when the bundled CLI accepts it, using the existing detection probe as the source of truth rather than the static list.
  • Or keep the allowlist as-is and simply warn on silent fallback, so the failure is visible even if the behaviour doesn't change. This alone would remove most of the pain.

The second option is small and non-controversial if the first is a bigger design change than you want.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions