Skip to content

Update spec to v2.1.234; read methods and headers from the binary - #9

Open
lroolle wants to merge 2 commits into
mainfrom
spec/v2.1.234
Open

Update spec to v2.1.234; read methods and headers from the binary#9
lroolle wants to merge 2 commits into
mainfrom
spec/v2.1.234

Conversation

@lroolle

@lroolle lroolle commented Aug 18, 2026

Copy link
Copy Markdown
Member

Documents @anthropic-ai/claude-code@2.1.234 and corrects the extraction method this repo has used since releases went binary-only.

The correction

Every previous revision of this repo carried the same caveat:

Header sets, request bodies and timeouts are not recoverable from a Bun binary — those are read from v2.1.76, the last release with a readable bundle, and carried forward explicitly labelled.

That was wrong, and it has been wrong since v2.1.117. The binary embeds the entire minified JavaScript bundle as printable text. It reads as one enormous line, so rg -A/-B context returns nothing useful and "not recoverable" looked like a fair conclusion. Cut a fixed byte window instead and the call site is right there, complete:

fs.get("/v1/ultrareview/quota", {auth: "teleport-org", timeout: 3000})
this._client.post(Fa`/v1/tunnels/${e}/certificates?beta=true`, {
  body: o, ...r,
  headers: yi([{"anthropic-beta": [...n ?? [], "mcp-tunnels-2026-06-22"]...

Methods, header sets, auth modes, timeouts and beta flags for v2.1.234 are now read from v2.1.234, not carried forward from a two-year-old release. The same method works retroactively on older binaries.

Auth modes — the most useful thing recovered

axios call sites name their auth mode, and the mode decides the entire header set:

auth: Headers
teleport-org Authorization, Content-Type, anthropic-version, anthropic-client-platform, x-organization-uuidand substitutes the literal :orgUUID in the path
session-jwt Authorization: Bearer <session access token> only
claude-ai-oauth Authorization, anthropic-beta: oauth-2025-04-20
none no auth headers
async / unset resolved OAuth headers, or x-api-key under API-key auth

That last row also solves a long-standing oddity: paths in the constant pool contain :orgUUID verbatim because the auth layer, not the call site, substitutes it.

Two pre-flight refusals apply to every axios call before a request is made: essential-traffic-only mode, and a non-first-party provider (data-residency).

New scripts

None of them hardcodes a minified identifier.

Script What it does
extract-routes.py method + path + beta + auth + timeout per call site. Anchors the SDK shape on the literal _client., detects axios instances by frequency, resolves hoisted path constants. 242 routes (129 SDK, 114 axios), 120 with a beta flag.
extract-calls.py printable byte window per endpoint anchor — replaces the rg -B 10 -A 20 cli.js recipe that a one-line bundle broke.
binary-literals.sh binary → one-literal-per-line text; the input validate-spec.sh needs for a compiled release.

validate-spec.sh fixes

  • Trims captures at URL-invalid characters — a binary capture runs straight into adjacent data (/api/hello,{headers:{).
  • Widens the path scope to the families the specs actually cover (/v1/code, /v1/vaults, /v1/agents, /worker/…, …), which were silently reported as phantoms.
  • Normalises {server_id}-style placeholders alongside ${…}.
  • Takes --routes to union in the call-site table, so a path assembled from a template (/v1/environments/${id}/work/${w}/ack — never a whole literal) stops reading as a phantom.
  • Adds a # PATH-ONLY declaration for a path literal whose call site builds it through a helper the route extractor doesn't follow. The path is verified, the method is not, and the spec says so instead of guessing. 47 such paths — so "0 undocumented" means every path literal is accounted for, not that every method is known.

Both gates pass: 0 undocumented, 0 phantom for claude-code-api-complete.http and (in --subset mode) claude-oauth-api.http.

Surface changes

101 path literals (+33 vs v2.1.197), 53 beta flags (+9), 161 routes newly written up.

New families: self-hosted runner pools, MCP tunnels, dreams, deployments, Design consent/grants, ultrareview quota, a much larger frame (Artifact) surface, local/org memory, and plugin/skill search.

Removed — verified absent, commented out as history rather than deleted: /api/claude_code/discovery/team_usage, /api/claude_code/team_memory, /api/claude_code/user_settings, /api/oauth/claude_cli/client_data, /v1/code/egress/gateway, /v1/code/upstreamproxy, and the bare /v1/code/ root.

Gateway protocol document

Grew 9,598 → 13,246 bytes; recovered whole to extractions/v2.1.234/GATEWAY-PROTOCOL.md. New sections: the overage 429 header contract (including the trap where sending representative-claim makes the client drop your message), TLS leaf-certificate pinning, client guarantees, and proxying to Bedrock/Vertex/Foundry.

specs/claude-code-gateway.http validates as "phantom" by design — it specifies the server side, and the CLI resolves those paths from the gateway's own discovery document. A note in the spec now says so.

Cross-check against live traffic

WORKFLOW.md's rule stands: endpoints are never inferred from runtime logs. Section 43 goes the other way — it checks header sets already read from the binary against a local capture of one live v2.1.234 session. The capture confirms the auth-mode table exactly (/v1/code/triggers and /v1/ultrareview/quota went out with the full teleport-org set; /mcp-registry/v0/servers with no authorization at all).

No identifiers, tokens, request-ids or organization UUIDs from that capture appear anywhere in this repository.

🤖 Generated with Claude Code

lroolle and others added 2 commits August 18, 2026 00:12
Documents @anthropic-ai/claude-code@2.1.234 and corrects the extraction method
this repo has used since releases went binary-only.

The correction. Every previous revision carried this caveat:

  Header sets, request bodies and timeouts are NOT recoverable from a Bun
  binary -- those are read from v2.1.76, the last release with a readable
  bundle, and carried forward explicitly labelled.

That was wrong, and has been since v2.1.117. The binary embeds the entire
minified JavaScript bundle as printable text. It reads as one enormous line, so
`rg -A/-B` context returns nothing useful and "not recoverable" looked like a
fair conclusion. Cut a fixed byte window instead and the call site is complete:

  fs.get("/v1/ultrareview/quota", {auth: "teleport-org", timeout: 3000})

Methods, header sets, auth modes, timeouts and beta flags for v2.1.234 are now
read from v2.1.234.

Auth modes -- the most useful thing this recovered. axios call sites name their
auth mode and the mode decides the whole header set:

  teleport-org      Authorization + Content-Type + anthropic-version +
                    anthropic-client-platform + x-organization-uuid, and
                    substitutes the literal ":orgUUID" in the path -- which is
                    why paths in the constant pool contain it verbatim
  session-jwt       Authorization: Bearer <session access token>, nothing else
  claude-ai-oauth   Authorization + anthropic-beta: oauth-2025-04-20
  none              no auth headers
  async / unset     resolved OAuth headers, or x-api-key under API-key auth

Two pre-flight refusals apply to every axios call: essential-traffic-only mode,
and a non-first-party provider (data-residency).

New scripts, none hardcoding a minified identifier:

  extract-routes.py   method + path + beta + auth + timeout per call site.
                      Anchors the SDK shape on the literal `_client.`, detects
                      axios instances by frequency, resolves hoisted path
                      constants. 242 routes (129 SDK, 114 axios).
  extract-calls.py    printable byte window per endpoint anchor, replacing the
                      `rg -B 10 -A 20 cli.js` recipe that a one-line bundle
                      broke.
  binary-literals.sh  binary -> one-literal-per-line text; the input
                      validate-spec.sh needs for a compiled release.

validate-spec.sh: trims captures at URL-invalid characters (a binary capture
runs straight into adjacent data), widens the path scope to the families the
specs actually cover, normalises {server_id}-style placeholders, and takes
--routes so template-built paths stop reading as phantoms. Adds a `# PATH-ONLY`
declaration for a path literal whose call site builds it through a helper the
route extractor does not follow: the path is verified, the method is not, and
the spec says so instead of guessing. 47 such paths.

Both gates pass: 0 undocumented, 0 phantom for claude-code-api-complete.http
and (--subset) claude-oauth-api.http.

Surface changes: 101 path literals (+33), 53 beta flags (+9), 161 routes newly
written up. New families -- self-hosted runner pools, MCP tunnels, dreams,
deployments, Design consent/grants, ultrareview quota, a much larger frame
(Artifact) surface, local/org memory, plugin and skill search. Removed and
commented out as history: team_usage, team_memory, user_settings,
claude_cli/client_data, /v1/code/egress/gateway, /v1/code/upstreamproxy, and the
bare /v1/code/ root.

The embedded gateway protocol document grew 9,598 -> 13,246 bytes; recovered
whole to extractions/v2.1.234/GATEWAY-PROTOCOL.md. New sections: the overage
429 header contract, TLS leaf-certificate pinning, client guarantees, and
proxying to Bedrock/Vertex/Foundry.

Section 43 records a cross-check of the binary-derived header sets against a
local capture of one live v2.1.234 session. This does not infer endpoints from
runtime logs -- it checks facts already read from the binary. No identifiers,
tokens, request-ids or organization UUIDs from that capture appear anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Section 42 is ~1,700 lines of request blocks derived mechanically from
raw/routes.tsv. Those lines were generated, but the generator lived in /tmp --
so the largest single artifact in the change had no provenance, which is exactly
the thing this repo exists to avoid.

scripts/gen-spec-section.py now ships. It rewrites the section in place from the
route table and is idempotent: run it twice, get the same bytes (verified). The
split is explicit -- request blocks are generated, family grouping and prose are
authored and live in the FAMILIES table inside the script, so editing prose in
the .http file would be lost on the next run.

This is also what makes the diff reviewable: the generated block is skimmed and
re-derived, and review attention goes to the 370 lines of extraction scripts and
the prose.

Both gates still report 0 undocumented, 0 phantom.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lroolle

lroolle commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Review note: provenance for the generated section

Pushed 68094b0. One real defect in the original push: Section 42 is ~1,700 lines of request blocks derived mechanically from raw/routes.tsv, but the generator lived in /tmp. The largest artifact in the diff had no provenance — the exact failure mode this repo exists to prevent.

scripts/gen-spec-section.py now ships. Idempotent (verified: two consecutive runs are byte-identical), rewrites the section in place, and makes the split explicit:

  • generated — the request block per route: method, URL, the header set implied by its auth mode, and a comment carrying source / beta / auth / timeout as read from the call site
  • authored — the family grouping and prose, in the FAMILIES table inside the script. Editing prose in the .http file would be dropped on the next run, so it lives where it survives.

How to review this PR

Surface Lines How to read it
Extraction scripts 370 read closely — this is the new logic
Prose: SUMMARY, README, WORKFLOW, FAMILIES ~690 read
.http Section 42 ~1,766 skim; re-derive with scripts/gen-spec-section.py 2.1.234 <literals>
raw/*.tsv 644 the completeness record; routes.tsv is the one that matters
calls/*.txt 808 evidence windows, cited by offset from the specs — grep, don't read

Reproduce end to end:

scripts/binary-literals.sh <binary> /tmp/literals.txt
scripts/extract-routes.py <binary> --all extractions/v2.1.234/raw/routes.tsv
scripts/gen-spec-section.py 2.1.234 /tmp/literals.txt
scripts/validate-spec.sh --routes extractions/v2.1.234/raw/routes.tsv \
  /tmp/literals.txt specs/claude-code-api-complete.http

Known follow-up, deliberately not in this PR

claude-code-api-complete.http is now 4,289 lines and grew ~40% in one release. The same breadth information is in routes.tsv in 243 lines. Worth considering whether routes.tsv should become the breadth record, with the .http file carrying only curated endpoints that earn a body and a paragraph. That changes the repo's contract, so it belongs in its own PR rather than riding along with a version bump.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant