Skip to content

[Bug]: Session import turns every Codex subagent into its own top-level thread #16222

Description

@alcxyz

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. In a project, run Codex threads that spawn subagents (spawn_agent). Running them through T3 Code is enough.
  2. On another T3 Code server (or a fresh base dir) that shares the same ~/.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 (upstream main @ 9e5229b), the session_meta branch reads only payload.id and ignores payload.source. Top-level sessions have a string source ("cli", "exec", "vscode", …), so checking source.subagent.thread_spawn there would be enough to skip spawned sessions or link them to parent_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_id above. Its delete-imports command removes any other leftover imports from a stopped server. Both write the same thread.deleted events as T3 Code's own delete, and take a backup first.

Activity

  1. juliusmarminge commented on Oct 5, 2026

    @juliusmarminge
    Member

    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-*.jsonl under ~/.codex/sessions as its own conversation. A spawn_agent child is written as a separate rollout with the same cwd as 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.
    • parseAgentSessionRecords only reads payload.id / payload.session_id from session_meta. TranscriptRecord doesn't declare payload.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: subagent on disk, subAgent in the app-server session schema. Its value isn't only thread_spawn; it also covers review, compact, memory_consolidation, and other.
    • 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 decode payload.source and exclude a rollout when the subagent/subAgent key is present, rather than only when thread_spawn is set.
    • Where the check runs matters. Reporting these as Skipped would bump skippedCount, 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.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 5, 2026
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 is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions