Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/aradotso_codex-skills.json
T

1 line
30 KiB
JSON

{"repo": "aradotso/codex-skills", "files": {"skills/codex-shim-byok-models/SKILL.md": {"ed60f86664b7ac81b98339bf8d41f2dac02a70a6": {"t": 1785746411.1237373, "n": 14110, "h": "59affcc6a7feebc1", "c": "---\nname: codex-shim-byok-models\ndescription: Run Codex Desktop with Factory BYOK models and ChatGPT GPT-5.5 via local API shim\ntriggers:\n - how do I use custom models in Codex Desktop\n - set up codex-shim with Factory models\n - expose my OpenAI API key to Codex\n - add custom models to Codex picker\n - route Codex through local shim server\n - patch Codex Desktop model allowlist\n - configure BYOK models for Codex\n - use ChatGPT subscription with Codex Desktop\n---\n\n# Codex Shim BYOK Models\n\n> Skill by [ara.so](https://ara.so) — Codex Skills collection.\n\n## Overview\n\n**codex-shim** is a local Python API shim that intercepts Codex Desktop's model requests and routes them to:\n- Any model in your `~/.factory/settings.json` (Factory BYOK)\n- Your ChatGPT subscription GPT-5.5\n- Custom OpenAI/Anthropic/generic chat completion endpoints\n\nIt exposes a local Responses API endpoint that Codex Desktop points to, bypassing Codex's server-side Statsig model allowlist.\n\n**Key capabilities:**\n- Use any OpenAI, Anthropic, DeepSeek, Gemini, OpenRouter, or Z.ai model\n- Keep ChatGPT subscription GPT-5.5 alongside BYOK models\n- No modification to `~/.codex/config.toml` (uses launch-time overrides)\n- Translates between Codex Responses API ↔ upstream APIs (OpenAI chat completions, Anthropic messages)\n\n## Installation\n\n```bash\n# Clone repository\ngit clone https://github.com/0xSero/codex-shim ~/Documents/codex-shim\ncd ~/Documents/codex-shim\n\n# Install Python dependencies (requires 3.11+)\npython3 -m pip install --user aiohttp pytest\n\n# Symlink commands to PATH\nln -s \"$PWD/bin/codex-shim\" ~/.local/bin/codex-shim\nln -s \"$PWD/bin/codex-app\" ~/.local/bin/codex-app\nln -s \"$PWD/bin/codex-model\" ~/.local/bin/codex-model\n```\n\nVerify installation:\n```bash\ncodex-shim --help\n```\n\n## Configuration\n\n### Factory Settings File\n\nThe shim reads `~/.factory/settings.json` by default. Structure:\n\n```json\n{\n \"customModels\": [\n {\n \"model\": \"gpt-5.5\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://api.openai.com/v1\",\n \"apiKey\": \"${OPENAI_API_KEY}\",\n \"displayName\": \"OpenAI GPT-5.5\",\n \"maxContextLimit\": 400000\n },\n {\n \"model\": \"claude-opus-4-7-20251109\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.anthropic.com/v1\",\n \"apiKey\": \"${ANTHROPIC_API_KEY}\",\n \"displayName\": \"Claude Opus 4.7\"\n },\n {\n \"model\": \"deepseek-v4-pro\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.deepseek.com/anthropic\",\n \"apiKey\": \"${DEEPSEEK_API_KEY}\",\n \"displayName\": \"DeepSeek V4 Pro\",\n \"noImageSupport\": true\n }\n ]\n}\n```\n\n**Supported providers:**\n- `openai` → OpenAI `/v1/chat/completions`\n- `generic-chat-completion-api` → OpenAI-compatible endpoints\n- `anthropic` → Anthropic `/v1/messages`\n\n### Custom Config Path\n\n```bash\ncodex-shim --settings /path/to/custom-models.json generate\ncodex-shim --settings /path/to/custom-models.json start\n```\n\n### Environment Variables\n\nStore API keys in environment:\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\nexport DEEPSEEK_API_KEY=\"...\"\n```\n\n## Key Commands\n\n### Generate Catalog\n\nReads Factory settings and creates `.codex-shim/custom_model_catalog.json`:\n\n```bash\ncodex-shim generate\n```\n\n### Start/Stop Daemon\n\n```bash\n# Start shim on 127.0.0.1:8765\ncodex-shim start\n\n# Check status\ncodex-shim status\n\n# Stop daemon\ncodex-shim stop\n\n# Restart\ncodex-shim restart\n```\n\n### List Available Models\n\n```bash\n# Show all generated slugs and upstream routes\ncodex-shim list\n\n# Show models currently in Codex Desktop picker\ncodex-model list\n```\n\n### Launch Codex Desktop\n\n```bash\n# Launch with shim wired in (doesn't modify ~/.codex/config.toml)\ncodex-app\n\n# Launch and open specific path\ncodex-app /path/to/project\n\n# Equivalent long form\ncodex-shim app /path/to/project\n```\n\n### Switch Active Model\n\n```bash\n# List available slugs\ncodex-model list\n\n# Set default model for next launch\ncodex-model openai-gpt-5-5\n\n# Relaunch Codex\ncodex-app\n```\n\n### Run Codex CLI Through Shim\n\n```bash\ncodex-shim codex -- chat \"explain this code\"\ncodex-shim codex -- edit main.py \"add error handling\"\n```\n\n## Model Routing Architecture\n\n```\nCodex Desktop → /v1/responses → codex-shim (127.0.0.1:8765)\n ┃\n ┏━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┓\n ┃ ┃ ┃\n slug \"openai-gpt-5-5\" provider provider\n ┃ \"openai\" \"anthropic\"\n ┃ ┃ ┃\n chatgpt.com/backend-api baseUrl/ baseUrl/\n /codex/responses chat/ messages\n (Bearer token) completions (x-api-key)\n```\n\nThe shim:\n1. Receives Codex Responses API request\n2. Looks up slug in catalog\n3. Translates to upstream format (OpenAI chat completions or Anthropic messages)\n4. Streams upstream response\n5. Translates back to Responses API format\n\n## Code Examples\n\n### Python: Implementing Custom Provider Translation\n\n```python\n# codex_shim/translator.py example pattern\n\nasync def translate_to_openai(responses_request):\n \"\"\"Convert Codex Responses API → OpenAI chat completions.\"\"\"\n return {\n \"model\": responses_request[\"model\"],\n \"messages\": responses_request[\"messages\"],\n \"stream\": True,\n \"temperature\": responses_request.get(\"temperature\", 1.0),\n \"max_tokens\": responses_request.get(\"max_tokens\"),\n }\n\nasync def translate_to_anthropic(responses_request):\n \"\"\"Convert Codex Responses API → Anthropic messages.\"\"\"\n messages = []\n system = None\n \n for msg in responses_request[\"messages\"]:\n if msg[\"role\"] == \"system\":\n system = msg[\"content\"]\n else:\n messages.append({\n \"role\": msg[\"role\"],\n \"content\": msg[\"content\"]\n })\n \n body = {\n \"model\": responses_request[\"model\"],\n \"messages\": messages,\n \"stream\": True,\n \"max_tokens\": responses_request.get(\"max_tokens\", 4096),\n }\n \n if system:\n body[\"system\"] = system\n \n return body\n```\n\n### Python: Adding Custom Model Programmatically\n\n```python\nimport json\nfrom pathlib import Path\n\ndef add_custom_model(model_config):\n \"\"\"Add model to Factory settings.\"\"\"\n settings_path = Path.home() / \".factory\" / \"settings.json\"\n \n if settings_path.exists():\n with open(settings_path) as f:\n settings = json.load(f)\n else:\n settings = {\"customModels\": []}\n \n settings[\"customModels\"].append(model_config)\n \n with open(settings_path, \"w\") as f:\n json.dump(settings, f, indent=2)\n\n# Example: Add OpenRouter model\nadd_custom_model({\n \"model\": \"anthropic/claude-3.5-sonnet\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://openrouter.ai/api/v1\",\n \"apiKey\": \"${OPENROUTER_API_KEY}\",\n \"displayName\": \"Claude 3.5 Sonnet (OpenRouter)\",\n \"maxContextLimit\": 200000\n})\n```\n\n### Shell: Automated Setup Script\n\n```bash\n#!/bin/bash\n# setup-codex-shim.sh\n\nset -e\n\nCODEX_SHIM_DIR=\"$HOME/Documents/codex-shim\"\n\n# Clone and install\nif [ ! -d \"$CODEX_SHIM_DIR\" ]; then\n git clone https://github.com/0xSero/codex-shim \"$CODEX_SHIM_DIR\"\nfi\n\ncd \"$CODEX_SHIM_DIR\"\npython3 -m pip install --user aiohttp\n\n# Symlink commands\nmkdir -p \"$HOME/.local/bin\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-shim\" \"$HOME/.local/bin/\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-app\" \"$HOME/.local/bin/\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-model\" \"$HOME/.local/bin/\"\n\n# Generate catalog and start\ncodex-shim generate\ncodex-shim start\n\necho \"✓ Shim installed and running\"\ncodex-shim status\n```\n\n## macOS Picker Patch\n\nCodex Desktop's Statsig config hides models not on a server-side allowlist. Apply this one-time ASAR patch to bypass:\n\n```bash\nAPP=/Applications/Codex.app\n\n# Backup\nsudo cp -R \"$APP\" \"$APP.unpatched-$(date +%Y%m%d-%H%M%S)\"\n\n# Extract ASAR\ncd /tmp && rm -rf codex-asar-patch && mkdir codex-asar-patch && cd codex-asar-patch\nnpx --yes @electron/asar extract \"$APP/Contents/Resources/app.asar\" extracted\n\n# Patch picker filter (disables useHiddenModels check)\nPATCH_FILE=$(grep -RIl 'useHiddenModels' extracted/webview/assets/model-queries-*.js | head -n1)\nsed -i.bak -E 's/let u=c\\.useHiddenModels&&o!==`amazonBedrock`,d;/let u=!1,d;/' \"$PATCH_FILE\"\n\n# Verify exactly one change\ndiff \"$PATCH_FILE.bak\" \"$PATCH_FILE\" && echo \"ERROR: No changes made\" && exit 1\nrm \"$PATCH_FILE.bak\"\n\n# Repack\nnpx --yes @electron/asar pack extracted app.asar.new\nsudo cp app.asar.new \"$APP/Contents/Resources/app.asar\"\n\n# Recompute ASAR header hash for Electron integrity check\nHEADER_HASH=$(python3 - \"$APP/Contents/Resources/app.asar\" <<'PY'\nimport struct, hashlib, sys\nwith open(sys.argv[1], 'rb') as f:\n data_size, header_size, _, json_size = struct.unpack('<4I', f.read(16))\n header_json = f.read(json_size)\nprint(hashlib.sha256(header_json).hexdigest())\nPY\n)\n\n# Update Info.plist\nsudo /usr/libexec/PlistBuddy -c \\\n \"Set :ElectronAsarIntegrity:Resources/app.asar:hash $HEADER_HASH\" \\\n \"$APP/Contents/Info.plist\"\n\n# Re-sign (ad-hoc)\nsudo codesign --force --deep --sign - \"$APP\"\n\necho \"✓ Patch applied. Launch Codex Desktop.\"\n```\n\n**Rollback:**\n```bash\nsudo rm -rf \"$APP\"\nsudo mv \"$APP.unpatched-YYYYMMDD-HHMMSS\" \"$APP\"\n```\n\n## ChatGPT GPT-5.5 Passthrough\n\nIf `~/.codex/auth.json` exists with `auth_mode: chatgpt`, the shim auto-generates a synthetic slug `openai-gpt-5-5` that proxies to:\n\n```\nhttps://chatgpt.com/backend-api/codex/responses\nAuthorization: Bearer <access_token from auth.json>\n```\n\nThis bypasses Factory and uses your ChatGPT subscription quota.\n\n**Disable:**\n```bash\n# Remove from catalog after generation\njq 'del(.models[] | select(.slug == \"openai-gpt-5-5\"))' \\\n .codex-shim/custom_model_catalog.json > tmp.json && mv tmp.json .codex-shim/custom_model_catalog.json\n```\n\n## Common Patterns\n\n### Multi-Provider Setup\n\n```json\n{\n \"customModels\": [\n {\n \"model\": \"gpt-5.5\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://api.openai.com/v1\",\n \"apiKey\": \"${OPENAI_API_KEY}\",\n \"displayName\": \"GPT-5.5\"\n },\n {\n \"model\": \"claude-opus-4-7-20251109\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.anthropic.com/v1\",\n \"apiKey\": \"${ANTHROPIC_API_KEY}\",\n \"displayName\": \"Claude Opus 4.7\"\n },\n {\n \"model\": \"gemini-2.0-flash-exp\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://generativelanguage.googleapis.com/v1beta/openai\",\n \"apiKey\": \"${GOOGLE_API_KEY}\",\n \"displayName\": \"Gemini 2.0 Flash\"\n }\n ]\n}\n```\n\n### OpenRouter Aggregation\n\n```json\n{\n \"model\": \"meta-llama/llama-3.3-70b-instruct\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://openrouter.ai/api/v1\",\n \"apiKey\": \"${OPENROUTER_API_KEY}\",\n \"displayName\": \"Llama 3.3 70B (OpenRouter)\"\n}\n```\n\n### DeepSeek with Anthropic-Style Thinking\n\n```json\n{\n \"model\": \"deepseek-v4-pro\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.deepseek.com/anthropic\",\n \"apiKey\": \"${DEEPSEEK_API_KEY}\",\n \"displayName\": \"DeepSeek V4 Pro\",\n \"noImageSupport\": true\n}\n```\n\nThe shim translates extended thinking blocks from `thinking` items to `reasoning.encrypted_content`.\n\n## Troubleshooting\n\n### Models Don't Appear in Picker\n\n**Cause:** Statsig allowlist still active.\n\n**Solution:** Apply macOS picker patch (see section above).\n\n### \"Connection refused\" When Launching Codex\n\n**Cause:** Shim daemon not running.\n\n```bash\ncodex-shim status # Check if running\ncodex-shim start # Start if stopped\n```\n\n### 401 Unauthorized Errors\n\n**Cause:** API key not found or invalid.\n\n**Check environment variables:**\n```bash\necho $OPENAI_API_KEY\necho $ANTHROPIC_API_KEY\n```\n\n**Verify settings file:**\n```bash\ncat ~/.factory/settings.json | jq '.customModels[].apiKey'\n```\n\n**Test upstream directly:**\n```bash\ncurl https://api.openai.com/v1/models \\\n -H \"Authorization: Bearer $OPENAI_API_KEY\"\n```\n\n### ChatGPT Passthrough Not Working\n\n**Verify auth.json exists:**\n```bash\ncat ~/.codex/auth.json | jq '.auth_mode'\n# Should output: \"chatgpt\"\n```\n\n**Check access token validity:**\n```bash\nTOKEN=$(jq -r '.access_token' ~/.codex/auth.json)\ncurl https://chatgpt.com/backend-api/me \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### Shim Logs\n\n```bash\n# Tail daemon logs\ntail -f ~/.codex-shim/codex-shim.log\n\n# Check last 50 lines\ntail -n 50 ~/.codex-shim/codex-shim.log\n```\n\n### Port Already in Use\n\n```bash\n# Change default port (8765)\ncodex-shim --port 9876 start\ncodex-shim --port 9876 app\n```\n\n### Extended Thinking Not Appearing\n\n**For Anthropic-shaped providers** (Claude, DeepSeek), thinking blocks appear as `reasoning.encrypted_content` items in Codex UI.\n\n**Verify provider is set to `anthropic`:**\n```bash\njq '.customModels[] | select(.model==\"deepseek-v4-pro\") | .provider' \\\n ~/.factory/settings.json\n```\n\nShould return `\"anthropic\"`, not `\"openai\"`.\n\n## Testing\n\nRun test suite:\n```bash\ncd ~/Documents/codex-shim\npython3 -m pytest tests/ -v\n```\n\nTest specific translation:\n```python\n# tests/test_translation.py\nimport pytest\nfrom codex_shim.translator import translate_to_anthropic\n\n@pytest.mark.asyncio\nasync def test_system_message_extraction():\n request = {\n \"model\": \"claude-opus-4-7\",\n \"messages\": [\n {\"role\": \"system\", \"content\": \"You are helpful\"},\n {\"role\": \"user\", \"content\": \"Hello\"}\n ]\n }\n \n result = await translate_to_anthropic(request)\n assert result[\"system\"] == \"You are helpful\"\n assert len(result[\"messages\"]) == 1\n```\n\n## MCP Tool Forwarding\n\nCodex Desktop forwards three generic MCP tools to **all models** (built-in and shim-routed):\n\n- `list_mcp_resources`\n- `list_mcp_resource_templates`\n- `read_mcp_resource`\n\nThese are available in the function calling schema for every routed model. The model calls `list_mcp_resources` to discover available resources.\n\n**Note:** Codex Desktop does **not** flatten individual MCP server tools. That's a Codex client behavior, not a shim limitation.\n\n---\n\n**Official Repository:** https://github.com/0xSero/codex-shim \n**License:** MIT \n**Requires:** Python 3.11+, aiohttp\n"}, "035c3b0f2b7663d7beca5f7808ecf93fa4b6e12f": {"t": 1785763661.0796058, "n": 14110, "h": "59affcc6a7feebc1", "c": "---\nname: codex-shim-byok-models\ndescription: Run Codex Desktop with Factory BYOK models and ChatGPT GPT-5.5 via local API shim\ntriggers:\n - how do I use custom models in Codex Desktop\n - set up codex-shim with Factory models\n - expose my OpenAI API key to Codex\n - add custom models to Codex picker\n - route Codex through local shim server\n - patch Codex Desktop model allowlist\n - configure BYOK models for Codex\n - use ChatGPT subscription with Codex Desktop\n---\n\n# Codex Shim BYOK Models\n\n> Skill by [ara.so](https://ara.so) — Codex Skills collection.\n\n## Overview\n\n**codex-shim** is a local Python API shim that intercepts Codex Desktop's model requests and routes them to:\n- Any model in your `~/.factory/settings.json` (Factory BYOK)\n- Your ChatGPT subscription GPT-5.5\n- Custom OpenAI/Anthropic/generic chat completion endpoints\n\nIt exposes a local Responses API endpoint that Codex Desktop points to, bypassing Codex's server-side Statsig model allowlist.\n\n**Key capabilities:**\n- Use any OpenAI, Anthropic, DeepSeek, Gemini, OpenRouter, or Z.ai model\n- Keep ChatGPT subscription GPT-5.5 alongside BYOK models\n- No modification to `~/.codex/config.toml` (uses launch-time overrides)\n- Translates between Codex Responses API ↔ upstream APIs (OpenAI chat completions, Anthropic messages)\n\n## Installation\n\n```bash\n# Clone repository\ngit clone https://github.com/0xSero/codex-shim ~/Documents/codex-shim\ncd ~/Documents/codex-shim\n\n# Install Python dependencies (requires 3.11+)\npython3 -m pip install --user aiohttp pytest\n\n# Symlink commands to PATH\nln -s \"$PWD/bin/codex-shim\" ~/.local/bin/codex-shim\nln -s \"$PWD/bin/codex-app\" ~/.local/bin/codex-app\nln -s \"$PWD/bin/codex-model\" ~/.local/bin/codex-model\n```\n\nVerify installation:\n```bash\ncodex-shim --help\n```\n\n## Configuration\n\n### Factory Settings File\n\nThe shim reads `~/.factory/settings.json` by default. Structure:\n\n```json\n{\n \"customModels\": [\n {\n \"model\": \"gpt-5.5\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://api.openai.com/v1\",\n \"apiKey\": \"${OPENAI_API_KEY}\",\n \"displayName\": \"OpenAI GPT-5.5\",\n \"maxContextLimit\": 400000\n },\n {\n \"model\": \"claude-opus-4-7-20251109\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.anthropic.com/v1\",\n \"apiKey\": \"${ANTHROPIC_API_KEY}\",\n \"displayName\": \"Claude Opus 4.7\"\n },\n {\n \"model\": \"deepseek-v4-pro\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.deepseek.com/anthropic\",\n \"apiKey\": \"${DEEPSEEK_API_KEY}\",\n \"displayName\": \"DeepSeek V4 Pro\",\n \"noImageSupport\": true\n }\n ]\n}\n```\n\n**Supported providers:**\n- `openai` → OpenAI `/v1/chat/completions`\n- `generic-chat-completion-api` → OpenAI-compatible endpoints\n- `anthropic` → Anthropic `/v1/messages`\n\n### Custom Config Path\n\n```bash\ncodex-shim --settings /path/to/custom-models.json generate\ncodex-shim --settings /path/to/custom-models.json start\n```\n\n### Environment Variables\n\nStore API keys in environment:\n```bash\nexport OPENAI_API_KEY=\"sk-...\"\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\nexport DEEPSEEK_API_KEY=\"...\"\n```\n\n## Key Commands\n\n### Generate Catalog\n\nReads Factory settings and creates `.codex-shim/custom_model_catalog.json`:\n\n```bash\ncodex-shim generate\n```\n\n### Start/Stop Daemon\n\n```bash\n# Start shim on 127.0.0.1:8765\ncodex-shim start\n\n# Check status\ncodex-shim status\n\n# Stop daemon\ncodex-shim stop\n\n# Restart\ncodex-shim restart\n```\n\n### List Available Models\n\n```bash\n# Show all generated slugs and upstream routes\ncodex-shim list\n\n# Show models currently in Codex Desktop picker\ncodex-model list\n```\n\n### Launch Codex Desktop\n\n```bash\n# Launch with shim wired in (doesn't modify ~/.codex/config.toml)\ncodex-app\n\n# Launch and open specific path\ncodex-app /path/to/project\n\n# Equivalent long form\ncodex-shim app /path/to/project\n```\n\n### Switch Active Model\n\n```bash\n# List available slugs\ncodex-model list\n\n# Set default model for next launch\ncodex-model openai-gpt-5-5\n\n# Relaunch Codex\ncodex-app\n```\n\n### Run Codex CLI Through Shim\n\n```bash\ncodex-shim codex -- chat \"explain this code\"\ncodex-shim codex -- edit main.py \"add error handling\"\n```\n\n## Model Routing Architecture\n\n```\nCodex Desktop → /v1/responses → codex-shim (127.0.0.1:8765)\n ┃\n ┏━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┓\n ┃ ┃ ┃\n slug \"openai-gpt-5-5\" provider provider\n ┃ \"openai\" \"anthropic\"\n ┃ ┃ ┃\n chatgpt.com/backend-api baseUrl/ baseUrl/\n /codex/responses chat/ messages\n (Bearer token) completions (x-api-key)\n```\n\nThe shim:\n1. Receives Codex Responses API request\n2. Looks up slug in catalog\n3. Translates to upstream format (OpenAI chat completions or Anthropic messages)\n4. Streams upstream response\n5. Translates back to Responses API format\n\n## Code Examples\n\n### Python: Implementing Custom Provider Translation\n\n```python\n# codex_shim/translator.py example pattern\n\nasync def translate_to_openai(responses_request):\n \"\"\"Convert Codex Responses API → OpenAI chat completions.\"\"\"\n return {\n \"model\": responses_request[\"model\"],\n \"messages\": responses_request[\"messages\"],\n \"stream\": True,\n \"temperature\": responses_request.get(\"temperature\", 1.0),\n \"max_tokens\": responses_request.get(\"max_tokens\"),\n }\n\nasync def translate_to_anthropic(responses_request):\n \"\"\"Convert Codex Responses API → Anthropic messages.\"\"\"\n messages = []\n system = None\n \n for msg in responses_request[\"messages\"]:\n if msg[\"role\"] == \"system\":\n system = msg[\"content\"]\n else:\n messages.append({\n \"role\": msg[\"role\"],\n \"content\": msg[\"content\"]\n })\n \n body = {\n \"model\": responses_request[\"model\"],\n \"messages\": messages,\n \"stream\": True,\n \"max_tokens\": responses_request.get(\"max_tokens\", 4096),\n }\n \n if system:\n body[\"system\"] = system\n \n return body\n```\n\n### Python: Adding Custom Model Programmatically\n\n```python\nimport json\nfrom pathlib import Path\n\ndef add_custom_model(model_config):\n \"\"\"Add model to Factory settings.\"\"\"\n settings_path = Path.home() / \".factory\" / \"settings.json\"\n \n if settings_path.exists():\n with open(settings_path) as f:\n settings = json.load(f)\n else:\n settings = {\"customModels\": []}\n \n settings[\"customModels\"].append(model_config)\n \n with open(settings_path, \"w\") as f:\n json.dump(settings, f, indent=2)\n\n# Example: Add OpenRouter model\nadd_custom_model({\n \"model\": \"anthropic/claude-3.5-sonnet\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://openrouter.ai/api/v1\",\n \"apiKey\": \"${OPENROUTER_API_KEY}\",\n \"displayName\": \"Claude 3.5 Sonnet (OpenRouter)\",\n \"maxContextLimit\": 200000\n})\n```\n\n### Shell: Automated Setup Script\n\n```bash\n#!/bin/bash\n# setup-codex-shim.sh\n\nset -e\n\nCODEX_SHIM_DIR=\"$HOME/Documents/codex-shim\"\n\n# Clone and install\nif [ ! -d \"$CODEX_SHIM_DIR\" ]; then\n git clone https://github.com/0xSero/codex-shim \"$CODEX_SHIM_DIR\"\nfi\n\ncd \"$CODEX_SHIM_DIR\"\npython3 -m pip install --user aiohttp\n\n# Symlink commands\nmkdir -p \"$HOME/.local/bin\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-shim\" \"$HOME/.local/bin/\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-app\" \"$HOME/.local/bin/\"\nln -sf \"$CODEX_SHIM_DIR/bin/codex-model\" \"$HOME/.local/bin/\"\n\n# Generate catalog and start\ncodex-shim generate\ncodex-shim start\n\necho \"✓ Shim installed and running\"\ncodex-shim status\n```\n\n## macOS Picker Patch\n\nCodex Desktop's Statsig config hides models not on a server-side allowlist. Apply this one-time ASAR patch to bypass:\n\n```bash\nAPP=/Applications/Codex.app\n\n# Backup\nsudo cp -R \"$APP\" \"$APP.unpatched-$(date +%Y%m%d-%H%M%S)\"\n\n# Extract ASAR\ncd /tmp && rm -rf codex-asar-patch && mkdir codex-asar-patch && cd codex-asar-patch\nnpx --yes @electron/asar extract \"$APP/Contents/Resources/app.asar\" extracted\n\n# Patch picker filter (disables useHiddenModels check)\nPATCH_FILE=$(grep -RIl 'useHiddenModels' extracted/webview/assets/model-queries-*.js | head -n1)\nsed -i.bak -E 's/let u=c\\.useHiddenModels&&o!==`amazonBedrock`,d;/let u=!1,d;/' \"$PATCH_FILE\"\n\n# Verify exactly one change\ndiff \"$PATCH_FILE.bak\" \"$PATCH_FILE\" && echo \"ERROR: No changes made\" && exit 1\nrm \"$PATCH_FILE.bak\"\n\n# Repack\nnpx --yes @electron/asar pack extracted app.asar.new\nsudo cp app.asar.new \"$APP/Contents/Resources/app.asar\"\n\n# Recompute ASAR header hash for Electron integrity check\nHEADER_HASH=$(python3 - \"$APP/Contents/Resources/app.asar\" <<'PY'\nimport struct, hashlib, sys\nwith open(sys.argv[1], 'rb') as f:\n data_size, header_size, _, json_size = struct.unpack('<4I', f.read(16))\n header_json = f.read(json_size)\nprint(hashlib.sha256(header_json).hexdigest())\nPY\n)\n\n# Update Info.plist\nsudo /usr/libexec/PlistBuddy -c \\\n \"Set :ElectronAsarIntegrity:Resources/app.asar:hash $HEADER_HASH\" \\\n \"$APP/Contents/Info.plist\"\n\n# Re-sign (ad-hoc)\nsudo codesign --force --deep --sign - \"$APP\"\n\necho \"✓ Patch applied. Launch Codex Desktop.\"\n```\n\n**Rollback:**\n```bash\nsudo rm -rf \"$APP\"\nsudo mv \"$APP.unpatched-YYYYMMDD-HHMMSS\" \"$APP\"\n```\n\n## ChatGPT GPT-5.5 Passthrough\n\nIf `~/.codex/auth.json` exists with `auth_mode: chatgpt`, the shim auto-generates a synthetic slug `openai-gpt-5-5` that proxies to:\n\n```\nhttps://chatgpt.com/backend-api/codex/responses\nAuthorization: Bearer <access_token from auth.json>\n```\n\nThis bypasses Factory and uses your ChatGPT subscription quota.\n\n**Disable:**\n```bash\n# Remove from catalog after generation\njq 'del(.models[] | select(.slug == \"openai-gpt-5-5\"))' \\\n .codex-shim/custom_model_catalog.json > tmp.json && mv tmp.json .codex-shim/custom_model_catalog.json\n```\n\n## Common Patterns\n\n### Multi-Provider Setup\n\n```json\n{\n \"customModels\": [\n {\n \"model\": \"gpt-5.5\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://api.openai.com/v1\",\n \"apiKey\": \"${OPENAI_API_KEY}\",\n \"displayName\": \"GPT-5.5\"\n },\n {\n \"model\": \"claude-opus-4-7-20251109\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.anthropic.com/v1\",\n \"apiKey\": \"${ANTHROPIC_API_KEY}\",\n \"displayName\": \"Claude Opus 4.7\"\n },\n {\n \"model\": \"gemini-2.0-flash-exp\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://generativelanguage.googleapis.com/v1beta/openai\",\n \"apiKey\": \"${GOOGLE_API_KEY}\",\n \"displayName\": \"Gemini 2.0 Flash\"\n }\n ]\n}\n```\n\n### OpenRouter Aggregation\n\n```json\n{\n \"model\": \"meta-llama/llama-3.3-70b-instruct\",\n \"provider\": \"openai\",\n \"baseUrl\": \"https://openrouter.ai/api/v1\",\n \"apiKey\": \"${OPENROUTER_API_KEY}\",\n \"displayName\": \"Llama 3.3 70B (OpenRouter)\"\n}\n```\n\n### DeepSeek with Anthropic-Style Thinking\n\n```json\n{\n \"model\": \"deepseek-v4-pro\",\n \"provider\": \"anthropic\",\n \"baseUrl\": \"https://api.deepseek.com/anthropic\",\n \"apiKey\": \"${DEEPSEEK_API_KEY}\",\n \"displayName\": \"DeepSeek V4 Pro\",\n \"noImageSupport\": true\n}\n```\n\nThe shim translates extended thinking blocks from `thinking` items to `reasoning.encrypted_content`.\n\n## Troubleshooting\n\n### Models Don't Appear in Picker\n\n**Cause:** Statsig allowlist still active.\n\n**Solution:** Apply macOS picker patch (see section above).\n\n### \"Connection refused\" When Launching Codex\n\n**Cause:** Shim daemon not running.\n\n```bash\ncodex-shim status # Check if running\ncodex-shim start # Start if stopped\n```\n\n### 401 Unauthorized Errors\n\n**Cause:** API key not found or invalid.\n\n**Check environment variables:**\n```bash\necho $OPENAI_API_KEY\necho $ANTHROPIC_API_KEY\n```\n\n**Verify settings file:**\n```bash\ncat ~/.factory/settings.json | jq '.customModels[].apiKey'\n```\n\n**Test upstream directly:**\n```bash\ncurl https://api.openai.com/v1/models \\\n -H \"Authorization: Bearer $OPENAI_API_KEY\"\n```\n\n### ChatGPT Passthrough Not Working\n\n**Verify auth.json exists:**\n```bash\ncat ~/.codex/auth.json | jq '.auth_mode'\n# Should output: \"chatgpt\"\n```\n\n**Check access token validity:**\n```bash\nTOKEN=$(jq -r '.access_token' ~/.codex/auth.json)\ncurl https://chatgpt.com/backend-api/me \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### Shim Logs\n\n```bash\n# Tail daemon logs\ntail -f ~/.codex-shim/codex-shim.log\n\n# Check last 50 lines\ntail -n 50 ~/.codex-shim/codex-shim.log\n```\n\n### Port Already in Use\n\n```bash\n# Change default port (8765)\ncodex-shim --port 9876 start\ncodex-shim --port 9876 app\n```\n\n### Extended Thinking Not Appearing\n\n**For Anthropic-shaped providers** (Claude, DeepSeek), thinking blocks appear as `reasoning.encrypted_content` items in Codex UI.\n\n**Verify provider is set to `anthropic`:**\n```bash\njq '.customModels[] | select(.model==\"deepseek-v4-pro\") | .provider' \\\n ~/.factory/settings.json\n```\n\nShould return `\"anthropic\"`, not `\"openai\"`.\n\n## Testing\n\nRun test suite:\n```bash\ncd ~/Documents/codex-shim\npython3 -m pytest tests/ -v\n```\n\nTest specific translation:\n```python\n# tests/test_translation.py\nimport pytest\nfrom codex_shim.translator import translate_to_anthropic\n\n@pytest.mark.asyncio\nasync def test_system_message_extraction():\n request = {\n \"model\": \"claude-opus-4-7\",\n \"messages\": [\n {\"role\": \"system\", \"content\": \"You are helpful\"},\n {\"role\": \"user\", \"content\": \"Hello\"}\n ]\n }\n \n result = await translate_to_anthropic(request)\n assert result[\"system\"] == \"You are helpful\"\n assert len(result[\"messages\"]) == 1\n```\n\n## MCP Tool Forwarding\n\nCodex Desktop forwards three generic MCP tools to **all models** (built-in and shim-routed):\n\n- `list_mcp_resources`\n- `list_mcp_resource_templates`\n- `read_mcp_resource`\n\nThese are available in the function calling schema for every routed model. The model calls `list_mcp_resources` to discover available resources.\n\n**Note:** Codex Desktop does **not** flatten individual MCP server tools. That's a Codex client behavior, not a shim limitation.\n\n---\n\n**Official Repository:** https://github.com/0xSero/codex-shim \n**License:** MIT \n**Requires:** Python 3.11+, aiohttp\n"}}}}