Older resumed Codex Desktop threads can miss newly available tools and may stay on legacy subagent runtime
I asked Codex to create this issue, hence the verbose and tech-dense tone. Intent is to capture as much of the info as I could about the issues I experienced today with sub-threads and (going back weeks) sub-agents. I wonder now if my existing sub-agent issues are related to the below problem.
Why this matters beyond a technical puzzle: I was under the impression new features were broken or the agent wasn't able to plan/stage them well. But performance was better in fresh threads that (so far today ) aren't exhibiting sub-agent nor the sub-thread handling tools.
I'll let codex take it from here:
---
What version of the Codex App are you using (From “About Codex” dialog)?
Codex Desktop, current app build as of 2026-06-03. I do not want to overstate the exact About-dialog version here; the most useful repro anchors are the session IDs below.
What subscription do you have?
ChatGPT Pro ($100).
What platform is your computer?
macOS / Darwin on Apple Silicon.
What issue are you seeing?
Older resumed Codex Desktop threads appear able to miss newer tool surfaces after the Codex app/runtime is updated.
In a newer/current thread, tool_search can discover thread-management tools such as create_thread, list_threads, send_message_to_thread, set_thread_pinned, set_thread_archived, and set_thread_title. Calling create_thread from that newer thread succeeds.
In an older thread, the same class of tool discovery failed: create_thread was not available, and tool_search returned no thread-management tool. This made the older thread report that it could not create a separate review thread.
This looks like more than a one-off missing tool. It appears that older resumed threads may remain pinned to the tool/runtime metadata that existed when the thread was created, rather than refreshing to the current Codex app tool surface.
There is also a related suspicion around subagents: older threads may be negatively affected as Codex updates the multi-agent/subagent runtime. Current/newer threads can use the newer subagent tool surface, but older resumed/forked threads may fall back to legacy multi-agent behavior.
What steps can reproduce the bug?
Known session anchors:
- Current/newer session where thread tools were discoverable and
create_threadworked:019e8a4c-6f76-7fc3-9a21-ec5e722c1b9c - Older session with the aforementioned missing thread-management tools issue:
019e4748-30f8-7622-af3f-bdb6b4997771
Observed flow:
- Open/resume an older Codex Desktop thread that was created before recent thread-management/dynamic-tool features were available.
- Ask it to create or use a separate review/background thread.
- The thread reports that
create_threadis unavailable and thattool_searchreturned no thread-management tool. - Open/use a newer thread in the same app/account context.
- Ask it to search for thread-management tools.
tool_searchexposes thecodex_appthread-management tools.- Calling
create_threadsucceeds.
Control result from the newer/current thread:
tool_searchreturned thread-management tools.create_threadcreated a background test thread successfully.spawn_agentalso worked in the newer/current thread, which suggests the app is globally capable of these tools and the issue is likely per-thread/runtime state rather than a global account/app outage.
What is the expected behavior?
Older resumed threads should not silently lose or miss newer Codex Desktop tool capabilities after the app/runtime is updated.
One of these behaviors would be reasonable:
- On
thread/resume, refresh safe host-owned dynamic tools to the current app surface when the saved thread metadata predates those tools. - Provide a clear “continue/fork with current tools” path for legacy threads.
- Show an explicit warning when a thread is pinned to a legacy tool/runtime surface.
- For subagents, avoid silently falling back to an older multi-agent runtime unless that is required for correctness, and make the fallback visible.
Additional information
I searched existing openai/codex issues for related terms before filing and did not find a direct duplicate. Searches included terms around dynamicTools, tool_search, create_thread, thread-management tools, resumed/older threads, subagents, and multi-agent V1/V2 behavior.
Technical details from source inspection
I inspected current openai/codex source at commit:
e7039f98449d0e39687aab14eda4b4383b3bce31
Dynamic/thread-management tools appear thread-start scoped
thread/start accepts dynamicTools, validates them, and passes them into the new thread/session:
codex-rs/app-server-protocol/src/protocol/v2/thread.rsThreadStartParams.dynamic_tools- https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/app-server-protocol/src/protocol/v2/thread.rs#L154-L156
codex-rs/app-server/src/request_processors/thread_processor.rs- validates/maps
dynamic_toolsand passes them tostart_thread_with_options - https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/app-server/src/request_processors/thread_processor.rs#L1052-L1088
On session spawn, dynamic tools are restored from the resumed conversation history if no fresh dynamic tools are supplied:
// Dynamic tools are defined at thread start and persisted in rollout session metadata.
let dynamic_tools = if dynamic_tools.is_empty() {
conversation_history.get_dynamic_tools().unwrap_or_default()
} else {
dynamic_tools
};
Source:
InitialHistory::get_dynamic_tools() only reads SessionMeta.dynamic_tools from resumed/forked history:
The public app-server docs also describe dynamicTools as a thread/start API and say deferred dynamic tools become searchable through tool_search:
I did not see equivalent dynamicTools fields on thread/resume or thread/fork. That suggests older threads whose saved SessionMeta predates newer dynamic tools may resume with an empty/stale dynamic-tool set.
Subagent suspicion: explicit legacy multi-agent fallback for older resumed/forked threads
The subagent issue may be the same class of problem, though it is mediated through multi_agent_version rather than dynamicTools.
resolve_multi_agent_version() explicitly keeps resumed/forked threads without runtime metadata on legacy V1:
conversation_history
.get_multi_agent_version()
.or(inherited_multi_agent_version)
.or(match conversation_history {
InitialHistory::New | InitialHistory::Cleared => None,
// Threads created before runtime metadata existed keep the legacy V1 tool surface.
InitialHistory::Resumed(_) | InitialHistory::Forked(_) => Some(MultiAgentVersion::V1),
})
Source:
The lookup for saved multi-agent runtime comes from SessionMeta.multi_agent_version or prior turn context metadata:
- https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/protocol/src/protocol.rs#L2453-L2462
- https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/protocol/src/protocol.rs#L2735-L2757
The planner then selects different visible/callable subagent tool families for V1 vs V2:
- V2: direct tools such as
spawn_agent,send_message,followup_task,wait_agent,close_agent,list_agents - V1: legacy/namespaced tools under
multi_agent_v1, includingspawn_agent,send_input,resume_agent,wait_agent,close_agent
Relevant source:
- https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/core/src/tools/spec_plan.rs#L675-L760
- https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/core/src/tools/handlers/multi_agents_spec.rs#L48-L111
Existing tests appear to encode this behavior:
- legacy resumed/forked history defaults to
MultiAgentVersion::V1 - https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/core/src/session/tests.rs#L1653-L1717
- V1 and V2 select different agent tool families; V1 tools may be deferred behind
tool_search - https://github.com/openai/codex/blob/e7039f98449d0e39687aab14eda4b4383b3bce31/codex-rs/core/src/tools/spec_plan_tests.rs#L941-L1070
This may be intentional for compatibility, but it creates a confusing user-facing behavior: old threads can appear to have broken or missing subagent capabilities after the app has moved on to the V2 runtime.
Why this is worth addressing
The current behavior is difficult for users and agents to diagnose. A capable current thread can use tools successfully, while an older thread in the same app/account says the tools do not exist. That makes it look like a transient tool registry failure rather than a legacy-thread capability surface.
A small UX/protocol improvement would help a lot:
- refresh safe host-owned tools on resume when missing,
- add an explicit upgrade/fork-with-current-tools path,
- or expose a clear legacy capability warning in the thread context/tool instructions.
Even if the legacy fallback is required for correctness, surfacing it would prevent agents from making incorrect claims like “the create_thread tool is not available in this session” when the more precise statement is “this resumed legacy thread did not receive the current host-owned thread-management tools.”
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