Claude Code LLM gateway environment variables observability prompt engineering 2026

Claude Code v2.1.273 Added 5 New Gateway Headers. The Official Protocol Docs Don't List Them Yet (2026)

The Prompt Shelf ·

Claude Code v2.1.273 (September 15, 2026) added five new request headers for LLM gateways, gated behind a single opt-in flag: CLAUDE_CODE_GATEWAY_HINT_HEADERS=1. The official changelog describes them in one line — “Added x-claude-code-request-class, x-claude-code-agent-type, x-claude-code-prev-tool-durations, x-claude-code-compaction and x-claude-code-context-compacted request headers for LLM gateways” — and that’s it. As of this writing, the LLM gateway protocol reference, which is the page that documents every other header Claude Code sends, doesn’t mention any of the five.

If you run or evaluate a gateway in front of Claude Code — LiteLLM, Portkey, Kong AI Gateway, or something you built in-house — this is worth understanding now, not when the reference page eventually catches up.

What the flag actually turns on

By default, Claude Code sends only three custom headers to a gateway, all documented on the protocol reference page:

HeaderSent whenPurpose
x-claude-code-session-idAlwaysAggregate every request from one Claude Code session without parsing bodies
x-claude-code-agent-idOnly on requests from a spawned subagentAttribute cost to a specific subagent inside a session
x-claude-code-parent-agent-idOnly on requests from a nested agentAttribute cost through a chain of spawned agents

Setting CLAUDE_CODE_GATEWAY_HINT_HEADERS=1 adds five more. None of them are documented with a value format yet, so what follows is grounded in how Claude Code already behaves elsewhere in its own docs — not a guess pulled from nothing, but not an official spec either. Treat the header names as consume-only routing keys, not a schema to build strict parsing logic against.

x-claude-code-request-class

The protocol docs already describe at least one internal distinction between request types: auto mode’s classifier requests. The gateway protocol page notes that Claude Code keeps its system-prompt attribution block on “auto mode classifier requests” even when CLAUDE_CODE_ATTRIBUTION_HEADER=0 is set for regular turns, specifically because classifier requests carry no other system prompt content to identify them as Claude Code traffic. That’s Anthropic telling you, in a different section of the same doc, that classifier calls are a distinct internal category from normal conversation turns.

x-claude-code-request-class most plausibly surfaces that categorization (and probably others, like tool-execution follow-ups) as a header value instead of leaving gateways to infer it from body shape. If your gateway currently guesses “is this a classifier call” by looking for a short system prompt, this header is the thing that replaces that guess.

x-claude-code-agent-type

Claude Code already distinguishes between agent kinds internally. Per the same reference doc: a regular subagent gets a “fresh” ID every time it’s spawned, while a teammate — a named member of an agent team — “reuses a stable name-based ID across reconnections.” That’s two agent types with different ID lifecycles, plus the main session agent itself as a third. x-claude-code-agent-type is the natural header to carry which of those three issued a given request, letting a gateway apply different rate limits to, say, a long-lived teammate versus a one-shot subagent, without tracking ID-reuse patterns itself.

x-claude-code-prev-tool-durations

This one is new territory — nothing in the existing docs names a “previous tool duration” concept directly. The most consistent reading, given the header fires per-request rather than per-session, is that it reports how long the tool call(s) immediately preceding this API request took to execute. For a gateway, that’s a way to correlate upstream latency (yours) against tool latency (the developer’s local environment, MCP servers, subprocess calls) without cross-referencing Claude Code’s own session logs. If your dashboards currently can’t tell “the model was slow” from “the last Bash command was slow,” this header is aimed at that gap.

x-claude-code-compaction and x-claude-code-context-compacted

Claude Code compacts long conversations automatically once they approach the context limit, replacing older turns with a summary. The protocol docs’ prompt caching section already flags what happens when a gateway mishandles cache markers: “the conversation bills as uncached input on every turn, visible as high input_tokens with little or no cache activity.” Compaction is one of the few events that legitimately invalidates a cached prefix — the summarized history is a different system/messages structure than what was cached a moment ago.

Two separate headers suggest two separate signals: x-claude-code-compaction likely indicates a request that triggers or requests compaction, while x-claude-code-context-compacted likely flags a request sent after compaction has already happened. For a gateway with its own prompt-caching layer, the second one especially is useful as an early warning that the next cache lookup for this session is expected to miss — instead of finding out only after usage.cache_read_input_tokens drops to zero.

Using it today

The flag ships now, in the current release, so you don’t need to wait for anything to try it:

export CLAUDE_CODE_GATEWAY_HINT_HEADERS=1
export ANTHROPIC_BASE_URL="https://your-gateway.internal"
claude

To see the real values before writing any gateway logic against them, run a session with debug logging and inspect the outbound request headers directly rather than trusting a summary (including this one):

claude --debug

A minimal gateway-side extraction, for routing or metrics purposes only — remember the protocol docs’ rule that everything except anthropic-version, anthropic-beta, and (on the Claude Platform on AWS) anthropic-workspace-id is yours to consume and does not need to be forwarded upstream:

request_class = request.headers.get("x-claude-code-request-class")
agent_type = request.headers.get("x-claude-code-agent-type")
prev_durations = request.headers.get("x-claude-code-prev-tool-durations")

# Route classifier-style traffic to a cheaper rate-limit bucket,
# tag latency metrics by agent type, without touching the request body.
metrics.increment(f"claude_code.requests.{agent_type or 'unknown'}")
if request_class:
    metrics.increment(f"claude_code.request_class.{request_class}")

Two practical notes before you build on this:

  1. Don’t hardcode enum values. Because the header contents aren’t published yet, treat whatever strings you observe today as provisional. The protocol docs explicitly warn that Claude Code’s header and field set is an open list that grows across releases — a gateway “pinned to an observed list strips the next capability’s header or field and breaks it on the release that introduces it.” Match on presence and log the raw value; don’t branch on an assumed fixed set of strings.
  2. These headers are opt-in for a reason. Unlike x-claude-code-session-id, which is always sent, the hint headers only appear when a developer sets the environment variable. If you’re building a gateway product for other teams, document that this flag needs to be set client-side — it’s not something your gateway can request or infer on its own.

Why gateways couldn’t do this reliably before

Before these headers existed, a gateway that wanted to tell a classifier request apart from a normal turn had to guess from the request body — typically by checking whether the system array was short or missing the usual project context. That approach breaks the moment Claude Code changes what a classifier request’s body looks like, and the protocol docs are explicit that body shape changes across releases without notice: “Claude Code gains capabilities over releases, and they arrive as new anthropic-beta values, new request body fields, and occasionally new anthropic-* or x-claude-code-* headers.” A header the gateway can match on directly is far more stable than a heuristic over body structure that was never a documented contract in the first place.

The same logic applies to subagent cost attribution. Before x-claude-code-agent-id existed, splitting a session’s spend across parallel subagents meant either trusting whatever the subagent put in its own output or not splitting it at all. Headers turn an inference problem into a lookup.

Building a full attribution key

None of the five hint headers replace the three always-on headers — they extend them. A gateway that wants a complete per-request attribution row for a cost dashboard now has, in principle, up to five fields to key on instead of two:

FieldSourceGranularity
Sessionx-claude-code-session-idOne Claude Code invocation
Spawning agentx-claude-code-parent-agent-idOne link in a nested-agent chain
Requesting agentx-claude-code-agent-idOne subagent instance
Agent kindx-claude-code-agent-type (hint)Main session / subagent / teammate
Request purposex-claude-code-request-class (hint)Conversation turn / classifier call / other

A cost dashboard keyed only on session ID tells you “this session cost $4.10.” The same dashboard keyed on all five fields can tell you “this session cost $4.10, of which $0.90 came from three parallel subagents, and $0.05 came from auto-mode classifier calls that never touched the model the developer thinks they’re paying for.” That second sentence is the kind of line finance teams ask engineering to produce manually today.

A scope caveat worth flagging

The gateway protocol reference is written primarily around gateways that speak the Anthropic Messages format — the one selected by ANTHROPIC_BASE_URL — as opposed to Bedrock InvokeModel or Google Cloud’s Agent Platform rawPredict, which carry capability flags as request-body fields rather than headers in several documented cases. The changelog entry for these five headers doesn’t specify whether they’re emitted identically across all three transport formats. If your gateway fronts Bedrock or Vertex rather than terminating the Anthropic Messages format directly, confirm with claude --debug before assuming the headers show up the same way.

FAQ

Do I need to update my gateway code to keep working with Claude Code v2.1.273?

No. The five hint headers are additive and opt-in — nothing changes for a gateway that ignores them, and nothing breaks if you never set CLAUDE_CODE_GATEWAY_HINT_HEADERS=1.

What Claude Code version do I need?

v2.1.273 (September 15, 2026) or later.

Are the hint header values documented anywhere?

Not as of this writing. The changelog names the five headers; the dedicated LLM gateway protocol reference page doesn’t list them yet. Use claude --debug to inspect real values before writing routing logic against them.

Do I need to forward these headers to the upstream model provider?

No. Per the protocol docs, only anthropic-version, anthropic-beta, and (for the Claude Platform on AWS) anthropic-workspace-id must reach the upstream unchanged. The x-claude-code-* headers, hint headers included, are yours to consume for routing, attribution, or tracing and don’t need to be forwarded.

Does this replace x-claude-code-session-id and x-claude-code-agent-id?

No. Those two (plus x-claude-code-parent-agent-id) are always sent regardless of this flag. The five new headers add detail on top of them; they don’t replace the existing attribution mechanism.

Anthropic ships gateway-facing changes through the changelog before the protocol reference catches up often enough that it’s a pattern, not a one-off. If you maintain a gateway integration, checking the changelog directly — not just the reference pages — is the only way to see a change like this on day one instead of whenever the docs team gets to updating the header table. Our gallery tracks the rule and config files teams write around exactly this kind of gap between “shipped” and “documented.”

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules