An experimental local adapter that lets the Codex app and CLI use the Claude
Code fable model alias through an OpenAI Responses-compatible endpoint.
Codex remains the agent runtime: it owns tools, approvals, filesystem access, and the conversation loop. Claude Fable chooses either one final response or one Codex function call per model turn. The adapter translates that decision into Responses API server-sent events.
This is an independent proof of concept, not an OpenAI or Anthropic product. Both Codex's provider contract and Claude Code's CLI flags can change. Review the relevant product terms before using subscription-backed authentication in an adapter.
The working setup required more than pointing Codex at claude -p:
- Implement a local
/v1/responsesbridge that translates Codex messages, function definitions, function calls, function outputs, and usage data. - Return the exact Responses streaming events the installed Codex client expects, even though Claude's structured-output call completes first.
- Expose
/v1/models. Without it, Codex ran but reported an unknown model and used incomplete fallback metadata. - Derive a Fable catalog entry from the installed Codex catalog, then clear
inherited
tool_modeandmulti_agent_versionrestrictions. Copying a native model entry unchanged caused Codex to omit shell tools. - Add the custom provider to user-level
~/.codex/config.tomland pointmodel_catalog_jsonat a generated local catalog. - Keep the adapter alive for the desktop app with a macOS LaunchAgent.
- For one combined picker, route
fableto Claude and native model IDs back to the normal Codex backend. This mode is optional and security-sensitive.
OpenAI's current Codex documentation supports custom providers and recommends the Responses wire API; Chat Completions support is deprecated:
- Node.js 20 or newer
- A current Codex app or CLI
- Claude Code installed and authenticated
- An account for which this succeeds:
claude -p --model fable --effort high --tools "" \
--no-session-persistence "Reply with exactly: FABLE_OK"The prototype was last verified with Codex CLI 0.144.2 and Claude Code
2.1.210. Fable availability is account-dependent.
git clone https://github.com/michaelvu1207/codex-fable-adapter.git
cd codex-fable-adapter
npm test
npm run build-catalogThe build creates two local, gitignored files:
fable-models.json: only Fable, recommended for the simplest setupcombined-models.json: Fable plus the native Codex catalog
Run in the foreground:
npm start
curl -s http://127.0.0.1:8741/healthOr install the macOS LaunchAgent:
npm run install-serviceThe installer discovers the current Node binary, claude executable, home
directory, and repository path. Remove it with npm run uninstall-service.
The health endpoint checks that the Claude CLI is executable; the direct
FABLE_OK probe above is the authentication and model-availability check.
Back up ~/.codex/config.toml, then add or update these top-level settings.
Replace /ABSOLUTE/PATH with the cloned repository path.
model = "fable"
model_provider = "claude_fable"
model_catalog_json = "/ABSOLUTE/PATH/codex-fable-adapter/fable-models.json"
model_reasoning_effort = "high"
[model_providers.claude_fable]
name = "Claude Fable (local adapter)"
base_url = "http://127.0.0.1:8741/v1"
wire_api = "responses"
request_max_retries = 0
stream_max_retries = 0
stream_idle_timeout_ms = 900000Start a new Codex task. Restart the desktop app because
model_catalog_json is loaded at startup.
Verify the catalog and a real turn:
codex debug models | jq '.models[] | {slug, display_name, tool_mode}'
codex exec --skip-git-repo-check --ephemeral \
"Reply with exactly: FABLE_IN_CODEX_OK"Combined mode lets the local provider advertise both Fable and the native Codex models. It is opt-in because the adapter must receive Codex's ChatGPT authorization headers and forward them in memory for non-Fable requests. Read SECURITY.md first.
Install the service in combined mode:
npm run install-service -- --combinedPoint model_catalog_json at combined-models.json and add this line to the
same provider block:
requires_openai_auth = trueThe service sets CODEX_FABLE_ENABLE_OPENAI_PASSTHROUGH=1. Fable requests go
to Claude Code; every other model ID is proxied to the normal Codex backend.
Re-run npm run build-catalog after a Codex update changes its native catalog.
| Variable | Default | Purpose |
|---|---|---|
CLAUDE_FABLE_HOST |
127.0.0.1 |
Listening interface; keep loopback-only |
CLAUDE_FABLE_PORT |
8741 |
Listening port |
CLAUDE_FABLE_CLI |
claude |
Claude Code executable |
CLAUDE_FABLE_MODEL |
fable |
Claude model alias |
CLAUDE_FABLE_EFFORT |
high |
Claude effort level |
CLAUDE_FABLE_TIMEOUT_MS |
900000 |
Per-turn timeout |
CLAUDE_FABLE_MAX_BUDGET_USD |
unset | Optional Claude invocation cap |
CLAUDE_FABLE_PICKER_CATALOG |
unset | Catalog returned by /v1/models |
CODEX_FABLE_ENABLE_OPENAI_PASSTHROUGH |
unset | Enables native-model proxying when 1 |
- Text and Codex function tools are supported. Image bytes and provider-native web-search events are not translated.
- Text arrives as one delta rather than token-by-token because the structured Claude call finishes before the adapter emits Responses events.
- Only one tool call is requested per model turn. Codex can continue the loop with additional turns, but parallel tool calls are disabled.
- Namespaced tools are flattened to names such as
agents.spawn; this path has unit coverage but has not received the same end-to-end smoke testing. - The model catalog format and internal ChatGPT Codex passthrough endpoint are implementation details and can change between Codex releases.
- Fable usage and availability are governed by the authenticated Claude account, independently of Codex usage.
Codex app or CLI
-> POST /v1/responses
-> local adapter
-> claude -p --model fable --json-schema ...
-> final text or one function call
-> Responses SSE events
-> Codex executes tools and continues the loop