# Windmill AI on Codex Pooler

Windmill is a developer platform for building scripts, workflows and internal apps. Its AI features help write and fix code, generate flows and summarize work. Connect Windmill AI to Codex Pooler to use your Pool's models from the workspace.

![Codex Pooler Windmill AI integration](/codex-pooler-windmill.webp)

## Before you start

- Set up [Windmill](https://www.windmill.dev/docs/getting_started/how_to_use_windmill) and make sure you can edit the workspace AI settings.
- Have a Codex Pooler URL reachable from Windmill's server.
- Create a [Pool API key](/getting-started/quick-start/) and choose a model available to that Pool.

`localhost` refers to the Windmill server, not the browser running Windmill.

## Configure the connection

Use a dedicated Pool API key for Windmill's `customai` connection. Operator MCP tokens and upstream account credentials are not model-request credentials.

Use the commands for the terminal that starts the client. Environment-variable assignments below apply to that terminal; desktop apps and services need the variables in their own launch environment.

### Runtime shape

Windmill should call Codex Pooler's OpenAI-compatible `/v1` surface:

```text
https://codex-pooler.example.com/v1
```

For local setup, use:

```text
http://localhost:4000/v1
```

The setup uses Windmill's `customai` resource type. It is a chat-completions
integration, not Codex backend compatibility and not full OpenAI API parity.

### Store the Pool API key in Windmill

Create a Windmill secret variable for the Pool API key. The path is only an
example; use the owner or folder convention for your workspace.

**macOS / Linux / WSL**

```bash
wmill variable add '<pool-api-key>' \
  'u/<owner>/codex_pooler_windmill_codegen' \
  --workspace '<workspace>'
```

**Windows PowerShell**

```powershell
wmill variable add '<pool-api-key>' 'u/<owner>/codex_pooler_windmill_codegen' --workspace '<workspace>'
```

If you mirror Windmill resources with `wmill sync`, update the remote secret
first and then pull the encrypted export. Do not put a raw Pool API key in a
tracked `*.variable.yaml` file.

### Create a `customai` resource

Create a Windmill `customai` resource whose `base_url` points at Codex Pooler's
`/v1` surface and whose `api_key` references the secret variable.

```yaml
description: Codex Pooler API credentials for Windmill AI
value:
  api_key: '$var:u/<owner>/codex_pooler_windmill_codegen'
  base_url: https://codex-pooler.example.com/v1
  headers: {}
resource_type: customai
```

For local setup, change `base_url` to `http://localhost:4000/v1`.

Use `headers` only for synthetic routing metadata required by your gateway or
proxy. Do not put bearer tokens or account secrets in those headers.

<a id="configure-workspace-ai"></a>

## Choose a model

In Windmill, open the workspace settings and configure Windmill AI with the
`customai` provider. Use the `customai` resource path and model id your assigned
Pool can serve.

```yaml
providers:
  customai:
    resource_path: u/<owner>/codex_pooler_windmill_codegen
    models:
      - gpt-6-luna
      - gpt-6-sol
      - gpt-6-astra
default_model:
  provider: customai
  model: gpt-6-sol
metadata_model:
  provider: customai
  model: gpt-6-sol
```

This enables Windmill AI chat, navigation chat, script and flow assistance,
fixes, summaries, metadata generation, and form-filling features that use chat
completion style requests.

<a id="connection-check-through-windmill"></a>

## Verify the connection

After saving the resource and workspace AI settings, call Windmill's AI proxy
route. Use a Windmill user token for the Windmill API request and let Windmill
resolve the Pool API key from its `customai` resource.

**macOS / Linux / WSL**

```bash
curl -sS -X POST \
  -H "Authorization: Bearer <windmill-user-token>" \
  -H "Content-Type: application/json" \
  -H "X-Provider: customai" \
  --data '{
    "model": "gpt-6-sol",
    "messages": [
      { "role": "user", "content": "Reply with only: ok" }
    ],
    "stream": false,
    "max_completion_tokens": 16
  }' \
  "$WINDMILL_URL/api/w/<workspace>/ai/proxy/chat/completions"
```

**Windows PowerShell**

```powershell
$headers = @{
  Authorization = "Bearer <windmill-user-token>"
  "X-Provider" = "customai"
}
$body = @{
  model = "gpt-6-sol"
  messages = @(@{ role = "user"; content = "Reply with only: ok" })
  stream = $false
  max_completion_tokens = 16
} | ConvertTo-Json -Depth 5
Invoke-RestMethod -Method Post -Uri "$env:WINDMILL_URL/api/w/<workspace>/ai/proxy/chat/completions" -Headers $headers -ContentType "application/json" -Body $body
```

Windmill's agent request field is `max_completion_tokens`; provider adapters map it to OpenAI Responses `max_output_tokens` or chat `max_completion_tokens` as needed. Do not use `max_tokens` for GPT-5/O-series Windmill AI requests.

A working setup returns an OpenAI-shaped chat completion. If the response says
the URL resolves to a private or internal IP address, set
`ALLOW_PRIVATE_AI_BASE_URLS=true` on the Windmill app/server runtime and restart
or roll out the app.

In Codex Pooler's request logs, match the request time, API key, model, and final status to your test. A reply alone does not confirm that the client used your Pooler instance.

## Advanced configuration

### Self-hosted private URL guard

Self-hosted Windmill validates AI provider base URLs before sending requests. If
your deployed Codex Pooler hostname resolves to a private or internal address
from the Windmill app/server runtime, Windmill rejects the request unless the
server explicitly opts in.

Set this environment variable on the Windmill app/server process:

```text
ALLOW_PRIVATE_AI_BASE_URLS=true
```

For the Windmill Helm chart, put it on the app/server container environment:

```yaml
windmill:
  app:
    extraEnv:
      - name: ALLOW_PRIVATE_AI_BASE_URLS
        value: "true"
```

This setting belongs to Windmill, not Codex Pooler. Use it only when the
Codex Pooler base URL is intentionally private from Windmill's point of view.

## Compatibility notes

Leave Windmill's code completion model unset unless you have separately
configured a provider with fill-in-the-middle autocomplete support. Windmill's
autocomplete path is distinct from chat/codegen, and generic chat-completions
providers are not a drop-in replacement for a fill-in-the-middle completion
endpoint.

Codex Pooler's `/v1` surface is narrow OpenAI-compatible support over Codex Pool
routing. It does not provide full OpenAI API parity, and OpenAI Realtime SDK
routes are unsupported.