split-brain

Sign in

Default Claude model — design

Status: Implemented. Makes the router's default Claude model runtime-tunable from the UI admin page (no redeploy), seeded to claude-sonnet-4-6.

What "default model" means

The router picks the model sent to Anthropic per request:

  • Anthropic ingress (/v1/messages) — the client's own claude-* model id is honored (Claude Code names a model per task; flattening them all to one would degrade it). See ClaudeBackend._effective_model.
  • Otherwise — the OpenAI ingress (/v1/chat/completions, where model is a router alias) and any request that doesn't name a real claude-* model fall back to the default model.

This setting controls that fallback. It does not override a client that pins its own Claude model.

Where the value lives

A single JSON file on the shared PVC, written by the UI and read by the router — the same pattern as limits.json (see token-limits):

/var/split-brain/settings/settings.json
  -> { "default_claude_model": "claude-sonnet-4-6" }
  • UI (ui/settings.py) is the single writer (replicaCount 1). The admin page (/admin, @smasint.com only) POSTs /admin/model; the value is validated (claude-*) and written atomically.
  • Router (router/settings.py SettingsStore) reads it, cached ~5s, and resolves the Claude backend's model_id per request via a provider callable — so a change takes effect within seconds, no restart.
  • Seed / fallback: when settings.json is absent or holds a bad value, both sides fall back to the configured seed (anthropic_model / ui_default_claude_model, both claude-sonnet-4-6; the router seed is also set via the chart's config.anthropicModel).

Safety

is_valid_model_id requires a non-empty claude-* string on both the write side (rejected with 400) and the read side (a malformed file silently falls back to the seed) — a bad value can never break every Claude call.