Skip to content

feat(subagents): stable color assignment for spawned agents#282

Merged
emal-avala merged 1 commit into
mainfrom
feat/subagent-color-manager
May 5, 2026
Merged

feat(subagents): stable color assignment for spawned agents#282
emal-avala merged 1 commit into
mainfrom
feat/subagent-color-manager

Conversation

@emal-avala
Copy link
Copy Markdown
Member

Summary

Slice of Phase 8.10 (subagent color manager piece). Spawned subagents now receive a stable, distinct color across the session — visible in /tasks and propagated to the child via env vars for downstream renderers.

  • New services::subagent_colors module: SubagentColor (8 stable slots) and SubagentColorManager (deterministic insertion-order assignment, idempotent per id, wraps after the eighth).
  • AppState owns one shared Arc<SubagentColorManager>; ToolContext and TaskContext plumb it through.
  • AgentTool resolves a stable subagent id (input field or uuid), assigns a color, propagates AGENT_CODE_SUBAGENT_ID and AGENT_CODE_SUBAGENT_COLOR to the child.
  • LocalAgentExecutor pre-assigns a color, registers a LocalAgent queue entry stamped with it (new TaskManager::register_with_color), and drives the entry to a terminal status when the run finishes.
  • /tasks rendering colorizes LocalAgent descriptions through the new subagent_theme_color bridge in ui::theme. Shell-task rows stay plain.

/tasks display

After spawning four subagents in a single session the table looks roughly like:

Background tasks (5):

  a1   LocalAgent       3s  running   audit-security      <- red
  a2   LocalAgent      12s  running   refactor-parser     <- blue
  a3   LocalAgent       1s  running   add-tests           <- green
  a4   LocalAgent      45s  completed write-docs          <- yellow
  b5   LocalShell       8s  running   echo plain          <- uncolored

Use TaskOutput to read output; TaskStop to cancel a running task.

Each agent's description is painted with its assigned subagent_* slot from the active theme (the comments on the right are illustrative — there's no extra column). Shell tasks keep the plain rendering they have today.

Out of scope (deferred follow-ups)

  • Fork and Resume pieces of 8.10 — not touched here.
  • Coordinator memory snapshot piece of 8.10 — not touched here.
  • Turn-summary panel colorization in tui::render_turn_summary — needs the subagent id plumbed through ToolEntry / tool-call events. Invasive enough that I shipped the manager + /tasks integration without it; flagging for a follow-up.

Test plan

  • cargo check --all-targets
  • cargo clippy --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • cargo test --tests — all new tests green; the only pre-existing failures are bwrap_* sandbox tests that need real user namespaces in the runner (unrelated to this change).
  • Unit tests for the manager: 8 distinct ids → 8 distinct colors in declaration order, 9th wraps to red, reassigning an id returns the same color, for_id returns None for unknown ids, concurrent assignment yields 8 distinct slots, Send + Sync compile-time check.
  • Unit test for subagent_theme_color: every variant maps to its matching subagent_* slot across every advertised theme.
  • Integration test: assign two subagent ids, register both as LocalAgent queue entries with their colors, confirm format_task_list surfaces both rows.

Slice of Phase 8.10 (color manager piece). Each spawned subagent
now gets one of eight stable color slots (red, blue, green, yellow,
purple, orange, pink, cyan) for the duration of the session, mapped
through the per-theme `subagent_*` slots PR #275 added.

- New `services::subagent_colors` module with `SubagentColor` enum
  and `SubagentColorManager`. Assignment is deterministic
  (insertion-order counter, not hashmap iteration), idempotent per
  id, and wraps after the eighth subagent.
- `AppState` carries a shared manager; `ToolContext` and
  `TaskContext` plumb it through so the Agent tool and
  `LocalAgentExecutor` see the same allocation table.
- `AgentTool` resolves a stable subagent id (input field or fresh
  uuid), assigns a color, and propagates both to the child via
  `AGENT_CODE_SUBAGENT_ID` / `AGENT_CODE_SUBAGENT_COLOR`.
- `LocalAgentExecutor` registers a `LocalAgent` task entry stamped
  with the assigned color (new `TaskManager::register_with_color`)
  so `/tasks` shows the run with its color.
- `format_task_list` paints the description with the matching
  `subagent_*` theme slot via the new `subagent_theme_color`
  bridge in `ui::theme`.
- Tests: manager unit tests (8-distinct, wrap, idempotent, for_id
  None, Send+Sync, concurrent), theme-bridge round-trip across
  every advertised theme, `/tasks` colorization, and a manager↔
  task-manager integration test.

Fork/resume and the coordinator memory snapshot pieces of 8.10 are
out of scope for this PR.
@emal-avala emal-avala merged commit 09e7980 into main May 5, 2026
14 checks passed
@emal-avala emal-avala deleted the feat/subagent-color-manager branch May 5, 2026 04:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant