Skip to content

Instantly share code, notes, and snippets.

@WolframRavenwolf
Last active June 19, 2026 21:32
Show Gist options
  • Select an option

  • Save WolframRavenwolf/e6c3755cc9919e2d258335707090eebc to your computer and use it in GitHub Desktop.

Select an option

Save WolframRavenwolf/e6c3755cc9919e2d258335707090eebc to your computer and use it in GitHub Desktop.
Add GLM 5.2 To Codex Via OpenRouter

This guide adds z-ai/glm-5.2 to Codex through OpenRouter's Responses API. The example route tries Fireworks first, then Z.ai, and does not fall back to any other provider.

Tested with Codex Desktop/CLI 0.142.0-alpha.1 on macOS.

What This Does

  • Uses OpenRouter's /responses endpoint, because current Codex provider integration requires Responses API.
  • Stores the OpenRouter API key in macOS Keychain, not in config.toml.
  • Creates an OpenRouter preset for z-ai/glm-5.2.
  • Adds a Codex model catalog entry for GLM 5.2.
  • Points Codex at OpenRouter as the active provider.

Important caveat: Codex uses one active model_provider per run. With this config active, the Codex run uses OpenRouter as the provider. The model selector does not automatically route GPT models through OpenAI and GLM through OpenRouter per model.

1. Set Variables

Use the same values consistently across all steps:

export CODEX_BIN="/Applications/Codex.app/Contents/Resources/codex"
export OPENROUTER_KEYCHAIN_SERVICE="codex-openrouter-glm52"
export OPENROUTER_PRESET="codex-glm52-openrouter"
export OPENROUTER_MODEL="z-ai/glm-5.2"
export CODEX_MODEL="${OPENROUTER_MODEL}@preset/${OPENROUTER_PRESET}"

If your Codex binary is elsewhere, adjust CODEX_BIN.

2. Create An OpenRouter API Key

In OpenRouter:

  1. Open OpenRouter API Keys.
  2. Create a dedicated API key for Codex.
  3. Optional but recommended: set a daily spend limit.
  4. Copy the key once.

Store it in macOS Keychain:

read -rs OPENROUTER_API_KEY
security add-generic-password \
  -a "$USER" \
  -s "$OPENROUTER_KEYCHAIN_SERVICE" \
  -w "$OPENROUTER_API_KEY" \
  -U
unset OPENROUTER_API_KEY

Do not put the raw key into Markdown, shell scripts, config.toml, or shared dotfiles.

3. Create A Keychain Helper

Codex custom providers can fetch bearer tokens through a command. Create a helper that prints the OpenRouter key from Keychain:

mkdir -p ~/.codex/bin

cat > ~/.codex/bin/openrouter-glm52-token <<'EOF'
#!/bin/zsh
exec /usr/bin/security find-generic-password -a "${USER}" -s "codex-openrouter-glm52" -w
EOF

chmod 700 ~/.codex/bin/openrouter-glm52-token

If you changed OPENROUTER_KEYCHAIN_SERVICE, update the service name inside the helper script too.

Validate without printing the secret:

test -n "$(~/.codex/bin/openrouter-glm52-token)" && echo "OpenRouter key helper OK"

4. Create The OpenRouter Responses Preset

Create a preset that routes GLM 5.2 to Fireworks first and Z.ai second:

OPENROUTER_API_KEY="$(~/.codex/bin/openrouter-glm52-token)"

curl -fsS \
  -X POST "https://openrouter.ai/api/v1/presets/${OPENROUTER_PRESET}/responses" \
  -H "Authorization: Bearer ${OPENROUTER_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{
    "model": "z-ai/glm-5.2",
    "provider": {
      "order": ["fireworks", "z-ai"],
      "allow_fallbacks": false
    }
  }'

unset OPENROUTER_API_KEY

Do not set require_parameters: true.

Codex sends tool schemas (tools, tool_choice, etc.) with agent requests. With require_parameters: true, OpenRouter may reject the request before inference with:

404 Not Found: No endpoints found that can handle the requested parameters

5. Create A GLM Model Catalog

Create a GLM-only catalog:

mkdir -p ~/.codex/model-catalogs

cat > ~/.codex/model-catalogs/glm52-openrouter.json <<EOF
{
  "models": [
    {
      "slug": "${CODEX_MODEL}",
      "display_name": "Z.ai GLM 5.2 (OpenRouter Fireworks + Z.ai)",
      "description": "GLM 5.2 via OpenRouter preset ${OPENROUTER_PRESET}. The preset tries Fireworks first, then Z.ai, with fallbacks beyond that disabled.",
      "base_instructions": "",
      "model_messages": null,
      "default_reasoning_level": "xhigh",
      "supported_reasoning_levels": [
        { "effort": "minimal", "description": "Minimal reasoning" },
        { "effort": "low", "description": "Fast responses with lighter reasoning" },
        { "effort": "medium", "description": "Balances speed and reasoning depth" },
        { "effort": "high", "description": "Greater reasoning depth for complex problems" },
        { "effort": "xhigh", "description": "Extra high reasoning depth for complex problems" }
      ],
      "shell_type": "shell_command",
      "visibility": "list",
      "supported_in_api": true,
      "priority": 50,
      "additional_speed_tiers": [],
      "service_tiers": [],
      "availability_nux": null,
      "upgrade": null,
      "context_window": 1048576,
      "max_context_window": 1048576,
      "effective_context_window_percent": 95,
      "truncation_policy": { "mode": "tokens", "limit": 10000 },
      "supports_parallel_tool_calls": true,
      "supports_reasoning_summaries": false,
      "default_reasoning_summary": "none",
      "support_verbosity": false,
      "default_verbosity": "medium",
      "apply_patch_tool_type": "freeform",
      "experimental_supported_tools": [],
      "input_modalities": ["text"],
      "supports_search_tool": false,
      "web_search_tool_type": "text",
      "supports_image_detail_original": false,
      "use_responses_lite": false
    }
  ]
}
EOF

support_verbosity must be false. If global Codex config has model_verbosity set, Codex should then ignore it for GLM instead of sending OpenAI-specific verbosity fields to OpenRouter.

6. Merge With The Existing Codex Catalog

model_catalog_json replaces the catalog; it does not merge automatically. To keep the existing Codex models in the selector, merge the GLM entry into the current catalog:

"$CODEX_BIN" debug models > /tmp/codex-models.json

node <<'NODE'
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');

const home = os.homedir();
const basePath = '/tmp/codex-models.json';
const extraPath = path.join(home, '.codex/model-catalogs/glm52-openrouter.json');
const outPath = path.join(home, '.codex/model-catalogs/codex-plus-glm52-openrouter.json');

const base = JSON.parse(fs.readFileSync(basePath, 'utf8'));
const extra = JSON.parse(fs.readFileSync(extraPath, 'utf8')).models[0];

const models = Array.isArray(base) ? base : base.models;
if (!Array.isArray(models)) {
  throw new Error('Unexpected Codex model catalog shape');
}

const mergedModels = models
  .filter((model) => model.slug !== extra.slug)
  .concat(extra);

const merged = Array.isArray(base)
  ? mergedModels
  : { ...base, models: mergedModels };

fs.writeFileSync(outPath, JSON.stringify(merged, null, 2) + '\n');
console.log(outPath);
NODE

7. Back Up And Edit config.toml

Back up first:

cp -p ~/.codex/config.toml ~/.codex/config.toml.bak-glm52-openrouter-$(date +%Y%m%d-%H%M%S)

Then add or update these top-level keys in ~/.codex/config.toml:

# Replace /Users/YOUR_USERNAME with your actual macOS home path.
model = "z-ai/glm-5.2@preset/codex-glm52-openrouter"
model_provider = "openrouter"
model_catalog_json = "/Users/YOUR_USERNAME/.codex/model-catalogs/codex-plus-glm52-openrouter.json"
model_reasoning_effort = "xhigh"

If you already have model_verbosity globally set, you can leave it. The GLM catalog entry above marks verbosity as unsupported, so Codex should ignore it for this model.

Add or update the provider block:

[model_providers.openrouter]
name = "OpenRouter"
base_url = "https://openrouter.ai/api/v1"
wire_api = "responses"
http_headers = { "HTTP-Referer" = "https://codex.local", "X-Title" = "Codex GLM 5.2 via OpenRouter" }

[model_providers.openrouter.auth]
command = "/Users/YOUR_USERNAME/.codex/bin/openrouter-glm52-token"
timeout_ms = 5000
refresh_interval_ms = 0

Use wire_api = "responses". Current Codex no longer supports using Chat Completions as the provider wire API for this path.

8. Validate

Check that Codex can load the merged catalog:

"$CODEX_BIN" debug models | rg "GLM 5.2|OpenRouter"

Optional smoke test:

"$CODEX_BIN" exec \
  --ephemeral \
  --skip-git-repo-check \
  -C /private/tmp \
  "Reply OK only."

Expected output:

OK

9. Restart Codex Desktop

Restart Codex Desktop after changing ~/.codex/config.toml. GLM 5.2 should now be the active model and should appear in the model selector.

Rollback

If Codex Desktop cannot start, restore the backup manually:

mv ~/.codex/config.toml ~/.codex/config.toml.broken-glm52-openrouter
cp -p ~/.codex/config.toml.bak-glm52-openrouter-YYYYMMDD-HHMMSS ~/.codex/config.toml

Then restart Codex Desktop.

Troubleshooting

404 No endpoints found that can handle the requested parameters

Usually means the OpenRouter preset has require_parameters: true, or the request is being routed to providers that OpenRouter does not consider compatible with Codex's tool-heavy Responses request.

Fix: remove require_parameters from the preset.

429 Too Many Requests

Usually means the selected upstream provider is rate-limiting. With the example route, OpenRouter may try Fireworks and then Z.ai, but it will not use providers outside that ordered list.

Options:

  • wait and retry
  • add more providers to the order list
  • temporarily allow broader fallbacks
  • use BYOK/provider integrations if available

model_verbosity is set but ignored

Expected when the catalog entry has:

"support_verbosity": false

That is intentional for this setup.

References

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