-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Description
When using copilot --model claude-opus-4.6 on Linux with experimental: true enabled, the CLI was falling back to a different model instead of using the requested one. The model appeared in --model allowed choices but was not listed in the /models command output initially. The subscription includes access.
This affected multiple team members across platforms (Linux and macOS). One Mac team member was affected while another was not — the difference may be related to installation method (bun vs npm).
Environment
- Copilot CLI version: 0.0.405
- Platform: Linux x86_64 (containerized dev environments), macOS also reported
- Installation:
bun install -g @github/copilot - Config:
experimental: trueenabled in~/.copilot/config.json
Original Symptom
Running copilot --model claude-opus-4.6 fell back to the config default model instead of using opus-4.6. No error was shown — the fallback was silent. Only visible in the session breakdown output.
Multiple login/logout cycles (copilot /login, copilot /logout) were attempted with no effect. This was an existing Copilot CLI installation in every case — not a fresh install.
Root Cause Analysis
After decompiling the minified source (index.js), the following code paths are relevant:
1. Model selection gates opus-4.6 behind staff flag
The default model selection function gates claude-opus-4.6 exclusively behind config.staff:
// Default model selection (decompiled)
function getDefaultModel(availableModels, config) {
if (config?.staff) {
let model = "claude-opus-4.6";
if (isAvailable(model, availableModels)) return model;
}
// Falls back to first model with cost multiplier <= 1
return MODELS.find(m => isAvailable(m, availableModels) && getCost(m, availableModels) <= 1);
}2. Explicit --model flag validates against API-returned model list
// Model resolution (decompiled)
async function resolveModel(cliModel, session, availableModels, logger) {
if (cliModel) {
if (isAvailable(cliModel, availableModels)) return cliModel;
logger?.warning(`Model '${cliModel}' from CLI argument is not available. Falling back...`);
}
// Falls through to config model, env var, then default
// ...
let defaultModel = getDefaultModel(availableModels, config);
return defaultModel;
}3. Staff auto-detection checks org membership
The CLI has auto-detection that sets staff: true if the user belongs to ["microsoft", "github", "azure", "microsoftcopilot", "ms-copilot"] orgs. This auto-detection only runs if config.staff is not already defined.
4. Feature flags treat staff and experimental independently
// Feature flag resolver (decompiled)
function resolveFeatureFlags(isStaff, isExperimental) {
switch (availability) {
case "on": // Always enabled
case "staff-or-experimental": // Either flag works
case "staff": // Staff only — opus-4.6 uses THIS
case "experimental": // Experimental only
case "off": // Always disabled
}
}Opus-4.6 gating uses "staff" only, not "staff-or-experimental".
Reproduction Attempts
After adding staff: true to config (which resolved the issue), we attempted to reproduce by removing it:
| Test | Config | Command | Result |
|---|---|---|---|
| 1 | staff: true, experimental: true |
--model claude-opus-4.6 |
✅ opus-4.6 used |
| 2 | staff: null, experimental: true |
--model claude-opus-4.6 |
✅ opus-4.6 used |
| 3 | no staff key, experimental: true |
--model claude-opus-4.6 |
✅ opus-4.6 used |
| 4 | no staff, no experimental | --model claude-opus-4.6 |
✅ opus-4.6 used |
| 5 | no staff, no experimental | no --model (config default opus-4.5) | ✅ opus-4.5 used |
| 6 | no staff, no experimental, config model: opus-4.6 | no --model | ✅ opus-4.6 used |
| 7 | no staff, no experimental | /models command |
✅ opus-4.6 listed |
The issue was no longer reproducible after adding then removing staff: true. This suggests either:
- Server-side state change: Adding
staff: truemay have triggered a backend state change (e.g., model entitlement cache) that persisted after removing the flag - Transient API issue: The available models list returned by the API may have been temporarily missing
claude-opus-4.6for Linux clients - Token refresh: The auth flow during testing may have refreshed the Copilot token, which then included updated model entitlements
Issues Found (even if not currently reproducible)
-
Silent fallback: When
--modelspecifies a model that fails validation, the CLI silently falls back with no user-facing warning. Thelogger?.warning()call exists in code but the output is not shown to the user. -
Undocumented
staffflag: Thestaffconfig key gates access to premium model features but is not documented anywhere. Users have no way to discover this workaround. -
experimentalinsufficient: Users who enable experimental mode reasonably expect access to all available models, but opus-4.6 is gated behindstaffonly (notstaff-or-experimental). -
Cross-platform: Issue observed on both Linux and macOS. macOS evidence not yet collected but at least one Mac team member also affected.
Recommendation
- Model access should be gated purely by subscription/API entitlements, not local config flags
- Silent fallbacks should show a clear warning to the user
- If
staffflag is intentional, it should be documented - Consider gating opus-4.6 as
staff-or-experimentalinstead ofstaff-only