Repository navigation
[Bug]: Session import turns every Codex subagent into its own top-level thread #16222
Copy link
Copy link
Open
Labels
bugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
Description
Activity
Note
Grok responding on behalf of Julius.
Triage
Thanks for the detailed report and the thread counts, @alcxyz! That made this easy to trace.
What I found
- Codex history import treats every
rollout-*.jsonlunder~/.codex/sessionsas its own conversation. Aspawn_agentchild is written as a separate rollout with the samecwdas its parent, so project discovery counts it and import publishes it as a top-level thread (parentThreadId: null). - The title comes from the first line of the first user message, which on child rollouts is injected setup text (
# AGENTS.md instructions,<recommended_plugins>, and so on), which explains the odd titles. parseAgentSessionRecordsonly readspayload.id/payload.session_idfromsession_meta.TranscriptRecorddoesn't declarepayload.source, and the decode drops unknown fields, so the parent link is lost before the import decision.- Top-level Codex sessions use a string
source(cli,exec,vscode,appServer,unknown) or{custom}. Child rollouts use an object key:subagenton disk,subAgentin the app-server session schema. Its value isn't onlythread_spawn; it also coversreview,compact,memory_consolidation, andother. - This is separate from Bug: Imported Codex tasks use <recommended_plugins> as their titles #10513 (bad titles on real top-level sessions). fix(server): prevent duplicate and subagent history imports #11807 tried to cover both and was closed unmerged, so the subagent exclusion never landed. fix(server): skip imports of native agent sessions #10950 and fix(server): skip native sessions during bulk import #15634 only skip sessions T3 already owns.
Likely fix area
AgentSessionScanner.ts/parseAgentSessionRecords: one option is to decodepayload.sourceand exclude a rollout when thesubagent/subAgentkey is present, rather than only whenthread_spawnis set.- Where the check runs matters. Reporting these as
Skippedwould bumpskippedCount, which onboarding shows as "could not be imported" and which keeps the project out of the fully-imported set. Returning null from the parser may also be too late, since each file is reserved against the 100-transcript import budget before parsing, so child rollouts could crowd out real sessions. - The same check likely belongs in the project-candidate transcript count, since child rollouts share the parent's
cwd. - For comparison, Claude import also doesn't attach subagents to a parent thread (it drops sidechain/meta records), so linking Codex children into their parent during import would be a separate change. A fix here wouldn't remove threads that were already imported.
A maintainer will decide on the fix direction.
- Codex history import treats every
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 5, 2026
Metadata
Metadata
Assignees
Labels
bugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
Before submitting
Area
apps/server
Steps to reproduce
spawn_agent). Running them through T3 Code is enough.~/.codex, add the same project and import its recent sessions.Expected behavior
Only the conversations the user had are imported. Subagent sessions are skipped, or attached to their parent thread the way Claude subagents already are.
Actual behavior
Every Codex subagent session becomes its own top-level
import:codex:<id>thread. Codex stores each subagent as a separate rollout, and the scanner treats every rollout as a conversation. The titles come from injected setup text, not a user prompt, so the sidebar fills with threads named# AGENTS.md instructions,<recommended_plugins>or<thread_title_updates>…. On one server this produced 119 subagent threads next to 53 real ones.Codex records the parent in the first line of each child rollout:
{"type":"session_meta","payload":{"id":"<child>","source":{"subagent":{"thread_spawn":{"parent_thread_id":"<parent>","depth":1,"agent_path":"/root/…"}}},…}}In
apps/server/src/project/AgentSessionScanner.ts(upstreammain@ 9e5229b), thesession_metabranch reads onlypayload.idand ignorespayload.source. Top-level sessions have a stringsource("cli","exec","vscode", …), so checkingsource.subagent.thread_spawnthere would be enough to skip spawned sessions or link them toparent_thread_id.Impact
Minor bug or occasional failure
Version or commit
Seen on a nightly build (0.0.46-nightly.20261004); the scanner code is unchanged on
main@ 9e5229b.Environment
Linux, Codex CLI 0.160.0, two T3 Code servers on one host sharing
~/.codex.Workaround
Delete the imported subagent threads one by one in the UI. For many of them: I hit this while moving projects between two T3 Code servers on the same host, and wrote t3rry for those moves. As part of a move it soft-deletes imports of the moved threads' sessions and of the subagents they spawned, using the
parent_thread_idabove. Itsdelete-importscommand removes any other leftover imports from a stopped server. Both write the samethread.deletedevents as T3 Code's own delete, and take a backup first.