All notes

Using Ollama models with Codex providers

Why the goal is mixed-provider Codex delegation, and where today’s provider path breaks down.

  • This is the first note in a series about mixed-provider Codex delegation.
  • The goal was one Codex agent matrix that could mix OpenAI advanced models with Halo or Ollama workers.
  • Code generation and implementation work were major reasons to use those local workers.
  • A model provider is an inference endpoint, not the place where Codex runs commands.
  • Remote Ollama models can still read local files through Codex tool calls.
  • Direct profiles work around the handoff problem, but they do not allow mixed-provider teams.
  • In this Codex build, turning v2 off did not restore provider-readable subagent tasks for GPT-5.5 or GPT-5.6.
  • The current MultiAgentV2 subagent path can hide the child task in encrypted content.
  • A provider appearing in config does not prove work is actually being offloaded.
On this page

The goal was not just to make Codex talk to Ollama. The goal was to build a mixed-provider Codex agent matrix.

I wanted an advanced OpenAI-backed Codex model to stay in charge of the session: planning, tool authority, risk decisions, final review, and integration. Then I wanted to send bounded work to cheaper Halo-backed models running through Ollama and Open WebUI: code generation, implementation drafts, summaries, first-pass tests, and narrow reviews.

That looked simple at first. Add a custom model provider, point it at the OpenAI-compatible endpoint, and assign some Codex profiles or subagents to those models.

That is where the distinction matters. Provider configuration mostly describes inference. It does not, by itself, prove that native Codex delegation can mix OpenAI advanced models with other providers inside one agent tree.

What a model provider is

In Codex, a model provider is the endpoint that answers model requests. The provider might be OpenAI, Ollama, Open WebUI, LM Studio, or another OpenAI-compatible service.

The Codex runtime is still local. It owns the session, tools, sandbox, filesystem access, MCP connections, and approvals. The remote provider only receives prompts, tool results, and response state.

The shape looks like this:

TEXT
Codex runtime on my Mac
  - session state
  - shell and file tools
  - MCP tools
  - sandbox and approvals
 
        |
        | model request
        v
 
Remote model provider
  - Halo / Open WebUI / Ollama
  - inference only
 
        |
        | model response or tool call
        v
 
Codex runtime on my Mac
  - executes local tools

That distinction matters. In this remote inference setup, if a Halo-backed Codex profile reads a local file, Halo is not opening /Users/... on my Mac. Codex reads the file locally and sends the selected output back to the model.

Remote inference can still use local files

A direct Halo-backed Codex run can work because the top-level task is ordinary prompt text. The model can ask for a file search or read, and Codex executes the tool on the local machine.

TEXT
User asks Codex to inspect a file
        |
        v
Codex sends the task to Halo
        |
        v
Halo model asks for a tool call
        |
        v
Codex runs rg, sed, or another local tool
        |
        v
Codex sends the tool output back to Halo
        |
        v
Halo returns code, explanation, or another tool request

This is useful. It means an Ollama model can help with code generation without having direct filesystem access. The provider is remote, but the execution boundary stays with Codex.

Native subagents are a different path

The problem I hit was not basic remote inference. Direct provider calls worked. The problem was native Codex subagents.

This was observed with codex-cli 0.146.0-alpha.3.1. In that build, setting the configuration to disable the v2 agent path did not restore the old provider- readable handoff for the GPT-5.5 and GPT-5.6 profiles I tested. The setting may parse, but those model paths still used the encrypted native subagent message shape.

Subagents are not just another prompt. In the newer MultiAgentV2 path, Codex can send the child agent's task through an inter-agent message that contains encrypted content. OpenAI's backend can understand that private payload. A normal OpenAI-compatible provider, such as the Open WebUI relay in this setup, cannot decrypt it.

The observed shape looked like this:

TEXT
Parent Codex agent
        |
        v
spawn_agent
        |
        v
agent_message
        |
        |-- input_text header
        |
        `-- encrypted_content task body
                    |
                    v
          this relay cannot read it

Here is the sanitized proxy log from the failing shape:

TEXT
agent_items=[{
  "author":"/root",
  "recipient":"/root/halo_after_v2_disable_probe",
  "contentParts":[
    {"type":"input_text","encryptedLength":0},
    {"type":"encrypted_content","encryptedLength":268}
  ],
  "textPreview":"Message Type: NEW_TASK
Task name: /root/halo_after_v2_disable_probe
Sender: /root
Payload:
 
"
}]
 
POST /v1/responses input_types=message,message,message,message,agent_message converted=1
POST /v1/responses upstream=200

The important part is the empty Payload:. The visible message says a task exists, but the real task body is inside encrypted_content.

A compatibility proxy can rename agent_message into a normal message. It still cannot decrypt the task. At that point the model may guess from nearby context, but it did not receive a clean instruction.

That is a different failure from "the provider is down" or "Ollama cannot generate code." The provider can be healthy while the subagent handoff is still broken.

Configured does not always mean offloaded

There is another easy trap: a provider appearing in config does not prove that the work is actually running on that provider.

A Codex profile might say something like this:

TOML
[model_providers.halo]
name = "Halo Ollama"
base_url = "https://halo.example.com/ollama/v1"
wire_api = "responses"
 
[profiles.halo_worker]
model_provider = "halo"
model = "kimi-k2.7-code:cloud"

That is only the starting point. To know whether the offload is real, I need to check the actual request path:

TEXT
Does direct codex exec use the expected provider?
Does the provider receive the request?
Does the model receive the actual task text?
Do tool calls work?
Does local file content flow through Codex tools?
Does a subagent inherit the intended provider and model?

Those are separate checks. A profile can parse correctly and still fail at tool routing. A child agent can be created and still inherit the wrong provider. A request can reach Open WebUI and still contain a private Codex message shape the provider cannot consume.

Where that leaves things

This is not a useful pattern for modern agentic multi-model work. It breaks the thing that makes the setup valuable: one orchestrator coordinating different models by task, cost, latency, and risk.

The remaining options are operational workarounds. They can make a remote Ollama model generate text or code, but they do not provide a real mixed-provider agent flow.

A direct profile is a Codex profile that starts the whole top-level Codex turn on a chosen provider. Instead of asking an OpenAI-backed parent agent to spawn a Halo child, I start a separate Codex run whose model provider is Halo from the beginning.

That is not an acceptable substitute. It forces me to choose one provider ecosystem for the whole run, then switch sessions or profiles when I want a different model family. That adds coordination work exactly where the agent matrix was supposed to remove it.

The goal was mixed-provider delegation: keep an advanced Codex or GPT model as the orchestrator, then send bounded code generation, implementation, summarization, or review tasks to cheaper local or remote models. That lets the strongest model own planning, tool authority, final review, and risk, while Halo-backed models do focused work in parallel.

A direct profile does not do that. It chooses one provider for the whole top-level run. If I start Codex with a Halo profile, the main agent is Halo. If I start Codex with an OpenAI profile, the main agent is OpenAI. That profile-level choice does not give me an OpenAI parent and Halo children inside the same native Codex agent tree.

That is the important difference:

TEXT
Direct profile:
  user task -> Codex session using Halo provider
 
Native subagent:
  user task -> OpenAI-backed parent -> spawn Halo child

The direct profile path avoids the encrypted child-task handoff because there is no child handoff. The user prompt is the first task in that session, so it is sent to the configured provider as normal model input.

For example, a direct Halo profile can be useful for drafting code, summarizing files, writing first-pass tests, or reviewing a diff. Codex still executes the local tools.

But it gives up the core benefit of the agent matrix. It cannot mix a strong OpenAI-backed parent with Halo-backed specialist workers through Codex's native subagent mechanism. For my use case, that is a severe handicap, not a minor inconvenience.

For delegated work, a plain MCP tool or explicit worker command is safer than the broken native subagent path:

TEXT
Codex main agent
        |
        v
MCP tool: generate with Halo
        |
        v
selected local context sent as plain text
        |
        v
Halo returns a draft patch or notes
        |
        v
Codex reviews, edits, applies, and tests locally

That avoids the encrypted native subagent path. It also keeps authority in the main Codex runtime, where the local sandbox, file tools, and test commands are visible.

But it is still unsatisfactory. An MCP tool can send selected context to Halo and get back a draft. An explicit worker command can start a separate single-provider Codex run. Neither one gives me the thing I wanted: one Codex session where an advanced OpenAI-backed parent can delegate bounded native subagent work to Halo or Ollama models and then integrate the results. They replace native delegation with manual switching and glue code.

The short version is this:

TEXT
Remote inference works.
Remote file access is mediated by local Codex tools.
Direct profiles are useful but single-provider.
MCP-style offload is possible but manual.
Disabling v2 did not restore the old handoff for GPT-5.5 or GPT-5.6 here.
Mixed-provider native subagents are broken by the encrypted v2 handoff.

That is the problem. Code generation was one of the main reasons to bring Ollama and Halo into the Codex workflow in the first place. The workarounds can move some of that generation to local or remote Ollama models, but they do not preserve the agent matrix. They make me choose one ecosystem at a time, then manage the handoff myself. Until the native subagent handoff can send provider-readable task content, mixed-provider Codex delegation remains broken. That is a severe handicap for anyone trying to use Codex as a real multi-provider orchestrator.