You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One config file: ~/.claude/multi/config.toml. Backends, their models, endpoints, per-backend timeouts and named profiles all live there, with comments; providers.env keeps only keys. Read by scripts/config.py (stdlib tomllib, with a vendored tomli for python < 3.11). No file means the built-in default — codex, opencode, openrouter — and setup.sh init writes it out to edit.
Any number of Anthropic-compatible endpoints, each its own backend: [backends.zcode] with type = "claude-headless", its own base_url, models and key variable, next to openrouter instead of replacing it. Before, one endpoint could be pointed away from OpenRouter and that was all.
Profiles: [profiles] normal = ["openrouter:x-ai/grok-4.5", "zcode", "codex"], picked with ask.sh --backend normal; no --backend runs default_profile. code-review, check-if-done and ask stop hard-coding a backend list, so the config actually decides who reviews — a knob the skills bypass changes nothing. adhd keeps its fixed two external frames on purpose: its frames are distinct engines, not a reviewer roster.
backend:model pins exactly that model with no fallback. Asking for a paid model and silently getting a free one is worse than a marker saying it failed.
Per-backend timeout; ask.sh --timeout N is a floor (every backend gets at least N, the review skill passes 2400), never a cut — the same rule codex already had with its 600s.
A broken config stops every run before anything launches, naming the file and the key: unknown type, unknown key, a profile naming a backend that does not exist or sharing a backend's name, a claude-headless without models or base_url, a non-https endpoint (plain http only when the parsed host is the loopback), a model name with whitespace, a key variable or backend name that is not a plain identifier, more than one model on codex or gemini — those two do not walk a chain yet, and the config says so instead of ignoring the rest.
Removed, not aliased: the models file, MULTI_OPENROUTER_MODEL, MULTI_OPENROUTER_MODELS, MULTI_OPENROUTER_FALLBACKS, MULTI_OPENROUTER_BASE_URL, MULTI_OPENCODE_MODEL, MULTI_GEMINI_MODEL, MULTI_BACKEND_TIMEOUT, MULTI_CODEX_TIMEOUT, MULTI_OPENCODE_STALL, and the --or-model / --gemini-model flags (name:model does it, and a by-type flag picks the wrong backend once two share a type). Reading the old variables "just in case" would be a third config. While providers.env still sets any of them nothing runs: the old MULTI_OPENROUTER_BASE_URL chose where the key goes, and a config that ignored it would send a z.ai key to openrouter.ai. setup.sh init still works in that state, the probe says models-config: LEGACY while the old file exists, and setup.sh set MULTI_* explains where the value went. setup.sh set accepts exactly the key variables the config's backends read.
Upgrading: move MULTI_OPENROUTER_* values into [backends.openrouter] (base_url, models) and the models file's list into [backends.opencode]; timeouts become timeout = N per backend. Keys need no change.
config.example.toml and providers.example.env in the repo show every backend type, every field, a second endpoint with its own key, and several profiles; a test keeps the example valid.
python3 is now required to run anything: bash cannot read TOML. It was already needed to read OpenCode answers.