Skip to content

[Bug]: codex features enable multi_agent_v2 is reported as failed because the TOML table reader stops inside a multi-line string #1295

Closed

Description

@brunoflma

Client or integration

OpenCodex dashboard

Area

CLI

Summary

codex features enable multi_agent_v2 succeeds, but OpenCodex re-reads the result and concludes it did not, so every toggle path reports failure:

  • the dashboard Models → Sub-agent → v2 switch fails with multi_agent_v2 transition failed: codex feature command did not enable multi_agent_v2;
  • ocx v2 status keeps printing multi_agent_v2: OFF even though codex features list prints multi_agent_v2 stable true for the same config.toml.

The Codex command is not at fault — it writes enabled = true correctly. The failing part is the postcondition check in isMultiAgentV2Enabled().

Root cause is in tomlTableBody() (src/codex/features.ts:87), which ends the table body at the first line matching /^\s*\[/ (src/codex/features.ts:93):

const end = rest.findIndex(l => /^\s*\[/.test(l));

That scanner is not aware of TOML multi-line basic strings ("""). When a key inside [features.multi_agent_v2] holds a multi-line string that contains a line starting with [, the body is cut inside the string literal. codex features enable appends enabled = true at the end of the table, after the string closes, so the key lands outside the extracted body, tomlBoolInBody() returns null, and isMultiAgentV2Enabled() returns false.

A bracketed line inside such a string is not exotic: any prose containing a bracketed tag triggers it. In my case it is the first line of multi_agent_mode_hint_text.

Expected: isMultiAgentV2Enabled() should agree with codex features list for the same file, and the dashboard toggle should succeed.

I have a one-line workaround (moving enabled above the multi-line key), so this is not urgent for me — but the failure is silent and misattributes the fault to the Codex command, which is what makes it worth reporting.

Reproduction

Minimal, no Codex install needed — three files through isMultiAgentV2Enabled() from src/codex/features.ts, isolating the single variable:

A. enabled after a """ block whose first line starts with [ — this is the exact shape codex features enable produces:

[features.multi_agent_v2]
hint = """
[some bracketed first line]
more prose
"""
enabled = true

B. control — enabled before the block:

[features.multi_agent_v2]
enabled = true
hint = """
[some bracketed first line]
more prose
"""

C. control — no multi-line string:

[features.multi_agent_v2]
enabled = true

Result:

FALSE  <- A: enabled AFTER a """ block starting with [
true   <- B: enabled BEFORE the block
true   <- C: no multi-line string

Only A fails, so the multi-line string is the whole variable.

End-to-end on a real install:

  1. Put a [features.multi_agent_v2] table in ~/.codex/config.toml holding a multi-line string whose first line starts with [, and no enabled key.
  2. Run ocx v2 status → multi_agent_v2: OFF.
  3. Run codex features enable multi_agent_v2 → prints Enabled feature `multi_agent_v2` in config.toml, exit 0. It appends enabled = true at the end of the table.
  4. Run codex features list | grep multi_agent_v2 → multi_agent_v2 stable true.
  5. Run ocx v2 status again → still multi_agent_v2: OFF.
  6. Toggle Sub-agent v2 in the dashboard → multi_agent_v2 transition failed: codex feature command did not enable multi_agent_v2.

I also confirmed the truncation directly: the extracted body stops after 3 lines, at the bracketed line, and the extracted slice contains an odd number of """ markers — i.e. the cut happened with a string literal still open.

Note: this is not a 2.11.0 regression. tomlTableBody() is byte-identical between v2.10.2 and v2.11.0; the defect is latent and only fires on this config shape.

Version

2.11.0

Operating system

Windows 11 Home Single Language 26H2 (build 10.0.26200)

Provider and model

Not provider-specific.

Logs or error output

$ ocx v2 status
multi_agent_v2: OFF — v1 multi-agent surface (default install)

$ codex features enable multi_agent_v2
Enabled feature `multi_agent_v2` in config.toml.

$ codex features list | grep multi_agent_v2
multi_agent_v2                       stable             true

$ ocx v2 status
multi_agent_v2: OFF — v1 multi-agent surface (default install)

# dashboard toggle:
multi_agent_v2 transition failed: codex feature command did not enable multi_agent_v2

Codex CLI version: codex-cli 0.147.0.

Screenshots and supporting files

Not attached — the reproduction above is self-contained.

Redacted configuration

{
  "note": "The trigger lives in ~/.codex/config.toml, not in the OpenCodex config. Redacted shape:",
  "codex_config_toml": [
    "[features.multi_agent_v2]",
    "hide_spawn_agent_metadata = false",
    "tool_namespace = \"agents\"",
    "multi_agent_mode_hint_text = \"\"\"",
    "[codex-orchestration managed-policy v1]",
    "... prose ...",
    "\"\"\"",
    "enabled = true   <-- appended here by `codex features enable`, outside the parsed body"
  ]
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. github-actions commented on Aug 8, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: unknown.

  2. added
    bugSomething isn't working
    cliCLI, config inject, packaging flags
    on Aug 8, 2026
  3. lidge-jun commented on Aug 8, 2026

    @lidge-jun
    Owner

    @brunoflma Confirmed exactly as you described, and fixed in #1309.

    Your diagnosis was right down to the line. I reproduced it before touching anything: the same table with enabled after the """ block returns false, and with enabled before it returns true. Key order alone decides the answer, which is a good way to know a parser is guessing.

    Worth saying that your framing saved the most time here. You identified tomlTableBody yourself, ruled out the Codex command, and gave a three-file reproduction that isolates the single variable — so there was no phase of chasing the wrong layer.

    The fix is not the one I first wrote. My instinct was to make the line scanner string-aware, and review caught that doing so introduced regressions in three other readers that consume the same function's output through regexes (getAgentsEnabled, getAgentsMaxDepth, getMaxConcurrentThreads started returning values pulled out of string content). Twenty call sites depend on what that scanner returns, so widening it is a much larger change than it looks.

    So the readers now go through Bun.TOML.parse instead, and tomlTableBody is untouched. Prose that looks like an assignment stops being one because a real parser never confused the two.

    Two related defects you did not report turned up alongside and are fixed in the same PR: isDefaultModeRequestUserInputEnabled and [agents] max_threads had the same prose-as-assignment behaviour on dev already.

    You mentioned your one-line workaround makes this non-urgent for you — appreciated, but the silent misattribution to the Codex command is the part that makes it worth fixing properly rather than documenting. Someone without your diagnosis would have filed this against Codex.

  4. lidge-jun commented on Aug 8, 2026

    @lidge-jun
    Owner

    Fixed on dev as b90b41f (#1309).

    isMultiAgentV2Enabled and the sibling feature readers now go through Bun.TOML.parse, so a bracketed line inside a """ value no longer truncates the table and enabled is found wherever it sits. Your dashboard toggle and ocx v2 status will agree with codex features list again, and you can drop the key-order workaround.

    Closing manually: the PR said Fixes #1295, but GitHub only auto-closes on merges into the default branch and PRs here target dev. It ships in the next release off dev.

    Thanks again for the isolated reproduction — it is the reason this landed as a parser change rather than another patch to the line scanner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcliCLI, config inject, packaging flags

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions