Skip to content

Spike Claude Code Messages compatibility through CodexHub #74

Closed

Description

@NOirBRight

Part of #73.

Blocked by: nothing (native dependencies). This is the first gate of the campaign.

Status: needs-info. The remaining acceptance criteria cannot be completed without approved live upstream access and explicit authorization to use it. Historical scoped-PARTIAL evidence exists (PR #100 at 0aa1f3d3449264437c3c9efe097417bc31c3443c) but it establishes message shapes, not three-protocol readiness. It is historical and must not be cited as a GO.

Objective

Re-establish the exact Claude Code → CodexHub wire contract with a pinned real Claude Code CLI against approved real upstream access, for all three upstream protocols, and record a GO / scoped-PARTIAL / NO-GO decision for production /v1/messages support.

This is an evidence gate. Do not add production routing, client configuration, or client UI in this issue.

Authority and prior decisions

  • ADR-0014 replaces ADR-0001's blanket rejection of non-equivalent options with declared best-effort adaptation. This Spike must supply the evidence that policy is safe, field by field.
  • ADR-0001's representation seam, ordered content, opaque-field preservation, credential separation, and declared-adaptation outcomes still stand.
  • Product decisions (three protocols, full model picker, critical-content safety) are canonical in Track Claude Code as an external CodexHub Gateway client #73.

Scope

1. Pin the client

  • Install and record the exact Claude Code executable version, platform, and runtime. Historical public-source evidence used v2.1.207; prior local evidence used 2.1.201. This campaign currently observes installed 2.1.278; test that exact binary without treating historical pins as a supported-version floor. Record the version actually used, and never present one version's result as another's.
  • Record the startup traffic actually observed: POST /v1/messages (and ?beta=true path-vs-query matching), optional POST /v1/messages/count_tokens, any best-effort HEAD/connectivity probe, and model discovery.

2. Model roles and discovery (facts to establish, not assume)

  • Which environment variables / config fields the pinned CLI actually honors for: main model, fast/background model, subagent model, and any single custom-model option.
  • Whether discovery runs by default, its exact request (GET /v1/models?limit=1000, three-second timeout, redirect and auth behavior), and the exact response shape it requires: envelope fields, paging fields, display metadata, and required ID form.
  • Whether the pinned CLI enforces a model-ID prefix rule (e.g. claude*/anthropic*) on discovery results or accepts arbitrary IDs. This decides how Expose every Gateway model to Claude Code with fixed-name and role mapping #77 can make every exported model selectable.
  • Refresh behavior: what makes Claude Code pick up a changed model list (restart, cache, TTL).
  • Whether an explicit in-session model selection is overridden by any role mapping or default, and what the CLI reports as the effective model.
  • Exact role/alias names the CLI sends or hardcodes, captured as observed strings.

3. Credential carrier

  • Observe which carrier the pinned CLI sends under a documented configuration: Authorization: Bearer from ANTHROPIC_AUTH_TOKEN, x-api-key from ANTHROPIC_API_KEY, both, or apiKeyHelper.
  • Recommend what the Gateway must accept, without weakening Harden local Gateway auth so codex-app context is not spoofable #24, and state the fail-closed default when the carrier is wrong.

4. Capability classification across all three upstream protocols

Exercise the isolated translator prototype against real, approved upstreams of each format — native Anthropic Messages, OpenAI Responses, and Chat Completions — through CodexHub. For each format, classify: text, incremental SSE, multi-turn history, one tool call + tool_result follow-up, parallel tools, images, thinking/effort, anthropic-beta/body pairs, prompt caching, compaction/resume, subagents, count_tokens, usage, cancellation, and error/retry behavior as preserved, adapted (named policy) or explicitly unsupported, each with sanitized evidence.

5. Native-path fidelity

Prove what the Anthropic upstream path preserves end to end — semantic headers, ordered content blocks, opaque/unmodelled fields, JSON and SSE event order — and exactly what the Gateway rewrites (model identity, credentials, transport safety). The native path must not lose a field merely because a cross-protocol adapter cannot represent it.

6. Live access is a prerequisite, not an inference

  • Live evidence requires upstream access that is explicitly approved for this use. A provider being configured in the user's catalog is not consent, and no credential material belongs in this issue or its fixtures.
  • If approval is not granted, record the concrete blocker and leave this issue in needs-info; do not substitute mock-only results for the live criteria.

7. Downstream deliverables

  • Re-establish the pure AnthropicMessage representation seam required by ADR-0001/ADR-0014, reusing existing logic where compatible; do not reopen the accepted seam implicitly.
  • Record each non-equivalent field's named adaptation policy and the diagnostic text it produces (feeds Add inbound Anthropic Messages API for Claude Code clients #75 and the client card's compatibility state).
  • Update docs/reviews/v0.3-agent-provider-roadmap.md to keep downstream client support distinct from upstream AgentProvider work.

Out of scope

Production /v1/messages registration, codex_proxy.py handler integration, client configuration or launcher, discovery UI, aliases, and any AgentProvider/ACP work.

