Summary
mecatui has no visibility into subagent / Task activity. This is the largest remaining gap from the mecatui UX review (it mirrors the loudest emergent 2026 community ask — the "agent hierarchy dashboard" pattern). mecatl spawns subagents two ways and both are a black box in the TUI today:
- The
Task tool (internal/agent/subagent.go) runs a fresh read-only agent in an isolated context and, by design, drains the child's entire event stream inside Execute (drainChild) — discarding every turn.start / tool.call / tool.result / message.delta and folding back only the final summary string. The user sees a single Task tool card spin on … then resolve. No goal, no progress, no per-child tokens, no elapsed.
- Agent teams (
internal/team/, internal/adapter/server/team.go, the RunTeam stream in harness.proto) drive N long-lived member sessions. Here the data already exists: RunTeam streams a TeamEvent{member, Event} per member. But the TUI has no concept of a member, so N interleaved streams would collapse into one unreadable scrollback.
Design principle: one model, 1→N
The TUI renders purely from streamed events. So the design reduces to: give every event a parent/member identity, route by identity, render an Agents panel keyed by identity. A single Task subagent is the N=1 case of a team roster. Reuse three existing idioms: the MCP overlay pattern (opt-in, esc-dismissable, ctrl+* to open), the ctrl+t expand toggle, and the Tier-A context meter (▒▓█░ per-band glyph bar) for per-agent context %. The single-agent conversation view stays untouched; subagent activity never pollutes the main scrollback unless the user opts in.
1. Single Task subagent — inline card (MVP)
Keep the existing blockTool card as the anchor; while unresolved, show a live sub-status line fed by new lightweight events.
Collapsed (default):
… Task "audit auth middleware for missing checks"
⟳ subagent · Grep · 8.2s · ↑3.1K ↓410 · 3 tools · ctrl+t details
Expanded (ctrl+t) — a capped, opt-in trace of the child's tool calls (the only place the child's interior is shown; tool names/status only, never child message text):
… Task "audit auth middleware for missing checks"
subagent subagent-call_7f3 · running · 8.2s · ↑3.1K ↓410
✓ Grep "func.*Handler" internal/http 12 matches
✓ Read internal/http/mw.go 1–80
⟳ Grep "ValidateToken"
… child trace capped at 12 calls · ctrl+t collapse
On completion the card resolves as today (summary string → resultBody), with a terminal stat line:
✓ Task "audit auth middleware for missing checks"
subagent done · 14.6s · ↑5.2K ↓820 · 6 tools · 0 writes
Found 2 handlers that call the DB before ValidateToken… (summary)
This MVP needs no new panel/key — just intermediate events and one status line on the existing card.
2. Multi-agent — the Agents panel (ctrl+a)
A new overlay styled like the MCP inventory panel. Each row is one identity (lead at the root, members beneath): state · current activity · tokens · context meter.
┌─ agents · team-3kf9 · 4 members · round 6 ──────────────────────┐
│ │
│ ◆ lead working delegating │
│ ↑12K ↓2.1K · ctx ▓▓▓▓▒░░░ 58% · 92K/200K │
│ │
│ ├─ ◆ scout working Grep "ValidateToken" 6.1s │
│ │ ↑8.4K ↓900 · ctx ▒▒▒░░░░░ 31% · 62K/200K │
│ │ │
│ ├─ ◆ patcher working Edit internal/http/mw.go 2.3s │
│ │ ↑31K ↓7.2K · ctx █████▓▓░ 88% ⚠ · 176K/200K │
│ │ │
│ └─ ○ scribe idle awaiting message │
│ ↑2.1K ↓310 · ctx ▒░░░░░░░ 9% · 18K/200K │
│ │
│ tasks 5 done · 1 in-progress · 2 pending(blocked) │
│ ↑/↓ select · enter focus member · t tasks · esc close │
└──────────────────────────────────────────────────────────────────┘
◆ working/spawning, ○ idle, dim ✓ stopped — glyph-encoded state (colourblind-safe, survives ANSI stripping), mirroring the context-meter glyph-not-colour rule.
patcher at 88% ⚠ reuses the context meter's existing danger mark — directly answering "which agents are near their context limit."
- Tree connectors express parent→member; the lead sits at the root (it is a
team.Member with the Lead flag).
enter focuses a member → its tagged events render in the main viewport (a per-member filter over the buffered TeamEvent stream), so one agent's transcript is readable without the N-way interleave. esc returns.
t flips to the shared task list (ListTeam already returns team.Task: id · state · assignee · deps).
- A footer summary advertises activity without forcing the panel open:
⟳ team-3kf9 · 3/4 working · ctrl+a agents.
Auto-open policy: do not auto-open (it steals the keyboard, like the idle-only MCP overlay). Surface the footer summary when a team is live; ctrl+a opens the panel. The single-Task case never opens a panel — its inline card is enough.
3. Data / events the harness must emit
| Surface |
Today |
Needed |
| Team members |
RunTeam already streams TeamEvent{member, Event}; TeamMember{name, agent_type, state} and TeamTask exist. |
TUI client consumes the RunTeam stream and routes by member into per-identity render state. The session Event already carries usage/turn_end (tokens). Gap: per-member context-window size isn't on TeamMember — add context_used/context_window (or surface the member session's cumulative Usage + model window) so the per-agent meter has a denominator. The member's current tool is derivable client-side from the latest tool.call per member (likely no new field). |
| Task subagent |
subagent.go's drainChild emits nothing intermediate — the parent sees one tool.result. |
Add minimal child-progress events the parent forwards instead of discarding, carrying parent_call_id + child session_id: subagent.start{goal, child_id}, subagent.tool{child_id, tool_name, ok}, subagent.end{child_id, usage, tool_count, stop}. handleChildEvent is the single chokepoint — it can forward a redacted projection (tool names + usage, not child message text, preserving context-isolation) up to the parent's EventSink. |
Both cases converge on the same client-side shape: (identity, kind, activity, usage, ctx). Team tags by member; Task tags by child session_id. For N=1 (Task) the "roster" is the inline card; for N>1 (team) it's the panel.
4. Open questions & tradeoffs
- Screen real estate — the panel is an overlay (no permanent cost), but the footer summary competes with the context meter on narrow widths; needs a
fitFooter-style tier.
- Nesting depth — teams are flat (lead + members);
Task subagents can't recurse (child catalog excludes Task). A 2-level tree is sufficient today; don't build arbitrary depth.
- Performance —
MaxMembers = 32. Render from a per-member last-event projection (a snapshot), not by replaying buffered events each frame; cap the per-member focus buffer (reuse the maxToolResultLines idiom).
- Child trace verbosity — showing every child
tool.call risks re-bloating what Task exists to keep out of context; mitigate by keeping it opt-in (ctrl+t) + hard-capped + names/status only.
- Event volume —
subagent.tool per child call adds wire traffic; could gate behind a server flag and fall back to start/end-only.
5. Phased plan
- MVP — inline Task visibility. Forward
subagent.start/tool/end from handleChildEvent; render the live sub-status line + terminal stat on the existing Task card. No new panel/key. Biggest win for the smallest change.
- Team consumption + footer summary. Wire
client to the RunTeam stream, route by member, show the ⟳ team · k/N working footer segment.
- Agents panel (
ctrl+a). The roster overlay, modelled on mcp.go, with per-agent state/activity/tokens/context meter.
- Member focus + task sub-view.
enter to filter to one member; t for the shared task list. Add context_used/window to TeamMember if needed.
Key files
- Inline card + events:
internal/agent/subagent.go (handleChildEvent, drainChild), cmd/mecatui/ui/render.go (renderTool).
- Panel reuse:
cmd/mecatui/ui/mcp.go (overlay), cmd/mecatui/ui/footer.go (renderContextMeter/ctxLabel), cmd/mecatui/ui/keys.go.
- Team data:
internal/adapter/server/team.go (RunTeam/ListTeam), TeamEvent/TeamMember/TeamTask in contracts/proto/mecatl/v1/harness.proto.
Drafted from the mecatui UX gap analysis. The interface above is a proposal to spark implementation, not a final spec — the phased plan front-loads the highest-value, lowest-cost step (inline Task visibility).
Summary
mecatui has no visibility into subagent / Task activity. This is the largest remaining gap from the mecatui UX review (it mirrors the loudest emergent 2026 community ask — the "agent hierarchy dashboard" pattern). mecatl spawns subagents two ways and both are a black box in the TUI today:
Tasktool (internal/agent/subagent.go) runs a fresh read-only agent in an isolated context and, by design, drains the child's entire event stream insideExecute(drainChild) — discarding everyturn.start/tool.call/tool.result/message.deltaand folding back only the final summary string. The user sees a singleTasktool card spin on…then resolve. No goal, no progress, no per-child tokens, no elapsed.internal/team/,internal/adapter/server/team.go, theRunTeamstream inharness.proto) drive N long-lived member sessions. Here the data already exists:RunTeamstreams aTeamEvent{member, Event}per member. But the TUI has no concept of a member, so N interleaved streams would collapse into one unreadable scrollback.Design principle: one model, 1→N
The TUI renders purely from streamed events. So the design reduces to: give every event a
parent/memberidentity, route by identity, render an Agents panel keyed by identity. A singleTasksubagent is the N=1 case of a team roster. Reuse three existing idioms: the MCP overlay pattern (opt-in, esc-dismissable,ctrl+*to open), thectrl+texpand toggle, and the Tier-A context meter (▒▓█░per-band glyph bar) for per-agent context %. The single-agent conversation view stays untouched; subagent activity never pollutes the main scrollback unless the user opts in.1. Single
Tasksubagent — inline card (MVP)Keep the existing
blockToolcard as the anchor; while unresolved, show a live sub-status line fed by new lightweight events.Collapsed (default):
Expanded (
ctrl+t) — a capped, opt-in trace of the child's tool calls (the only place the child's interior is shown; tool names/status only, never child message text):On completion the card resolves as today (summary string →
resultBody), with a terminal stat line:This MVP needs no new panel/key — just intermediate events and one status line on the existing card.
2. Multi-agent — the Agents panel (
ctrl+a)A new overlay styled like the MCP inventory panel. Each row is one identity (lead at the root, members beneath): state · current activity · tokens · context meter.
◆working/spawning,○idle, dim✓stopped — glyph-encoded state (colourblind-safe, survives ANSI stripping), mirroring the context-meter glyph-not-colour rule.patcherat 88% ⚠ reuses the context meter's existing danger mark — directly answering "which agents are near their context limit."team.Memberwith theLeadflag).enterfocuses a member → its tagged events render in the main viewport (a per-member filter over the bufferedTeamEventstream), so one agent's transcript is readable without the N-way interleave.escreturns.tflips to the shared task list (ListTeamalready returnsteam.Task: id · state · assignee · deps).⟳ team-3kf9 · 3/4 working · ctrl+a agents.Auto-open policy: do not auto-open (it steals the keyboard, like the idle-only MCP overlay). Surface the footer summary when a team is live;
ctrl+aopens the panel. The single-Taskcase never opens a panel — its inline card is enough.3. Data / events the harness must emit
RunTeamalready streamsTeamEvent{member, Event};TeamMember{name, agent_type, state}andTeamTaskexist.clientconsumes theRunTeamstream and routes bymemberinto per-identity render state. The sessionEventalready carriesusage/turn_end(tokens). Gap: per-member context-window size isn't onTeamMember— addcontext_used/context_window(or surface the member session's cumulativeUsage+ model window) so the per-agent meter has a denominator. The member's current tool is derivable client-side from the latesttool.callper member (likely no new field).subagent.go'sdrainChildemits nothing intermediate — the parent sees onetool.result.parent_call_id+ childsession_id:subagent.start{goal, child_id},subagent.tool{child_id, tool_name, ok},subagent.end{child_id, usage, tool_count, stop}.handleChildEventis the single chokepoint — it can forward a redacted projection (tool names + usage, not child message text, preserving context-isolation) up to the parent'sEventSink.Both cases converge on the same client-side shape:
(identity, kind, activity, usage, ctx). Team tags bymember; Task tags by childsession_id. For N=1 (Task) the "roster" is the inline card; for N>1 (team) it's the panel.4. Open questions & tradeoffs
fitFooter-style tier.Tasksubagents can't recurse (child catalog excludesTask). A 2-level tree is sufficient today; don't build arbitrary depth.MaxMembers = 32. Render from a per-member last-event projection (a snapshot), not by replaying buffered events each frame; cap the per-member focus buffer (reuse themaxToolResultLinesidiom).tool.callrisks re-bloating whatTaskexists to keep out of context; mitigate by keeping it opt-in (ctrl+t) + hard-capped + names/status only.subagent.toolper child call adds wire traffic; could gate behind a server flag and fall back to start/end-only.5. Phased plan
subagent.start/tool/endfromhandleChildEvent; render the live sub-status line + terminal stat on the existingTaskcard. No new panel/key. Biggest win for the smallest change.clientto theRunTeamstream, route bymember, show the⟳ team · k/N workingfooter segment.ctrl+a). The roster overlay, modelled onmcp.go, with per-agent state/activity/tokens/context meter.enterto filter to one member;tfor the shared task list. Addcontext_used/windowtoTeamMemberif needed.Key files
internal/agent/subagent.go(handleChildEvent,drainChild),cmd/mecatui/ui/render.go(renderTool).cmd/mecatui/ui/mcp.go(overlay),cmd/mecatui/ui/footer.go(renderContextMeter/ctxLabel),cmd/mecatui/ui/keys.go.internal/adapter/server/team.go(RunTeam/ListTeam),TeamEvent/TeamMember/TeamTaskincontracts/proto/mecatl/v1/harness.proto.Drafted from the mecatui UX gap analysis. The interface above is a proposal to spark implementation, not a final spec — the phased plan front-loads the highest-value, lowest-cost step (inline Task visibility).