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: