codex

Codex works on a workstation with no configuration. This is for when you want to set a model, add MCP servers, or hand Codex a config.toml of your own.

Install Codex with the codex devtool and it is ready to use with its own defaults. Add this toolconfig when you want to change them. The simplest form is your config.toml, written as you would write it yourself:

toolconfigs:
  - id: codex
    name: codex
    config:
      configToml: |
        model = "o4-mini"

Ringleader writes that to ~/.codex/config.toml, owned by the login user and readable by nobody else, since it may hold a provider API key. The rest of this page covers the structured form, MCP servers, workspace trust, and the field list.

Structured form

If you would rather not write TOML, give the same settings as YAML under config and Ringleader renders them:

toolconfigs:
  - id: codex
    name: codex
    config:
      config:
        model: o4-mini              # a top-level scalar
        some_section:               # an object becomes a [section] table
          key: value
          enabled: true

renders as:

model = "o4-mini"

[some_section]
enabled = true
key = "value"

Key names are Codex’s, not Ringleader’s; nothing is validated or renamed, and keys are sorted so re-applying the same input changes nothing. The renderer handles top-level values and one level of [section] tables. Anything deeper (a table inside a section, an array of tables) is refused with a clear error; use configToml for those. If both are present, config wins.

MCP servers

Declare MCP servers by name and Ringleader writes Codex’s own [mcp_servers.<name>] tables, the same bytes codex mcp add would write:

toolconfigs:
  - id: codex
    name: codex
    config:
      mcpServers:
        linear:
          command: npx
          args: ["-y", "mcp-remote", "https://mcp.linear.app/sse"]
        internal:
          command: /opt/tools/mcp-internal
          env:
            API_BASE: https://api.internal.example

renders as:

[mcp_servers.internal]
command = "/opt/tools/mcp-internal"

[mcp_servers.internal.env]
API_BASE = "https://api.internal.example"

[mcp_servers.linear]
args = ["-y", "mcp-remote", "https://mcp.linear.app/sse"]
command = "npx"

A server definition takes scalars, an array of scalars (args), and one level of nested table (env); anything deeper is refused, and configToml is the way to write it. If your configToml already contains a [mcp_servers.<name>] table, the declared server of that name is skipped, because a duplicate table would make Codex reject the whole file.

Workspace trust

Folders in sources[].path and trustedFolders are added to the file as [projects."<absolute path>"] tables with trust_level = "trusted", which is Codex’s own per-project trust setting. A path you declared yourself is left alone. This happens whenever the workstation declares trusted folders, even with no codex toolconfig.

config fields

Provide one of the first three. mcpServers can accompany any of them.

FieldTypeDescription
configTomlstringA raw TOML document, written as is.
configobjectSettings as YAML, rendered to TOML. Wins if configToml is also present.
userConfigobjectAn alias for config.
mcpServersobjectMCP servers by name, rendered into [mcp_servers.…] tables.

Example

apiVersion: workstations.ringleader.dev/v1
kind: WorkstationConfig
metadata:
  name: codex-box
  namespace: local
spec:
  selector:
    matchLabels:
      tier: dev
  identity:
    user: dev
  devtools:
    - name: nodejs
      version: "24"
    - name: codex
  toolconfigs:
    - id: codex
      name: codex
      config:
        configToml: |
          model = "o4-mini"
  sources:
    - name: app
      git:
        url: https://github.com/acme/app.git
      path: /home/dev/src/app     # added as a trusted project

Notes

  • Codex has no managed (operator-enforced) layer here, only a single user-owned file.
  • The file is rewritten every time the workstation applies its configuration, so edits made inside it revert.
  • Secret references are resolved before the file is rendered, in either form.