All notes

Working between standard and custom Codex builds

My current setup uses an Ollama-enabled Codex fork as a specialized worker runtime alongside the OpenAI-signed build.

  • This is the fifth note in a series about mixed-provider Codex delegation.
  • The standard OpenAI-signed build retains app integrations such as the built-in browser, image generation, and the Chrome extension.
  • The custom build adds plaintext mixed-provider transport, worker controls, and Ollama-backed delegation, but many app-integrated features do not work in my current setup.
  • A separate launcher selects the custom binary without replacing the application bundle, and the main binary travels with its matching code-mode host.
  • I hand work between builds through explicit repository state because conversation and tool state may differ between runtimes.
On this page

In Routing and qualifying Ollama-backed Codex workers, I described how the private build discovers, routes, and qualifies Ollama-backed workers. I still use the standard Codex build for application integrations that the private binary cannot access.

I use two builds because they solve different problems. The custom build gives me the provider and worker behavior I was experimenting with. The standard, OpenAI-signed build retains Desktop integrations that the custom binary cannot use in my current setup.

Two builds because neither does everything

The custom build is the right runtime when I need plaintext handoffs to third-party providers, role-aware worker limits, or bounded implementation work on Halo. Those are the reasons the fork exists.

The standard build is the right runtime when a task needs the complete signed application tool path. The built-in browser, image generation, and the Chrome extension do not work through my custom build. Those are the visible examples, not an exhaustive compatibility list.

That makes the custom build a specialized worker runtime, not a drop-in replacement:

TEXT
standard Codex
  signed application integrations
  built-in browser
  image generation
  Chrome extension
 
custom Codex
  plaintext mixed-provider transport
  Ollama-backed workers
  private lifecycle and routing controls

I accept the split because the custom binary does not have feature parity with the signed application tool path.

The browser stops at a signing boundary

The built-in browser failure was not caused by a missing feature flag.

Desktop runs the browser host separately from the Codex sidecar. The custom sidecar could advertise browser support and still fail when it connected to the native pipe. Desktop rejected that connection because the private binary was ad-hoc signed and had no recognized signing identity. The bundled Codex binary has OpenAI's signing identity and passes that check.

The practical result is simple: the built-in browser works with the standard build and does not work with my custom build. Fixing that would require an accepted signing identity or a deliberate change to Desktop's trust policy. It is not something I can repair by turning on another Codex setting.

When I only need an unauthenticated local browser check, I can use a managed Playwright browser as a fallback. That does not restore the built-in browser or its existing application state. For work that depends on the actual Desktop browser integration, I return to the standard build.

The missing surface is wider than the browser

Image generation is also unavailable in my current custom setup.

I do not assume it fails for the same reason as the browser. The browser failure has a specific native-pipe and signing diagnosis. For image generation, the important fact in my workflow is narrower: the tool is available in the standard build and not available when I run the private build.

If a task needs a generated or edited image, I do that work in standard Codex, save the resulting asset in the repository, and then return to the custom build if the remaining work benefits from Halo-backed workers. The file becomes the handoff instead of an unavailable tool call.

The Chrome extension fails in the custom setup too. I do not assume every missing integration shares the browser's signing failure. The safer rule is to treat app-integrated features as unsupported by the private build until they pass a real end-to-end check. Tool registration, a visible feature flag, or a working app-server connection is not enough.

How the launcher selects the runtime

I do not replace the Codex binary inside the signed application bundle. Changing that bundle would invalidate its sealed identity and risk breaking macOS privacy and entitlement behavior.

The Ollama launcher starts the same application with CODEX_CLI_PATH pointing to the private executable. Without that override, the application falls back to its bundled OpenAI-signed Codex binary.

The private package carries two matching executables:

TEXT
Codex Ollama.app
└── Contents/Resources/bin/
    ├── codex
    └── codex-code-mode-host

Those files have to travel together. Updating only codex can leave Desktop or code mode speaking to an incompatible companion process. The installer and portable launcher therefore validate and package the pair as one unit.

If the application is already running, the launcher asks to quit and relaunch before selecting the custom runtime.

Configuration follows the runtime

I keep the Codex configuration in two branches. The openai branch is for the standard build. The ollama branch contains the custom provider and worker configuration.

That branch switch is part of changing runtimes. I check the configuration repository first and do not switch across uncommitted work. Otherwise a binary change can be mixed with the wrong provider definitions, agent roles, or tool policy, which makes failures much harder to interpret.

The application data still lives under the same Codex home directory. Session and tool state may still differ between builds, so I use repository state as the stable boundary and treat conversation state as runtime-specific until verified.

The worktree is the handoff

I normally switch builds at a deliberate stopping point:

TEXT
finish or stop the active turn
        |
        v
inspect git status and the current diff
        |
        v
record tests, open questions, and the next bounded task
        |
        v
quit Desktop and select the other runtime
        |
        v
re-read repository state before continuing

I avoid letting both builds edit the same worktree at the same time. The second runtime should not have to infer which changes belong to the first task or whether an incomplete edit is safe to continue.

For a browser or image task, standard Codex produces the verified page state or asset. For a large bounded implementation, the custom build can then delegate work to Halo. Tests, diffs, screenshots, and saved files survive that handoff more reliably than an assumption that both runtimes share the same conversation semantics.

I choose the build from the task

My current routing rule is straightforward:

TEXT
Needs the built-in browser, image generation, Chrome extension,
or another signed application integration?
  Use standard Codex.
 
Needs Ollama-backed subagents or private worker controls?
  Use custom Codex.
 
Needs both?
  Split the work at a repository artifact or verification boundary.

This routing rule reflects the capabilities available in each runtime. It does not compare their model quality.

This split lets me use Halo-backed workers for bounded implementation and return to the signed build when a task needs Desktop's application integrations.