Claude Desktop always caps Claude Code at 200K: spawns CLI with a bare model id, no 1M row in the picker
What happened
Claude Code sessions launched from Claude Desktop are always capped at a 200K context window, with no way to select 1M — even on a plan where 1M is entitled and where the terminal CLI offers it. There is no error or notice; the meter simply reads 200.0k.
Environment
- Claude Desktop 1.30096.1 (macOS 15 / darwin 24.6.0, Apple Silicon)
- Bundled Claude Code CLI 2.1.229
- Plan: Max 20x (1M entitled — the terminal CLI on the same machine, same account, gets 1M)
Root cause
Claude Desktop spawns the bundled CLI with a bare model id:
.../claude-code/2.1.229/claude.app/Contents/MacOS/claude … --model claude-opus-5 …
The CLI gates the 1M beta on a suffix in the model id:
function Ov(e){ if(sae()) return !1; return /\[1m\]/i.test(e) }
No [1m] ⇒ no context-1m-2025-08-07 beta ⇒ 200K, silently.
Three things make this unreachable from the desktop:
- The picker has no 1M row. The desktop builds one only on the third-party path —
Ndt()emits${id}[1m]whensupports1m && !restricted, andsupports1m/prefer1m/inferenceModelsare all scoped['3p']. On a first-party login the model list is server-driven and contains no 1M entry. settings.jsonis overridden.~/.claude/settings.jsonhas"model": "claude-opus-5[1m]", and the desktop picker even labels the row "Default from your Claude Code settings" — but it resolves that string against its own row list and drops the[1m]suffix before spawning.- Selecting
[1m]mid-chat doesn't help. The window is bound at spawn, andt0s()clamps it back:
``js``
function t0s(e,t){ return afr() && YAu()===void 0 && JAu(e,t)>hfe } // → 200K
function afr(){ return tHe.longContext1mCreditsBlocked() }
Reproduce
- On a plan with 1M entitlement, set
~/.claude/settings.jsonto"model": "claude-opus-5[1m]". - Open Claude Desktop, start a new chat. The context meter at bottom right reads
200K. ps -Ao args | grep claude-code— the spawn carries--model claude-opus-5, no suffix.- Run
claudein a terminal on the same machine/account —/statusreports 1M, and the picker has an "Opus … with 1M context" row.
Expected
The desktop model picker should offer the 1M variant when the account is entitled, the same way the terminal CLI does — or at minimum honor the [1m] suffix already present in settings.json instead of silently stripping it.
Workaround (and why it's a bad one)
The only route that works is bypassing the model-id path entirely, via env vars inherited from launchd:
launchctl setenv ANTHROPIC_BETAS context-1m-2025-08-07
launchctl setenv DISABLE_COMPACT 1
launchctl setenv CLAUDE_CODE_MAX_CONTEXT_TOKENS 1000000
This works (verified: desktop meter reads 1.0M) because TC() consults YAu() first, which returns CLAUDE_CODE_MAX_CONTEXT_TOKENS outright when DISABLE_COMPACT is set — short-circuiting Ov() and t0s().
The cost is severe and structural: CLAUDE_CODE_MAX_CONTEXT_TOKENS is otherwise ignored for claude-* ids (JAu() restricts it to !startsWith("claude-")), so DISABLE_COMPACT is mandatory — which also disables auto-compaction and the /compact command (isEnabled: () => !Q.DISABLE_COMPACT). Users are forced to choose between a 1M window and compaction, and the env var is global to every GUI-launched process.
Notes
- Patching the bundle (wrapping
Contents/MacOS/claudeto re-append[1m]) does not persist — the desktop restores its CLI on launch. - Possibly related: #66410 (closed as inactive) reported the desktop picker topping out below 1M.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