Parallel-first subagents and nonblocking background task management
Summary
This issue collects several related discussions around subagent delegation, background terminal/subagent lifecycle management, and task visibility in the TUI.
We have implemented a working fork, Open Codex CLI, that explores one possible direction:
- more proactive parallel-first subagent planning
- nonblocking background execution for terminals and subagents
- a persistent
Downtask panel for inspecting and managing background work - task-list visibility in the same panel, so plan/task progress is not only visible as a compact status-line counter
Fork: https://github.com/LEON-gittech/codex
The implementation is fork-specific today, but the interaction model may be useful as prior art for upstream Codex.
Related upstream discussions
Subagent planning / delegation
- #21858 - mission-entropy detection and bounded sub-agent delegation
https://github.com/openai/codex/issues/21858
- #16996 - subagent spawn policy conflicts with repo-level workflow instructions
https://github.com/openai/codex/issues/16996
- #16183 - configurable sub-agent spawning limits
https://github.com/openai/codex/issues/16183
These point to a common theme: Codex needs a clearer policy for when to split work into subagents, how aggressive that split should be, and how repo/user instructions should shape the delegation strategy.
Background terminals / nonblocking execution
- #3968 - Background Terminal Sessions
https://github.com/openai/codex/issues/3968
- #17737 - Claude Code-like monitoring for background terminals
https://github.com/openai/codex/issues/17737
- #16935 - view full output of background terminals
https://github.com/openai/codex/issues/16935
- #17821 -
/stop <id>for a single background terminal
https://github.com/openai/codex/issues/17821
- #19197 - orphaned subagents, lifecycle controls, session freezes
https://github.com/openai/codex/issues/19197
These discussions all touch the same interaction problem: long-running terminal or subagent work should remain visible and manageable, but it should not block the main conversation loop.
Design direction explored in Open Codex CLI
1. Parallel-first subagent planning policy
Open Codex currently implements this mostly through the instruction layer rather than a hardcoded scheduler.
The policy asks the main agent to classify non-trivial work by independent axes before editing:
- investigation
- review
- test discovery
- docs/reference comparison
- validation
- implementation
When independent axes exist, the agent is encouraged to spawn read-only subagents first, while keeping final code changes in one implementation lane unless write ownership is clearly disjoint.
This is intentionally more proactive than the default conservative behavior, but still bounded:
- do not duplicate work between main thread and subagents
- do not spawn if the next critical-path step is blocked on the result
- prefer read-only lanes for evidence gathering
- keep implementation centralized unless ownership is cleanly separable
- report what each lane found before finalizing
2. Nonblocking background execution
Open Codex treats long-running terminals and subagents as background work by default.
The goal is to avoid this pattern:
Waiting for background terminal...
Waiting for subagent...
Instead, background work continues independently while the user can keep typing and submitting new messages.
The foreground model turn still shows normal Working state when the model is active, but background terminals/subagents are tracked separately and summarized in the status line.
3. Persistent Down task panel
Open Codex adds a persistent bottom-pane panel opened with Down.
The panel separates:
TasksSubagentsTerminals
It updates in place rather than inserting a chat-stream summary.
For terminals, the detail view shows:
- status
- elapsed runtime
- wrapped command/task metadata
- recent output tail
- stop action when the process is stoppable
For subagents, the detail view shows:
- agent title / nickname
- role
- task prompt
- status
- elapsed runtime
- progress lines when available
4. Plan/task monitoring
In addition to background terminals and subagents, Open Codex also surfaces the latest plan/task list in the same Down panel.
This matters because compact status-line counters are useful, but insufficient when the user wants to inspect:
- what tasks exist
- which tasks completed
- which task is currently active
- what remains pending
So the panel acts as a lightweight task manager for the current session.
Other features in Open Codex CLI
Open Codex also includes several adjacent TUI / workflow improvements:
/effortslash command for changing reasoning effort- query-level
ulw/ultra/xhighmarker support for one-turnxhighreasoning - per-turn reasoning effort visibility in the status line while the turn is running
/export <path>for markdown session export- status-line token throughput visibility
- workspace git diff stats in the status line
- Open Codex-aware npm update prompts
- active memory staging on top of upstream memories
- stale turn output protection in the TUI
- improved user-query highlighting in chat history and composer
More details are in the fork README:
https://github.com/LEON-gittech/codex
Why this may be useful upstream
The core idea is that background work should be first-class TUI state, not a blocking foreground wait state.
A useful upstream design could separate three concepts:
- foreground model activity
The main assistant is currently generating or deciding.
- background task activity
Terminals/subagents are still running, but they should not block input.
- task management UI
Users need a stable place to inspect, switch, stop, and review background work.
This distinction makes the TUI easier to reason about:
Workingmeans the foreground model is active- background work is visible but nonblocking
- users can inspect details through a dedicated panel
- completed work can be surfaced without hijacking the chat stream
Implementation reference
The current implementation is available here:
https://github.com/LEON-gittech/codex
This is not proposed as a direct patch to copy verbatim. It is a working fork implementation that may help evaluate the interaction model and identify which parts would be appropriate for upstream Codex.
10 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Here are some screenshots:
<img width="1237" height="306" alt="Image" src="https://github.com/user-attachments/assets/37e1dfa1-70e7-499e-9d41-78b715ce69bd" />
<img width="1260" height="494" alt="Image" src="https://github.com/user-attachments/assets/d3efb353-eef5-49f6-871c-ae100e87e9ca" />
<img width="933" height="410" alt="Image" src="https://github.com/user-attachments/assets/8700d4fc-b3d3-4e02-a662-f3d7a387fdad" />
<img width="1125" height="308" alt="Image" src="https://github.com/user-attachments/assets/411e73c2-6c8f-44e2-a354-1950636487e2" />
The interaction model makes sense, but I would be careful not to turn parallel-first into an out first and ask questions later. The missing primitive for me is not just a better panel, it is a shared run contract across parent, subagents, and background terminals: ownership, budget slice, last-progress receipt, and terminal halt reason. Once those exist, the Down panel becomes much more useful because it shows why work is still admitted, not only that it exists. We have been hitting the same problem in MartinLoop around coding-agent orchestration.
Parallel-first design gets much safer if each background worker emits a tiny receipt before the parent keeps going: worker id, claimed scope, last verifier result, and terminal stop reason. Otherwise you can make subagents nonblocking and still leave operators blind to whether a worker is making progress or just staying busy in the background.
I read the relevant Open Codex implementation (the fork, not upstream codex) before replying — most of the receipt fields you describe are already there on
CollabAgentState; the gap is the verifier slot. Concretely:spawn_agent(agent_id+nicknamein v1,task_name+nicknamein v2;codex-rs/core/src/tools/handlers/multi_agents_spec.rs:354-401) and surfaced as the cell title in theDownpanel.agent_role,lane,ownership,output_contract,spawn_reason,phaseride onCollabAgentState(codex-rs/app-server-protocol/src/protocol/v2/item.rs:1014-1034) and are merged into per-thread metadata on every update (codex-rs/tui/src/chatwidget/background_agents.rs:76-99). The instruction layer that asks the parent to name a consumer decision and output contract before spawning lives indocs/parallel-first-agent-execution.md(Subagent Prompt Requirements section).CollabAgentStatusdistinguishesCompleted / Interrupted / Errored / Shutdown / NotFound, andnotify_collab_agent_background_completionemits an info line"{title} {status_verb}. {summary}"into the chat the moment a worker leaves the live set (background_agents.rs:192-234). The parent is not blocked on it, but the receipt lands in the main lane, not just buried in the panel.state.messageis the latest progress line and shows up in theDown-panel subagent detail view alongside status + elapsed runtime; cells update in place rather than re-inserting into the stream (background_agents.rs:101-150).Where I agree the model is still weak: there is no structured last verifier result field. Today the implicit verifier is whatever the subagent puts into its final
message, gated only by the human-readableoutput_contractstring. A small protocol addition — e.g.CollabAgentState.last_verification: { kind, passed, summary }populated by an explicitreport_verificationtool — would give the parent a typed receipt to gate the consumer decision on, instead of having to parse the free-form summary. Theparallel-firstdoc already names "validation/test runner" as a lane role, so this slots in without expanding the policy surface.Happy to prototype that in the fork if it sounds useful.
Agreed on the "fan out first, ask later" risk — that's why the policy doc leads with explicit caps, not just hints: 0 for trivial, 1 for one bounded evidence lane, 2–3 for multi-axis tasks, 4–6 only for broad audits (
docs/parallel-first-agent-execution.md, "How Many Subagents to Spawn"). The spawn tool itself takes amax_concurrent_threads_per_sessionknob that gets injected into the model's tool description so the cap is part of the contract, not a silent ceiling (codex-rs/core/src/tools/handlers/multi_agents_spec.rs:33,710-716). And the four pre-spawn gates — Independent / Consumer decision / Bounded / Worth it — are required to pass before aspawn_agentis justified (same file,SPAWN_AGENT_CONTRACT_GUIDANCE_V2).On the shared run contract, the local mapping is:
CollabAgentState.ownership(string-typed, e.g. write boundary), plumbed through to theDownpanel detail view.state.messageupdated live + status transition events (background_agents.rs:101-150).CollabAgentStatusenum —Completed / Interrupted / Errored / Shutdown / NotFound— and a chat-stream info line emitted at the transition so the parent lane sees the halt without polling (background_agents.rs:192-234).tokens_used/token_budgetintools/handlers/goal.rs), but no per-subagent budget slice carved out of the parent and reconciled on close. So the panel can tell you a worker is still admitted, but not that its budget is still admitted.So I think your framing is right: the receipt fields exist, the admission story doesn't — once each lane carries
{spawn_reason, output_contract, budget_slice, last_progress_at}and the panel renders the first three plus a "stale" badge driven by the fourth, "still admitted" becomes a property of the worker, not a UI inference. Curious what MartinLoop landed on for budget reconciliation across parent ↔ child threads — that's the part that gets ugly when a child re-spawns.Budget reconciliation got much saner for us once respawn stopped mutating the original slice.
A practical shape is to give every child run its own
{budget_slice_id, parent_budget_id}plusadmitted_tokens,spent_tokens,verifier_state,halt_reason, andhandoff_to. If child A re-spawns child B, A closes with something likehalt_reason=delegated_followup, and only A's committed spend rolls up. The parent can then admit the next step off(remaining_parent_budget, active_child_slices, last_verifier_delta)instead of a blob of descendant spend.That boundary is what kept retries cheaper for us: stalled children could be cut cleanly without poisoning the whole parent budget or hiding where the spend actually went.
This seems like the right place to separate background task exists from admission to run again. If you can keep the parent goal visible while subagents are running, users can make a real choice about whether to keep waiting, stop, or fork. That would make me much more likely to trust parallel-first behavior in a long session.
The line that stands out is the distinction between foreground work and background work. That split is what keeps long-running subagents useful instead of noisy. I would make stop_reason and next_attempt_allowed visible at the task level too, so the operator can tell whether the loop actually moved.
One extra guardrail I would want before parallel-first is a typed
next_attempt_allowedplushalt_reasonon each child, so the parent can decide whether to keep waiting, re-dispatch, or stop without reading tea leaves from a spinner. That keeps background work nonblocking while preventing the "looks busy / actually wedged" failure mode.