Repository navigation
[Bug]: codex features enable multi_agent_v2 is reported as failed because the TOML table reader stops inside a multi-line string #1295
Description
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 statuskeeps printingmulti_agent_v2: OFFeven thoughcodex features listprintsmulti_agent_v2 stable truefor the sameconfig.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 = trueB. 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 = trueResult:
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:
- Put a
[features.multi_agent_v2]table in~/.codex/config.tomlholding a multi-line string whose first line starts with[, and noenabledkey. - Run
ocx v2 status→multi_agent_v2: OFF. - Run
codex features enable multi_agent_v2→ printsEnabled feature `multi_agent_v2` in config.toml, exit 0. It appendsenabled = trueat the end of the table. - Run
codex features list | grep multi_agent_v2→multi_agent_v2 stable true. - Run
ocx v2 statusagain → stillmulti_agent_v2: OFF. - 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_v2Codex 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
github-actions commentedon Aug 8, 2026
Automated translation bookkeeping — detected language: unknown.
lidge-jun commentedon Aug 8, 2026
@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
enabledafter the"""block returnsfalse, and withenabledbefore it returnstrue. 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
tomlTableBodyyourself, 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,getMaxConcurrentThreadsstarted 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.parseinstead, andtomlTableBodyis 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:
isDefaultModeRequestUserInputEnabledand[agents] max_threadshad the same prose-as-assignment behaviour ondevalready.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.
fix(codex): read feature flags from a TOML parse, not a line scanner (#…
lidge-jun commentedon Aug 8, 2026
Fixed on
devas b90b41f (#1309).isMultiAgentV2Enabledand the sibling feature readers now go throughBun.TOML.parse, so a bracketed line inside a"""value no longer truncates the table andenabledis found wherever it sits. Your dashboard toggle andocx v2 statuswill agree withcodex features listagain, 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 targetdev. It ships in the next release offdev.Thanks again for the isolated reproduction — it is the reason this landed as a parser change rather than another patch to the line scanner.
fix(codex): read feature flags from a TOML parse, not a line scanner (l…