← Back to Articles
CodexAImacOSDeveloper Experience

Codex Desktop + DroidProxy Model Selector: A Shareable Guide

One local shim, a combined catalogue, and a careful patcher for when Desktop filters out models the backend already knows about.

Jul 2026.11 min read
Codex Desktop + DroidProxy Model Selector: A Shareable Guide

Experimental: I do not advise anyone else to do this

This article documents something I tried as an experiment. It is an unofficial, version-dependent workaround that modifies installed application files, replaces the official signature, and could break Codex Desktop or stop working at any time.

Please treat this as a record of my process, not as a recommendation or endorsement. Check whether a newer Desktop release has fixed the issue before considering any modification.

Back up before patching. Never distribute a patched app, app.asar, or backup. Share instructions and scripts only. Keep API keys, auth files, proxy config, logs, and provider credentials private.

This guide shows how to keep the standard OpenAI models in Codex Desktop while adding models routed through DroidProxy. It also documents a macOS workaround for a Desktop UI filter that can hide custom models even when the backend returns them correctly.

Related upstream issue: openai/codex#19694.

Start here: one prompt is all you need

For the quickest route, paste the prompt below into a new Codex task. This is all you need to get started. Codex can inspect what is already installed, identify the few values it cannot discover, and work through the setup safely with you.

Help me configure Codex Desktop on this Mac so I can keep the standard OpenAI models and also select models routed through DroidProxy.

Work through the setup end to end. Inspect my existing Codex, DroidProxy, shim, and model-catalogue configuration before changing anything. Reuse what is already working and ask me only for values you cannot discover locally, such as the DroidProxy model mappings or a non-default port. Never print or expose credentials, tokens, cookies, auth files, private prompts, or sensitive logs.

The target setup is:
- Codex Desktop talks to one local OpenAI-compatible Responses API shim, bound to 127.0.0.1 (prefer http://127.0.0.1:8765/v1 unless my setup already uses another port).
- The shim routes standard OpenAI models normally and sends clearly named custom model IDs to DroidProxy.
- Codex uses a combined local model catalogue that retains the standard OpenAI entries and adds visible DroidProxy entries with unique IDs.
- ~/.codex/config.toml uses a custom provider with wire_api = "responses" and an absolute model_catalog_json path.

First verify the backend with codex debug models. If the DroidProxy entries are missing there, fix the catalogue, shim, or routing layer before touching Codex Desktop. If the backend lists the custom models but the Desktop selector still hides them, check whether the current release or openai/codex#19694 has fixed the issue. Only if the workaround is still required, use a version-aware macOS patch that:
- checks /Applications/ChatGPT.app/Contents/Resources/app.asar;
- requires exactly one use_hidden_models marker and no use_hidden_modelZ marker;
- creates a version-specific backup without overwriting an existing backup;
- changes only the same-length marker use_hidden_models to use_hidden_modelZ;
- restores the backup automatically if verification fails;
- ad-hoc signs the app and verifies the signature;
- stops without forcing anything if the marker counts or expected byte differ.

Have me save my work and quit Codex Desktop before patching. Keep every proxy service on localhost unless I explicitly request and secure remote access. Afterward, verify the listening services, backend model list, patch marker, app signature, selector entries, and one harmless request through a DroidProxy model.

Show me each proposed change before making it, explain anything you cannot verify, and finish with the exact verification and rollback commands. Never reuse an app.asar backup from a different Codex Desktop version and never package or distribute the patched app, app.asar, or its backup.

Prefer to understand or perform each step yourself? The complete guide follows below, including the configuration, patcher script, verification, update procedure, rollback, and troubleshooting.

Important warnings

Back up the application resource before modifying it.

The patch changes the installed application and replaces its official signature with a local ad-hoc signature.

A Codex Desktop update may overwrite the workaround.

Never restore an app.asar backup from a different Codex Desktop version.

Do not distribute a patched application, app.asar, or backup. Share the instructions and script only.

Keep API keys, authentication files, proxy configuration, logs, and model-provider credentials private.

Architecture

The useful shape is a single OpenAI-compatible Responses endpoint that merges two sources:

Codex Desktop
  -> local Codex shim on 127.0.0.1
      -> standard OpenAI models
      -> DroidProxy models

The shim presents both sources through one Responses API. A combined local model catalogue tells Codex which entries should appear in the selector.

Prerequisites

Codex Desktop on macOSInstalled as /Applications/ChatGPT.app.
DroidProxyInstalled and configured for the custom model routes you want.
Local Responses shimA localhost service that exposes the OpenAI-compatible Responses API for both official and proxy models.
Combined catalogueA Codex model catalogue containing native OpenAI entries plus custom DroidProxy entries.
CLI toolsCommand-line access to grep, dd, codesign, shasum, and PlistBuddy.

Keep DroidProxy and the shim bound to localhost unless remote network access is deliberately required and protected.

Codex configuration

Use a custom provider for the merged shim and point Codex at the combined catalogue:

model_provider = "codex_shim"
model_catalog_json = "/Users/YOUR_USERNAME/.codex/combined-models.json"

[model_providers.codex_shim]
name = "OpenAI + DroidProxy"
base_url = "http://127.0.0.1:8765/v1"
wire_api = "responses"

Replace YOUR_USERNAME with the local macOS account name. Codex configuration paths should be absolute; do not assume that $HOME expands inside TOML strings.

The top-level model entry is only the current selection. It can point to either a native model or a DroidProxy model without changing the routing setup.

Catalogue conventions

Retain the normal OpenAI entries in the combined catalogue. Give custom routes unique model IDs, for example:

droidproxy-grok-example
droidproxy-claude-example
droidproxy-gpt-example

Set models intended for the picker to visible/listed according to the Codex catalogue schema. Keep internal helper models hidden.

Before changing Codex Desktop, confirm that the backend already returns the custom entries:

codex debug models | jq -r '.models[] | [.slug, .visibility] | @tsv'

If the DroidProxy entries are absent here, fix the catalogue or shim first. The desktop patch cannot repair a missing backend model list.

Why custom models can disappear

Codex Desktop can receive the correct model/list response and still filter custom IDs through a remote available_models allowlist. In affected builds, the selector may show only official models even though codex debug models includes the custom entries.

The workaround changes one same-length string inside app.asar:

use_hidden_models
use_hidden_modelZ

This causes the affected allowlist path to fail closed and lets the selector use the visible models returned by the backend.

Portable macOS patcher

Save the following as patch-codex-model-picker.sh in a private local scripts directory:

#!/bin/zsh
set -euo pipefail

app_path="/Applications/ChatGPT.app"
info_path="$app_path/Contents/Info.plist"
asar_path="$app_path/Contents/Resources/app.asar"
backup_dir="$HOME/.codex/backups"

if [[ ! -f "$info_path" || ! -f "$asar_path" ]]; then
  print -u2 "ChatGPT/Codex Desktop application bundle was not found."
  exit 1
fi

app_version=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$info_path")
backup_path="$backup_dir/ChatGPT-app.asar-$app_version-original"

count_marker() {
  { grep -abo "$1" "$asar_path" || true; } | wc -l | tr -d ' '
}

original_count=$(count_marker 'use_hidden_models')
patched_count=$(count_marker 'use_hidden_modelZ')

if [[ "$original_count" == "0" && "$patched_count" == "1" ]]; then
  print "Already patched for ChatGPT/Codex Desktop $app_version"
  exit 0
fi

if [[ "$original_count" != "1" || "$patched_count" != "0" ]]; then
  print -u2 "Unexpected marker counts. The application layout may have changed."
  print -u2 "Original marker: $original_count; patched marker: $patched_count"
  exit 1
fi

offset=$(grep -abo 'use_hidden_models' "$asar_path" | cut -d: -f1)
target_offset=$((offset + 16))
current_byte=$(dd if="$asar_path" bs=1 skip="$target_offset" count=1 2>/dev/null)

if [[ "$current_byte" != "s" ]]; then
  print -u2 "Expected the final marker byte to be s; found $current_byte"
  exit 1
fi

mkdir -p "$backup_dir"

if [[ -e "$backup_path" ]]; then
  print -u2 "Refusing to overwrite existing backup: $backup_path"
  exit 1
fi

cp -p "$asar_path" "$backup_path"
printf 'Z' | dd of="$asar_path" bs=1 seek="$target_offset" count=1 conv=notrunc 2>/dev/null

if [[ "$(count_marker 'use_hidden_modelZ')" != "1" || "$(count_marker 'use_hidden_models')" != "0" ]]; then
  cp -p "$backup_path" "$asar_path"
  print -u2 "Patch verification failed. The original app.asar was restored."
  exit 1
fi

codesign --force --deep --sign - "$app_path"
codesign --verify --deep --strict "$app_path"

print "Patched Codex Desktop version: $app_version"
print "Backup: $backup_path"
print "Patched SHA-256: $(shasum -a 256 "$asar_path" | cut -d' ' -f1)"

Make it executable:

chmod 700 /ABSOLUTE/PATH/TO/patch-codex-model-picker.sh

Recommended procedure

1. Finish or save active work.

2. Quit Codex Desktop completely.

3. Confirm that DroidProxy and the shim are running.

4. Run the patcher using its absolute path.

5. Reopen Codex Desktop.

6. Open the model selector and confirm that both official and DroidProxy · entries appear.

7. Select one custom model and run a harmless test prompt.

Quitting first is the safest approach because the running interface has already loaded its JavaScript into memory.

Optional non-interrupting staging

The patch can be staged while Codex Desktop remains open so active work is not interrupted. The current window will continue using the old code and the selector will not change immediately. Finish the active work, then quit and reopen Codex normally.

Avoid this method if modifying a running application bundle is outside your comfort level. Quitting before patching remains the recommended procedure.

Verification

Check local services. Adjust the ports if your configuration differs:

lsof -nP -iTCP:8765 -sTCP:LISTEN
lsof -nP -iTCP:8317 -sTCP:LISTEN

Check the backend catalogue:

codex debug models | jq -r '.models[] | [.slug, .visibility] | @tsv'

Check the patch marker:

grep -abo 'use_hidden_modelZ' /Applications/ChatGPT.app/Contents/Resources/app.asar
grep -abo 'use_hidden_models' /Applications/ChatGPT.app/Contents/Resources/app.asar

Expected result: the patched marker appears exactly once and the original marker does not appear.

Verify the application signature:

codesign --verify --deep --strict /Applications/ChatGPT.app

After a Codex Desktop update

If custom models disappear after an update:

1. Run codex debug models.

2. If custom models still appear there, check the two marker strings in app.asar.

3. Run the same version-aware patcher. It will create a backup named for the newly installed version.

4. Restart Codex Desktop when convenient.

5. Verify the selector again.

Do not manually reuse the backup from an older application version.

Rollback

Quit Codex Desktop. Determine the installed version:

/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' /Applications/ChatGPT.app/Contents/Info.plist

Restore only the backup whose filename matches that exact version:

cp -p "$HOME/.codex/backups/ChatGPT-app.asar-VERSION-original" \
  /Applications/ChatGPT.app/Contents/Resources/app.asar

codesign --force --deep --sign - /Applications/ChatGPT.app
codesign --verify --deep --strict /Applications/ChatGPT.app

Replace VERSION before running the command.

Troubleshooting

Custom models missing from codex debug modelsThe problem is in the combined catalogue, shim configuration, or provider routing. Fix that layer before touching the desktop application.
Patcher reports unexpected marker countsStop. The application bundle changed and this workaround may no longer match the installed build. Do not force an offset or patch an unverified byte.
Models appear but requests failThe selector is working, but the selected model route is not. Check DroidProxy, shim logs, model mappings, and credentials without publishing any secrets.
Codex will not launch after patchingRestore the exact version-matched backup, re-sign the app, and verify its signature. Reinstalling the official application is the clean fallback if the matching backup is unavailable.

Safe sharing checklist

Before publishing this guide or asking someone for troubleshooting help:

Replace usernames and absolute personal paths with placeholders

Remove API keys, tokens, cookies, and authorization headers

Remove the contents of authentication and provider configuration files

Remove private logs and prompts

Do not upload app.asar, application backups, or the patched app

Keep proxy services on localhost unless they are deliberately secured

State that the workaround is unofficial and version-dependent

Encourage readers to check for an upstream fix first