Acceptance criteria

  • A pinned real Claude Code CLI version and platform are recorded, and every claim names the version it was observed on.
  • Endpoint, query-variant, probe, discovery, and role mechanisms are documented as an open-set contract from real observation.
  • Role names/variables, discovery response shape, ID-prefix behavior, refresh behavior, and effective-model reporting are recorded as observed facts.
  • The credential carrier actually used is recorded, with a recommended Gateway acceptance rule that does not weaken Harden local Gateway auth so codex-app context is not spoofable #24.
  • A real "read file → tool call → tool result → final answer" lifecycle succeeds with stable call identity on each approved upstream protocol.
  • Incremental SSE (not buffered) is observed on each approved upstream protocol.
  • Sanitized traces cover request, JSON/SSE response, error, cancellation, and usage shapes for all three protocols, with no credentials or user content.
  • anthropic-version, anthropic-beta, and x-claude-code-* handling policies are documented as open-set contracts.
  • Every non-equivalent field has an explicit named adaptation policy or a fail-closed outcome; nothing is silently dropped.
  • Native Anthropic fidelity (semantic fields + SSE) is proven separately from the converted paths.
  • The report records GO, scoped PARTIAL, or NO-GO for production /v1/messages.
  • The ADR-0001/ADR-0014 representation contract is verified and recorded.
  • No production route or client configuration ships in this change.

Required verification

Risk class: strict (docs/agents/verification-policy.md) — protocol, transport, and auth boundary. Use the repository launcher; never a bare python/pytest.

Targeted checks during the Spike, then the relevant Python full suite once at the candidate commit:

.\scripts\codexhub-python.cmd -m pytest tests/test_route_plan_seam.py tests/test_chat_completions_gateway.py -q
.\scripts\codexhub-python.cmd -m pytest -q --ignore=tests/test_real_client_e2e.py
.\scripts\codexhub-python.cmd scripts/report_quality_gates.py

Linux: ./scripts/codexhub-python.sh ... with the same arguments. Real-CLI evidence is a separate local procedure; record exactly which environment produced it.

References

Document status

ADR-0014 is committed in draft PR #556 at ed76f0a6e22d3188879504638b2943f5bb855d41, not yet merged to main. The pinned link is readable now; the document is accepted direction, not live protocol evidence.

