Custom subagents in .codex/agents are not accessible from tool-backed Codex sessions as docs imply
What version of Codex is running?
I am filing from a Codex session that exposes the spawn_agent tool surface rather than the standalone Codex CLI/TUI. I do not have the exact product build identifier available in-session.
Which model were you using?
Observed across tool-backed Codex sessions while testing spawn_agent with multiple models and reasoning levels.
What OS are you running?
macOS
What happened?
The official subagents docs say custom agents live in .codex/agents/*.toml, use the name field as the source of truth, and inherit model / model_reasoning_effort when omitted.
In a tool-backed Codex session, repo-local custom agents are visible on disk and valid TOML, but there is no runtime path to invoke them by name. The exposed spawn_agent interface only accepts a generic agent_type plus explicit prompt/model overrides. There is no parameter to say "spawn custom agent review-bugs from .codex/agents/review-bugs.toml".
As a result, the only workaround is to manually read each TOML file and inject its developer_instructions into a generic spawned worker. That is not the behavior the docs imply.
Steps to reproduce
- Create a valid custom subagent file such as
.codex/agents/review-bugs.tomlwith:
namedescriptiondeveloper_instructions- optional
sandbox_mode
- Omit
modelandmodel_reasoning_effortso they inherit from the parent, as documented. - Start a Codex session that exposes the
spawn_agenttool surface. - Attempt to invoke the custom agent by name (for example,
review-bugs). - Inspect the available
spawn_agentinterface.
Expected behavior
One of these should be true:
- Custom agents from
.codex/agents/*.tomlare invocable by name in tool-backed Codex sessions, consistent with the docs. - Or the docs explicitly scope this feature to the Codex app/CLI/TUI and state that tool-backed/API sessions do not auto-load repo-local custom agents.
Actual behavior
The custom agent files are valid and present, but the runtime only exposes generic spawning. Named custom-agent invocation is not available through the tool surface.
Evidence collected
- We converted repo-local agents from Markdown frontmatter files to valid TOML custom agents under
.codex/agents/. - We removed
modelandmodel_reasoning_effortso they inherit from the parent session, matching the docs. - The TOML files parse correctly.
- The limitation persists even after ruling out GitHub auth and shell sandbox/network issues.
Why this matters
This creates a docs/runtime mismatch for anyone trying to build reusable project-specific subagents. The docs make it sound like named custom agents are a general Codex capability, but in tool-backed sessions the feature is not exposed in a first-class way.
Suggested resolution
Either:
- Expose named custom-agent loading in tool-backed Codex sessions, or
- Clarify the docs to distinguish between Codex app/CLI behavior and tool-backed/API runtime behavior.
Related issues checked
I searched for duplicates and did not find an existing issue describing this exact named-custom-agent/tool-runtime mismatch. Related but different issues include:
- #14451 Invalid agent role TOML silently breaks entire app
- #14039 Allow per-subagent model/provider/profile selection
- #11004 developer_instructions are not attached to app-created threads
15 Comments
+1, this gap matters for tool-backed Codex sessions.
If project-scoped and global custom agents are documented as first-class
.codex/agents/*.tomldefinitions, they should be invokable consistently from all Codex surfaces that expose subagent spawning. Otherwise the same repository setup works in one Codex surface but fails in another, which makes custom-agent workflows hard to trust.Expected behavior from my point of view:
.codex/agents/and~/.codex/agents/are discoverable in tool-backed sessionsspawn_agentcan target them by their declared name or stable identifierThis would make project-local agent definitions usable as shared workflow infrastructure rather than only as documentation-adjacent config.
This feels like a docs and runtime contract gap. If tool-backed sessions cannot resolve repo-local agents by name, Codex should either expose a custom_agent or
ame field on spawn_agent or emit a first-class capability flag saying named agents are unavailable in this runtime. Right now users end up manually parsing TOML just to rehydrate something the platform already understands. We hit a similar problem in MartinLoop when trying to keep role intent portable across tool-backed and app-backed runs. The receipt should say not only what spawned, but which resolution path was used: named agent, generic role, or fallback.
I can reproduce a related and possibly stronger version of this on Codex CLI
0.137.0on Linux in standalone Codex sessions.Setup
User config registers custom agents:
Agent TOML example:
What happened
In a standalone Codex session, the exposed
multi_agent_v1.spawn_agentschema only accepted:messageitemsfork_contextIt did not expose
agent_type,model,reasoning_effort,agent_path, or another role selector.Prompting the parent to "use the native plan-reviewer role" caused the parent to call:
The child spawned as a generic agent, not as the registered custom agent.
Child session metadata:
MultiAgentV2 check
With
multi_agent_v2 = true, the exposed spawn path acceptedtask_name, buttask_name = "plan_reviewer"produced a child with:So v2
task_namebehaved like an agent path/name label, not a custom-agent TOML resolver.Expected behavior
A registered custom agent should be invocable from the native subagent tool surface by declared name/role, and its TOML should apply:
model = "gpt-5.4-mini"model_reasoning_effort = "xhigh"developer_instructionsagent_roleoragent_pathActual behavior
The custom agent TOMLs are present and registered, but current native spawning cannot bind them. The role name can only be embedded as text in the child prompt, which produces a generic inherited-model subagent.
This appears to be a docs/runtime mismatch plus a regression from older sessions where
spawn_agentcalls includedagent_type: "plan-reviewer"and the child metadata showed the specialized role/model.Tried in v2 with following arguments:
{
"task_name": "search_docs",
"agent_type": "search-specialist",
"model": "gpt-5.4-mini",
"reasoning_effort": "medium",
"fork_turns": "none",
"message": "..."
}
And its working. I guess these arguments are not documented but somehow inside of the tool.
Created a plugin to enforthis such behaviour: https://github.com/eiphy/codex-subagent-guard/tree/main
Additional privacy-safe reproduction from a Windows Codex CLI session:
~/.codex/config.toml~/.codex/agents/*.tomlObserved state:
codex features listreportsmulti_agentas stable/true andmulti_agent_v2as false.~/.codex/config.tomlparses successfully and contains 33[agents.gsd-*]entries.~/.codex/agents/gsd-planner.tomlandgsd-executor.tomlfiles exist and parse.gsd-tools query init.quick) reportsagents_installed: true,missing_agents: [],agent_runtime: codex.multi_agent_v1.spawn_agent(message=..., fork_context=false)returns an agent id and the child replies.Actual exposed tool schema in the model-visible session:
There is no
agent_type/subagent_typeparameter exposed to the model, so an orchestrator cannot invoke a configured named agent such asgsd-plannerorgsd-executordirectly, despite those agents being installed and registered.Expected behavior:
If user-global custom agents are registered in
~/.codex/config.toml, the tool-backed session should expose a way to select them, for exampleagent_type, or documentation should explicitly state thatmulti_agent_v1tool-backed sessions only support generic child agents.Privacy note: local usernames, project names, and absolute private workspace paths are intentionally redacted here.
I can reproduce a model-dependent version of this in Codex CLI 0.142.5.
With
multi_agent = trueandmulti_agent_v2 = false, a fresh GPT-5.4 thread exposes V1 withagent_type,model, andreasoning_effort; spawning a GPT-5.4-mini child with an explicit effort succeeds. I also spawnedagent_type: "harness_reviewer"from a personal~/.codex/agents/profile. The result reported roleharness_reviewer, displayed modelgpt-5.4, displayed reasoning effortmedium, and the expected child response.A fresh GPT-5.5 thread behaves differently. The current model catalog sets
multi_agent_version: v2for GPT-5.5, and the runtime gives that model value precedence over the localmulti_agent_v2 = falsesetting. Its exposed schema contains onlytask_name,message, andfork_turns. It has noagent_type,model, orreasoning_effort, so configured profiles such asreviewerandharness_reviewercannot be selected. Naming the taskreviewercreates only a generic task path and does not resolve the TOML profile.Changing an existing GPT-5.5 thread to GPT-5.4 leaves it on V2 because the multi-agent version is pinned to the thread; starting a fresh GPT-5.4 thread restores V1.
This makes the documented custom-agent capability model-dependent in a way that is neither visible in
features listnor disclosed on the Subagents page. I filed the model-metadata/configuration-precedence reproduction here: https://github.com/openai/codex/issues/31097I can reproduce this in Codex Desktop on macOS.
Environment:
Codex Desktop
Codex CLI bundled version: 0.144.0-alpha.4
Root model: gpt-5.6-sol
Custom agents under ~/.codex/agents/:
economy_worker: gpt-5.6-luna, medium reasoning
economy_reviewer: gpt-5.6-terra, high reasoning
The custom TOML files load without configuration errors. However, the spawn_agent tool exposed to the root agent accepts only task_name, message, and fork_turns. It provides no custom-agent role or model parameter.
Spawning with task_name = "economy_worker" only names the child thread. Runtime metadata records:
agent_role: null
model: gpt-5.6-sol
The child therefore inherits Sol instead of loading the economy_worker TOML and running Luna. The same problem occurs with the Terra reviewer.
This caused unexpectedly slow and expensive delegation because multiple supposed “economy” workers were actually full Sol agents. Observed worker durations included approximately 3.5, 6, and 8 minutes.
Expected behavior:
spawn_agent should allow the root agent to explicitly select a named custom-agent role loaded from ~/.codex/agents/; or
Codex should automatically resolve an explicitly requested registered role; and
spawned-agent metadata/UI should clearly show the selected role, model, and reasoning effort.
As a temporary safeguard, I changed my global AGENTS.md to prohibit delegation unless the custom role and model can be explicitly selected and verified.
I can reproduce a closely related—and potentially more serious—variant on Codex CLI 0.144.1 on macOS.
In my case, named project-scoped agents appear to spawn successfully, but the requested profiles are not applied. The requested name becomes the child thread’s agent-path label while the child silently inherits the coordinator’s model and reasoning effort.
Configuration
I created five valid profiles under
.codex/agents/:v2_terra_executor_medium—gpt-5.6-terra/mediumv2_terra_executor_high—gpt-5.6-terra/highv2_terra_validator_high—gpt-5.6-terra/highv2_luna_evidence_low—gpt-5.6-luna/lowv2_luna_archivist_medium—gpt-5.6-luna/mediumThe files also specify role-specific instructions and sandbox modes.
Observed result
I spawned five children using those profile names and inspected the persisted rollout records under:
~/.codex/sessions/2026/07/11/For every child:
session_meta.agent_pathmatched the requested profile/task name.turn_contextshowed the actual model, reasoning effort and sandbox.| Requested profile | Actual model | Actual effort | Actual sandbox |
| --- | --- | --- | --- |
|
v2_terra_executor_medium|gpt-5.6-sol|high|workspace-write||
v2_terra_executor_high|gpt-5.6-sol|high|workspace-write||
v2_terra_validator_high|gpt-5.6-sol|high|workspace-write||
v2_luna_evidence_low|gpt-5.6-sol|high|workspace-write||
v2_luna_archivist_medium|gpt-5.6-sol|high|workspace-write|This indicates that
task_namelabels the spawned agent path but does not select the corresponding custom profile through the collaboration surface exposed in this build.Why this is especially concerning
This does not fail visibly.
The requested custom-agent name is accepted, and the child appears under that name. A user can therefore reasonably believe that a lower-cost Terra/Luna profile with low or medium reasoning was selected, while the child actually runs using the coordinator’s Sol/high allocation.
Because each spawned child consumes its own tokens, silent substitution can materially increase usage during multi-agent fan-out. The user receives no clear warning that the requested cost/quality profile was ignored.
This creates both a configuration-integrity problem and a usage-transparency problem.
Expected behavior
One of the following should happen:
spawn_agentexposes an explicitagent_typeor equivalent parameter that resolves a named.codex/agents/*.tomlprofile.Silently falling back to the coordinator configuration should not be considered successful profile selection.
Related reports
This also appears related to:
agent_typeoverrides conflicting with full-history forksThe distinguishing evidence here is that five differently configured profile names were accepted, but all five persisted child contexts showed the same actual
gpt-5.6-sol/highallocation.workaround:
Pushing sol I got the following solution working. It requires permission to work outside the sandbox wired into governance.
Try feeding this to sol as a workaround that it can implement itself
Workaround: make Codex 0.144.1 actually run Terra/Sol workers at the requested reasoning level
## 1. Run a no-repository canary
Do not use --ephemeral: you need the persisted rollout to verify the actual allocation.
codex exec \
--strict-config \
--model gpt-5.6-terra \
-c 'model_reasoning_effort="high"' \
-c 'sqlite_home="/tmp/codex-terra-canary-state"' \
--sandbox read-only \
--cd /tmp \
--skip-git-repo-check \
--json \
'Read no files and run no tools. Reply exactly CANARY_OK.'
An isolated sqlite_home avoids conflicts with an active Codex CLI/App state database.
For a Sol xhigh worker:
codex exec \
--strict-config \
--model gpt-5.6-sol \
-c 'model_reasoning_effort="xhigh"' \
-c 'sqlite_home="/tmp/codex-sol-xhigh-canary-state"' \
--sandbox read-only \
--cd /tmp \
--skip-git-repo-check \
--json \
'Read no files and run no tools. Reply exactly CANARY_OK.'
## 2. Verify the actual allocation
Find the new rollout under:
find ~/.codex/sessions -name 'rollout-*.jsonl' -type f -print0 |
xargs -0 ls -t |
head
Then inspect its first turn_context:
jq -c '
select(.type == "turn_context") |
{
model: .payload.model,
effort: .payload.effort,
sandbox: .payload.sandbox_policy
}
' /path/to/rollout.jsonl | head -n 1
Expected evidence:
{
"model": "gpt-5.6-terra",
"effort": "high",
"sandbox": {"type": "read-only"}
}
Do not trust:
Persisted turn_context is the decisive control-plane evidence. In my case, Tokenscale subsequently showed Terra’s lower price as
independent billing confirmation.
## 3. Run the real bounded worker
Put the worker’s instructions in a task packet:
codex exec \
--strict-config \
--model gpt-5.6-terra \
-c 'model_reasoning_effort="high"' \
-c 'sqlite_home="/tmp/codex-terra-worker-state"' \
--sandbox workspace-write \
--cd /path/to/repository \
--output-last-message /tmp/terra-worker-result.md \
The task packet should specify:
## 4. Reuse the worker’s warmed context
Once a Terra worker has learned a bounded subsystem, resume it instead of repeatedly creating cold workers:
codex exec resume \
--strict-config \
--model gpt-5.6-terra \
-c 'model_reasoning_effort="high"' \
-c 'sqlite_home="/tmp/codex-terra-worker-state"' \
--output-last-message /tmp/terra-followup-result.md \
THREAD_ID \
The resumed turn should again produce a matching persisted turn_context.
## Important boundaries
better suited to bounded execution and validation.
I can reproduce this with a user-global custom agent on Codex CLI 0.144.1, macOS arm64. A fresh process does not fix it, and the custom agent's instructions and context restrictions are not applied.
Global agent configuration
I created a regular, non-symlinked file at
~/.codex/agents/scout.tomlwith:The TOML parses successfully and
codex doctorreports zero configuration failures.Reproduction
I started a new parent process after the agent file existed:
I repeated the test three ways:
--enable use_agent_identity--ignore-user-config --enable multi_agent_v2 --enable use_agent_identityThe third variant required
--ignore-user-configbecausemulti_agent_v2otherwise rejected the existing[agents] max_threadssetting with:Actual result
All three runs spawned a child whose path was named
/root/scout, but all three persisted child transcripts recorded:In every child:
developer_instructionswere absentskills.config = []gpt-5.6-terra/lowonly because the parent was deliberately pinned to those settingsThe stable
spawn_agentcall recorded in the parent transcript accepts only:There is no
agent_type, role, profile or custom-agent identifier.task_name = "scout"labels the child path; it does not select~/.codex/agents/scout.toml.This also proves that restarting Codex is not a workaround: every test used a newly started process created after the global agent file existed.
Impact
This is not a cosmetic role-selection issue. It makes model and cost routing impossible and silently defeats context isolation.
Before identifying the failure, three children intended for cheaper read-heavy work silently ran as
gpt-5.6-sol/high. Their persisted cumulative totals were:Those transcript totals are not necessarily billable-token totals, but they demonstrate the scale of the silent substitution. The child names looked correct while the actual runtime configuration was wrong.
Required behavior
spawn_agentmust expose an explicit custom-agent identifier such asagent_type~/.codex/agents/*.tomlfrom tool-backed CLI and app sessionsThe current behavior makes documented custom agents unusable as reliable workflow infrastructure.
I can reproduce this on macOS with Codex Desktop using
multi_agent_version = v2and Codex CLI 0.144.1.I tested all currently documented and previously suggested configuration paths:
.codex/agents/~/.codex/agents/[agents.<name>]registry withconfig_filecodex exec --strict-configprocess started after the global files existedfork_turns: "none"to rule out full-history inheritance conflictsThe global registry configuration was accepted by
--strict-config, but the exposedspawn_agentschema still contained only:A direct request to use
agent_typefailed with:Using the configured agent name as
task_namespawned a generic child. Persisted child metadata showed:The requested custom profile specified
gpt-5.6-terra, a different reasoning effort, read-only sandboxing, and unique developer instructions. None of these settings were applied.As a control, I started a fresh parent explicitly pinned to
gpt-5.6-terra, medium reasoning, and read-only sandboxing. A generic child spawned withfork_turns: "none"inherited exactly those parent settings. This confirms that the current behavior is silent parent inheritance, not custom-agent resolution.This also rules out restarting Codex or moving the agent to the global registry as a workaround in the current V2 tool surface.
task_nameonly labels the child path.It would help if
spawn_agenteither:agent_typeor custom-agent identifier,The spawn result and UI should also report the effective role, model, reasoning effort, and sandbox before the child starts substantive work.
I am seeing this regression in the Codex desktop app as well, with additional before/after evidence.
Previously, the spawned-agent tool exposed an agent_type parameter. A call with agent_type="atlassian" successfully selected my project-local .codex/agents/atlassian.toml, started the MCP server configured under mcp_servers.alm-jira, and exposed jira_add_comment to that child agent.
In the current desktop runtime, the collaboration spawn_agent interface no longer exposes agent_type or another custom-agent selector. It exposes only a task_name used to name the spawned task. Spawning a worker and instructing it to read .codex/agents/atlassian.toml does not apply that file as a configuration layer, so its agent-scoped MCP server is absent from the child tool catalog.
I verified that this is not an invalid TOML, missing executable, authentication, or MCP-server problem: /Users/kmizuta/.local/bin/mcp-atlassian exists, and manually starting it with the arguments from atlassian.toml successfully advertises and executes jira_add_comment. The failure is specifically that the current spawn interface cannot select the named custom agent and therefore never loads its MCP configuration.
Moving these MCP servers into the parent project config is not a viable workaround for users with many specialist MCP servers: loading all servers globally causes startup overhead, performance problems, disconnects, and removes the intended per-agent tool isolation.
Expected behavior: restore a custom-agent selector equivalent to agent_type="atlassian" so project-local .codex/agents/*.toml files are applied as configuration layers, including their agent-specific mcp_servers.
Confirming this on Codex Desktop for Windows in a tool-backed session.
Valid custom-agent TOML files exist under
~/.codex/agents/, but the exposedspawn_agenttool accepts onlytask_name,message, andfork_turns. It provides noagent_type, custom-agent name, model, or reasoning parameters.This means a skill can require a named custom agent, but the runtime cannot verifiably select it. Prompting a generic subagent to imitate that role is not equivalent (and the expensive solution sol will silently select).
I can reproduce a more severe variant on Codex Desktop for Windows.
Environment
26.715.2305.0gpt-5.6-sol.codex/agents/*.tomlrole files. The TOML files parse successfully and each role has a non-emptyname,description, role-specific model/reasoning settings, and developer instructions.Actual result
In the affected fresh Desktop task, the collaboration spawn surface is missing entirely. This is not only a missing
agent_typeparameter: neitherspawn_agentnorwait_agentexists in the runtime tool registry.I ran this capability canary:
The task inspected the complete available tool registry. Searching it for
/spawn_agent|wait_agent/returned:Therefore:
spawn_agentcall event was emitted;wait_agentcould not be called;This differs from reports where
spawn_agentis present but only exposestask_name,message, andfork_turns. In this Windows Desktop case, the whole direct collaboration tool family is absent.Reproduction
.codex/agents/.spawn_agentfor a configured role usingfork_turns="none", then callwait_agent.I repeated this with fresh tasks after restarting the app.
Expected result
spawn_agentandwait_agentshould be available in a tool-backed Desktop task when project-local roles are configured.spawn_agentshould exposeagent_typeand apply the selected.codex/agents/*.tomlprofile.PR #33572 is already merged and its commit is included in Codex CLI
0.145.0-alpha.18, but the direct collaboration surface is still absent in this Desktop runtime.I can reproduce a named custom-agent selection gap in the VS Code extension with its bundled stable Codex build.
Environment
openai.chatgpt 26.707.91948codex-cli 0.144.5gpt-5.6-solProject setup
.codex/agents/researcher.tomldefines aresearcheragent with its own model, reasoning effort, read-only sandbox, and developer instructions..codex/agents/reviewer.tomldefines arevieweragent with its own model, reasoning effort, and developer instructions.researcherand independent confirmation toreviewer..codex/config.tomlenables multi-agent support. The researcher and reviewer are intentionally standalone project-agent files.This setup follows the current Subagents documentation, which documents project agents as standalone TOML files under
.codex/agents/and says Codex automatically discovers them. A separate[agents.<name>]registration is not documented as required for these project-scoped files.Reproduction
> Diagnostic only. Delegate to the researcher reading
package.jsonand reporting the package name. Then delegate to the reviewer independently confirming that result. Wait for both agents and report which agent types were used.spawn_agentinterface and the resulting child task metadata.Actual behavior
The exposed
spawn_agentschema accepts only:There is no
agent_type, custom-agent identifier, model, or reasoning-effort parameter.The run created generic canonical task names such as
/root/researcher_package_nameand/root/reviewer_package_name. The parent later clarified that these were generic child agents prompted to act as researcher and reviewer, not verified invocations of.codex/agents/researcher.tomland.codex/agents/reviewer.toml.The available runtime metadata therefore did not establish that either child's configured model, reasoning effort, sandbox, or developer instructions had been applied. This report does not claim that those effective child settings were captured; the problem is that the configured role could neither be explicitly selected through the exposed tool schema nor verified afterward.
Expected behavior
.codex/agents/*.tomlare discovered as documented.spawn_agentcan explicitly select a named custom agent.This appears related to the MultiAgentV2/tool-schema behavior discussed in #31097.
PR #33572 also appears relevant because it adds
agent_typewhen configured roles are available. It was merged after stable0.144.5. I have not tested a VS Code extension build containing that change, so I cannot confirm whether it fixes standalone project-agent discovery and selection in the extension.