ovm.sh / writing

investigation

Three numbers for one context window

Claude Code assumes 200K tokens for any model it doesn't recognise — including whatever your proxy is serving. Finding the right number for GPT-5.6 meant reading the binary, and the answer turned out not to be the one in the API docs.

10 August 2026 · claudex · context

1The warning

Run claudex — Claude Code as the harness, GPT-5.6 as the model, through a localhost-only sidecar — and until recently you were greeted by this:

"gpt-5.6-sol" is not a model this version of Claude Code recognizes,
so auto-compact will keep this session within 200k tokens (the context
window it assumes).

It isn't an error and nothing fails. Claude Code needs a token budget to decide when to auto-compact, it derives that budget from the model name, and gpt-5.6-sol is not a name in its table. So it falls back to 200K. The only consequence is that long sessions compact earlier than the model requires — which is a quiet consequence, the kind you pay for without noticing.

The obvious fix is to tell it the real number. Establishing what the real number is took the rest of this page.

2What everyone else does

Running Claude Code against GPT-5.6 through CLIProxyAPI is well-travelled ground by now. Almost nobody addresses the context window.

And the proxy can't rescue you from its own side. Claude Code's gateway protocol defines exactly what it reads from a gateway's /v1/models response: id and an optional display_name. There is no context field in the schema. A gateway cannot declare how big its models are.

3What the binary actually does

With the guides in disagreement and the upstream issue open, the remaining authority is the program itself. Claude Code ships as a native binary with its JavaScript embedded, so the resolver is recoverable directly from the shipped artefact — here from a 2.1.226 build, with minified identifiers left as they are:

function Qmf(e,t){
  if(ES(e))return 1e6;
  if(t?.includes(dz.header)&&mz(e))return 1e6;
  if(U1(e))return 1e6;
  let r=tri(e); if(r!==null)return r;
  let n=te.CLAUDE_CODE_MAX_CONTEXT_TOKENS;
  if(n!==void 0&&n>0&&!Eo(ns(e)).startsWith("claude-"))return n;
  return ebr;                          // ebr = the 200K default
}

That highlighted line settles it. CLAUDE_CODE_MAX_CONTEXT_TOKENS is honoured on the normal path, with no DISABLE_COMPACT required — under exactly one condition: the model ID must not start with claude-. Every proxied GPT-5.6 ID satisfies that.

The DISABLE_COMPACT claim isn't invented, just misplaced. It belongs to a separate, higher-priority branch that forces the value for any model, including real Claude ones:

function Xmf(){
  if(te.DISABLE_COMPACT){
    let e=te.CLAUDE_CODE_MAX_CONTEXT_TOKENS;
    if(e!==void 0&&e>0)return e
  }
  return
}

So the advice to disable compaction was never necessary — and disabling compaction to fix a compaction threshold would have been a poor trade.

The warning also suppresses itself. The notice function returns early when the variable is set, so one environment variable both fixes the budget and silences the message.

Which builds have it

A resolver that exists in today's build is not a resolver you can ship against. We keep every managed version on disk, so the question is answerable directly — this is the same evidence OVM's benchmarks are built from:

BuildVariable presentNon-claude- guard
2.0.24no
2.1.64no
2.1.96no
2.1.201yesyes
2.1.207yesyes
2.1.212yesyes
2.1.220yesyes
2.1.226yesyes

Across 2.1.201 → 2.1.226 the resolver is semantically identical; only the minifier's identifiers move between builds (beZte). It is absent from 2.1.96 and earlier, so it arrived somewhere in between — DocksDocks cites 2.1.193, consistent with what we can see. Older builds ignore the variable rather than misreading it, which makes setting it safe to ship unconditionally.

4Three numbers

Knowing how to declare the window leaves what to declare. GPT-5.6 has three defensible context numbers, and which one is true depends on which door you came in through.

SourceWindowWhat it describes
OpenAI API model spec 1,050,000 The raw capability, billed per token on API keys
Codex catalogue, before 18 Jul 2026 372,000 The subscription client's old default
Codex catalogue, current 272,000 Corrected to sit on the pricing boundary

claudex signs in with Codex OAuth on a ChatGPT subscription, so the Codex catalogue is the relevant one — not the API spec. And 272K isn't an arbitrary cap. It is where the price changes: OpenAI documents that prompts over 272K input tokens bill at 2x input and 1.5x output for the entire request. Codex corrected its own bundled metadata from 372K to 272K in July 2026 for exactly that reason: the old number left roughly 100,000 tokens of headroom sitting inside the premium band, reachable without any signal that the meter had changed rate.

Which makes the choice clear. Declaring 1,050,000 would let a session grow nearly four times past the cliff at double rates. Declaring 372,000 — the number the one project that solved this correctly still ships — is now stale by a month and parks that same 100K inside the premium band.

272,000. A 36% increase over the 200K Claude Code assumes today, and it stops exactly where the money changes price.

5What OVM ships

One line in the launch environment, config-backed so a future boundary move is an edit rather than a release:

(
    "CLAUDE_CODE_MAX_CONTEXT_TOKENS".to_string(),
    config.tuning.max_context_tokens.to_string(),   // 272_000
),

The accompanying test pins both halves of the contract: the value, and the fact that no configured model ID starts with claude-. The second assertion matters more than it looks — a future model rename that reintroduced that prefix would silently return every session to 200K, with nothing failing and no warning printed. A test that fails is cheaper than a regression nobody can see.

This is the same reasoning that produces the rest of what OVM publishes: the interesting failures are the quiet ones, where absence renders as a clean result. A 200K assumption looks exactly like a 200K model.

6References

claudex is an unofficial integration. No endorsement by Anthropic or OpenAI is claimed or implied. Decompiled excerpts are quoted from shipped binaries for interoperability, and identifiers are minifier output that changes between builds — verify against the build you run rather than copying names from here.