Activity

  1. self-assigned this
    on Jul 12, 2026
  2. NOirBRight commented on Jul 12, 2026

    @NOirBRight
    OwnerAuthor

    Dispatch

    • Profile: evidence
    • Model: gpt-5.6-terra / max
    • Base: origin/dev@83485089ce1108d44ddba1d0f008afc2d93ce935
    • Branch: codex/issue-74-claude-messages-spike
    • Ownership: isolated Messages prototype, sanitized fixtures/traces, ADR, and roadmap only
    • Prohibited hotset: no production /v1/messages route and no codex_proxy.py handler integration
    • Verification: focused prototype tests, routing/chat tests, report-only quality gates, pinned real Claude CLI evidence
    • Integration parent: none; GO/PARTIAL/NO-GO gates later Claude client work
  3. NOirBRight commented on Jul 12, 2026

    @NOirBRight
    OwnerAuthor

    Plan for #74:

    1. Add a standalone in-memory Anthropic Messages ↔ Responses/Chat translator prototype plus focused sanitized fixtures/tests (text stream, tool/result follow-up, multi-turn, usage, cancellation/error shapes).
    2. Write the pinned protocol evidence and compatibility matrix, then add an ADR and update the v0.3 roadmap with the downstream-client vs upstream-AgentProvider distinction and a GO/PARTIAL/NO-GO decision.
    3. Exercise the prototype with deterministic official-Responses and Chat-Completions adapters, run the required gateway regressions and report-only gate, then attempt the pinned real Claude Code smoke or document its concrete blocker.

    Collision proof: production src-python/codex_proxy.py, route registration, /v1/messages, and client auto-configuration are out of scope; the prototype will live in a new isolated module imported only by its focused tests.

  4. added
    needs-infoWaiting on reporter for more information
    and removed
    ready-for-agentFully specified, ready for an AFK agent
    on Jul 12, 2026
  5. removed their assignment
    on Jul 12, 2026
  6. NOirBRight commented on Jul 12, 2026

    @NOirBRight
    OwnerAuthor

    Scoped-PARTIAL evidence merged in PR #100 at 0aa1f3d.

    Established: pinned local Claude CLI loopback, sanitized text/tool/history/SSE/error/usage evidence, isolated Messages translator/ADR, and fail-closed Chat-stream shape/identity controls. No production route or client configuration shipped.

    Issue #74 remains open. A fresh autonomous worker cannot complete the remaining acceptance gates without approved real-provider access and authorization: official Responses plus one Chat Completions Provider proof, and the documented thinking/cache/image/beta/count-tokens/cancellation/retry compatibility gates. The Issue is therefore moved to needs-info and unassigned; #75-#78 remain blocked.

  7. self-assigned this
    on Sep 20, 2026
  8. NOirBRight commented on Sep 20, 2026

    @NOirBRight
    OwnerAuthor

    Campaign dispatch: draft PR #556, integration branch campaign/claude-code-gateway, decision baseline 3a9154c.

    Assigned implementer works in isolated campaign/claude-ticket-74. Current authorization allows deterministic tests and isolated synthetic loopback only; real upstream resources/limits are requested from the user and remain pending. No production routing or client UI is authorized by this dispatch.

    Concurrent read-only preparation covers #77 discovery/mapping, #78 verification inputs, and overlap with open Clients PRs. Partial evidence will not close this ticket or unblock production descendants. Exact commits/checks and remaining live gates will be recorded before integration.

  9. NOirBRight commented on Sep 20, 2026

    @NOirBRight
    OwnerAuthor

    Offline checkpoint submitted for independent merger review: campaign/claude-ticket-74 @ edd9efd. Implementer reports focused 214 passed / 41 subtests, full Python 3039 passed / 180 skipped, and credential-free Claude 2.1.278 loopback evidence. This is PARTIAL only; no production route or client UI.

    Authorization update: user approved a single Linux isolated round with <=20 actual upstream HTTP attempts per protocol (all retries/auxiliary calls included), <=2048 output tokens/request, <=30 minutes total, no automatic renewal. Responses target requested: Codex / Luna / max. Chat and Anthropic targets requested: CommandCode, but inspect candidates and discuss before choosing/calling. No dedicated credential input paths supplied yet. Therefore no real model call has been authorized to start; exact remaining targets and isolated inputs are still pending.

    Independent model-selection and configuration investigations completed; the discovery substring filter now has actual synthetic-loopback confirmation. The prototype refuses safeguards whose semantics remain unknown, rather than silently weakening them. #75–#78 remain blocked.

  10. added 2 commits that reference this issue on Sep 20, 2026
  11. NOirBRight commented on Sep 20, 2026

    @NOirBRight
    OwnerAuthor

    Offline response/transport checkpoint c8ba0c6 independently reviewed on both axes, merged as d57f486, and published with the reviewed input/admission correction in fbadd78. Combined core:3101 passed/180 skipped/267 subtests; Issue66 matrix reconciled; all three buffered loopback exchange/admission legs pass. Native bytes, truthful usage/zero counts, real source identities, explicit empty Chat text, malformed-success refusal, sanitized converted errors and cancellation guards have scoped regression coverage. This remains PARTIAL: no production /v1/messages route, no true-incremental/live GO. The next isolated #74 slice is native incremental transport with first-text-before-terminal, blocked-read cancellation and hard-deadline checks; converted incremental work remains later. No real upstream calls and no dependent ticket unblocked.

  12. NOirBRight commented on Sep 20, 2026

    @NOirBRight
    OwnerAuthor

    Additional bounded offline observation on fbadd78: pinned Claude Code 2.1.278 (SHA256 5c4735937844e84f8a93306e841a5b0e12252909b07870f789b190468da147ab) completed two text-only CLI+codec runs, one Responses and one Chat. Each first request was refused for safeguards; after the synthetic 400 named that unsupported field, the CLI itself retried without it. No Gateway code stripped it. The second request prepared successfully, a pure deterministic fixture was adapted to 200 SSE, and the CLI exited 0. Two admitted local requests/run, fresh isolated HOME and fake auth, 60-second cap/run; each observed run took 1.30s. Post-run strace found only loopback connections; this is detection, not OS containment. No upstream HTTP/model/real credential was used. This supports codec feasibility, NOT safeguards safety-equivalence, tool support, live transport, true incremental delivery, or production GO. Raw prompt/CLI/HOME records were erased; these are research observations, not the final acceptance artifact.

  13. NOirBRight commented on Sep 21, 2026

    @NOirBRight
    OwnerAuthor

    Native-only incremental relay is now in the campaign draft at 34cf9de (reviewed candidate ec4322b). Offline checks: first text_delta before terminal, real loopback cancellation/deadline via socket abort, complete event preserved before a later oversized frame, timeout bounds stalled polls, commit.cancel on EOF/non-success. Combined core: 3111 passed / 180 skipped / 267 subtests. Converted incremental remains explicitly unsupported. No production /v1/messages route, no live upstream, no GO. Next isolated slice is Responses/Chat incremental conversion; live three-protocol evidence still needs a fresh bounded grant and ready native input.

  14. NOirBRight commented on Sep 21, 2026

    @NOirBRight
    OwnerAuthor

    Converted incremental Responses/Chat relay is now in the campaign draft at 30be460 (reviewed d19cc73). Offline: text_delta before terminal for both converted formats; loopback cancel/deadline; Chat annotations fail closed; Responses streams without real id/model cannot emit fabricated chatcmpl_ UUIDs. Native byte passthrough unchanged. Combined core: 3117 passed / 180 skipped / 267 subtests. Still PARTIAL: no production /v1/messages, no live three-protocol evidence, no GO. Next remaining #74 gate is authorized live evidence with ready native input and a fresh bounded grant.

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestneeds-infoWaiting on reporter for more informationwayfinder:prototypeWayfinder bounded prototype or spike

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions