Claude Code and Codex

September 18, 2026 ยท View on GitHub

Yoshi serves both protocols on one loopback listener. /v1/messages continues to use YOSHI_UPSTREAM (Anthropic). /v1/responses, /responses, their child routes and /v1/models use YOSHI_CODEX_UPSTREAM (default: https://chatgpt.com/backend-api/codex). Compaction child routes pass through. The Codex integration uses HTTP streaming; WebSockets are not implemented.

Start bun start, then invoke Codex with per-process overrides:

codex -c 'model_provider="yoshi"' \
  -c 'model_providers.yoshi={name="Yoshi",base_url="http://127.0.0.1:8790/v1",wire_api="responses",requires_openai_auth=true,supports_websockets=false}'

This uses the existing Codex login. Yoshi forwards authentication but never writes it to traces. No global Codex configuration is changed. Claude Code can continue using ANTHROPIC_BASE_URL=http://127.0.0.1:8790 concurrently.

For OpenAI API-key authentication, set YOSHI_CODEX_UPSTREAM=https://api.openai.com/v1 and use env_key="OPENAI_API_KEY" instead of requires_openai_auth=true in the custom provider. OAuth transport was validated live; the API-key configuration follows the official provider contract but was not separately exercised with a paid key.

What is optimized

The Responses adapter maps addressable text onto the existing Jev policy and maps approved spans back to original Responses items. It does not translate the provider request into Anthropic Messages. Supported payloads include completed function_call argument fields (command, cmd, code, content, patch), custom_tool_call.input, text tool outputs (including stdout inside the real code-mode JSON envelope), new agent reports. Execution/write tools include exec, exec_command, shell, shell_command, apply_patch, write_file, append_to_file, and js. Only uniquely paired, completed historical code is eligible. Snapshot input payloads require 256 characters. Sticky input eligibility uses the configured text minimum and preserves paired completion receipts. Call IDs, namespace, status, paths, other arguments, annotations and unrelated item fields survive.

Each payload span goes to Jev separately, with up to eight concurrent calls. Indivisible oversized lines remain whole; a payload exceeding the judge budget stays unchanged. Invalid answers, errors and deadlines retain content. The default uses the shared sticky lifecycle and size gate for mixed conversations too. Decisions persist as hashes/verdicts in YOSHI_DECISIONS, and later human turns do not reopen old judgments. Human/developer/system instructions and assistant notes stay intact. Restart continuity, expiry, capacity and configuration limits are the same as Messages. Snapshot mode retains the older per-task behavior only for explicit experiments.

Encrypted reasoning, compaction blobs, images, tool schemas and developer/system instructions remain intact. They are reported separately, not counted as pruning savings. Requests using previous_response_id pass through without optimization: a server-held prefix is unavailable for local relevance judgment. This is explicitly logged as server-held-prefix.

Measurement

Use the consolidated report for measured numbers, including the latest Claude regression and incomplete Jev costs. Benchmark instructions cover reproduction. bun run summary separates Messages and Responses accounting in mixed logs. Provider input totals are different across the two APIs: Responses already includes cached input; do not add it twice.

The local Codex audit is diagnostic evidence, not a savings benchmark. Rebuild it with bun run codex:profile; private conversation text remains local. Encrypted reasoning and compaction are measured separately from readable text and never interpreted as token counts from ciphertext length.

Official references consulted for the integration on 2026-09-17: