Skip to content

Let a conversation coordinate child conversations #2105

Open

Description

@sentry-junior

Master tracker for letting any Junior conversation split work into child conversations, follow their state, and keep handling new input while they run. It consolidates the subagent runtime (#883), the coding workflow (#1998), and the coordinator and child steering that neither of them covers yet.

Current state

Direction

Proposed by David Cramer; details are still open.

  • Native to every thread. Any conversation can act as a coordinator. There is no separate Project record. The thread's plan, Brief, annotated PRs and issues, and child conversations are its persistent artifacts.
  • The coordinator doesn't implement. It keeps work aligned, handles what people say, and keeps the plan or tracking issue up to date. Children do the work.
  • No per-project memory. Children start from a task built from the parent's state. Lasting rules about a repo stay in AGENTS.md.
  • Coding mode is a consumer, not the foundation. Plan-first coding mode for complex feature work #1998 adds phase gates (plan → confirm → implement → verify → PR) on top of this. Generic reactive behavior stays independent (see Plan-first coding mode for complex feature work #1998, point 6).
  • Spaces ([Feature] Spaces: an append-only landscape of Sentry's work inside Junior #1784) becomes the scope above a single thread when one effort spans several threads.

Decided in the Oct 15 design thread (scope: canvas, behavior spec and eval cases: canvas):

  • The main agent talks to the user and manages the work; children do the work. Most work goes to a child, but most messages don't: quick questions are answered in place, even while children run. Modeled on Claude Code Projects and Claude Tag.
  • No mode switch. Per message, the main agent answers in place, sends to an existing child, or starts a new one. A new child is for a separate piece of work with its own output, long-running work, or independent tracks (one child per track). The plan → confirm gate in Plan-first coding mode for complex feature work #1998 is the one explicit state.
  • Starting N children is a normal turn with one reply. Each result is its own turn, where the main agent replies only if the user needs to know and otherwise ends with [[NO_REPLY]].
  • The parent chooses each child's profile.
  • Children never post to Slack. Only the main agent writes memory; children read it and may suggest memories in their result.
  • The parent checks work by asking the child for evidence (PR, CI, tests run), spot-checks it read-only, and starts a fresh verifier child for high-stakes changes.
  • An agent-written claim of approval never counts. The user's real message has to reach the child through the runtime, so the user isn't asked twice. A child started by an automation gets the automation's saved instruction as its authority, labeled as coming from the automation and its creator, never more than the run that started it (matches how Codex and Claude Code children inherit the parent run's approval policy).

Workstreams

Subagent runtime (#883)

Steering (no issue yet)

  • Coordinator: on each incoming message, decide whether to answer in place, send it to an existing child, or start a new one; propose children before starting the first batch
  • Child: a fixed report back to the parent (done with outcome/PR, or reportBlocked naming what's missing), with no guessing or mocking around missing access. A question that does not block goes to the parent with messageAgent, and the child keeps working. There is no separate needs_input result. (feat(subagents): Let a child agent report that it is blocked #2133, feat(subagents): Add messageAgent and drop spawnAgent name reuse #2135)
  • Rewrite the conversation prompt for coordination (subagents are always on, so there is no gate): a <coordination> section, result-turn rules, and rewrites of task-execution, skill-policy, handoff, "name changed paths" and planning. Update the spawnAgent description and result text, and add coordination.eval.ts scoring both over- and under-delegation
  • Child contract: name every artifact with evidence, never end a task with a question (seen in practice: a child returned "May I clone…?" as a completed result), and no Slack posts or memory writes. Briefs say scratch work in the child's sandbox is fine and name remote side effects explicitly
  • Audit skills: which ones the main agent uses to route work and which ones children load

Status and direct steering

Agent coordination tools
Refined direction. It replaces the earlier sendMessage / presence proposal. Design: canvas. First slice: #2135. Terms follow TERMINOLOGY.md. Parents and children get the same four tools.

  • spawnAgent only starts new children. A name that is already used fails and points to messageAgent. Name reuse is gone. (feat(subagents): Add messageAgent and drop spawnAgent name reuse #2135)
  • messageAgent(to, text) sends an agent message to "parent" or to a direct child, by name or conversation_id. (feat(subagents): Add messageAgent and drop spawnAgent name reuse #2135)
    • Parent → child: the message starts a new agent invocation on the child, and the child keeps its history. An idle or stopped child starts now. A busy child runs the message after that work (delivery: "queued") and one result covers both.
    • Child → parent: the message is a junior/agent.message Event. It uses the same mailbox and Actor path as child results. It is not from a person, so it gives no user approval. The sender keeps working, and its result still arrives later.
    • Done: a running target reads the message at the next step boundary, as a steering message from an agent. A running tool is never interrupted. (feat(subagents): Let a running child read parent messages #2139)
    • Next: siblings, and any id inside the conversation's agent tree. Messaging other Slack threads stays out of scope until it is clear which Actor sends and who can see the message.
  • listAgents replaces "active" with two fields that come from agent invocation records, not from a stored flag:
  • stopAgent stops a child and every child below it (exists). A stopped child keeps its name, and messageAgent starts new work on it. This replaces the earlier idea that a stopped target refuses the message. (feat(subagents): Stop child agents with stopAgent #2114, feat(subagents): Add messageAgent and drop spawnAgent name reuse #2135, fix(subagents): Run child watch events as agent invocations #2134)
  • Rules:
    • When a child finishes, its result always goes to its parent, whoever woke it. The parent–child link decides which work is tracked, not the tool that sent it.
    • Nothing waits or polls. There is no wait_agent. An agent ends its Turn, and a result or an agent message wakes it again.
    • A message never carries history, files or credentials. The receiver acts with its own Actor and credentials. An agent never asks another agent to do something that it was denied itself.
  • Limits: messages up to 8,000 characters, at most 4 open agent invocations per child, an active-child cap that counts children (not queued messages), and an idempotency key from the tool call. All of these are in feat(subagents): Add messageAgent and drop spawnAgent name reuse #2135. Next: rate limits per sender and dropping identical repeats.
  • Later: idle notices for agents other than the parent, as a new watchEvents resource type, not a new tool. A shared task list, as the coordinator's updatePlan with items that an agent can own. One-line message previews in the dashboard and Slack. User → child messages through the same path (see Status and direct steering).

Coding workflow

Runtime follow-ups

  • Approval provenance (security, draft PR #2147): parent-written task and message text is agent-sourced and never counts as approval. The runtime forwards forwardedInstructions to the child: user records carry the person's actual messages from the triggering turn, and automation records carry a scheduled or event automation's saved instruction, labeled as coming from that automation and its creator, never from a person. Grandchildren inherit them. When approval is missing, the child calls reportBlocked naming the action, and the user's reply is forwarded as a verified record. Child results, watch events and plugin dispatch forward nothing. Also fixes the ask-confirmation retry restarting a child that already ended with reportBlocked. Real pause and resume for children stays in Add subagent context, lifecycle controls, and execution limits #881
  • Remove the experimental subagents flag; keep disabledFeatures: ["subagents"] for depth limits and test opt-outs. Decide on a kill switch for the first release
  • Hide createMemory and archiveMemory in child runs (fix(memory): Hide memory write tools in child agent runs #2145)
  • Pass parent context to children (<context>, <configuration>, location config, a thread summary): the first slice of Add subagent context, lifecycle controls, and execution limits #881
  • Auth recovery: when a child blocks on missing credentials, the parent runs the normal OAuth flow, then uses messageAgent to tell the child to retry
  • Automations with children: an automation run ends with finishAutomationRun, so confirm later result turns can still post or finish its result
  • Router signal: a conversation with live children stays on the strong profile, so "yes, go" isn't handled on standard
  • Pass a system Actor's delegated credential subject to the result Turn (currently dropped, per agent-invocations/README.md)
  • Deliver child results in junior chat. It enables subagents but has no parent mailbox, so results never arrive locally.
  • Eval fixture: completedToolCalls and Conversation only cover the root, and about 24 eval files assert tool calls there. Add a helper that collects calls and replies across the agent tree through /:conversationId/agents, move outcome assertions onto it, and re-record (about 1–2 days)
  • Coverage beyond the evals in subagents.eval.ts (now: success, blocked, stop, nested): failed results, parallel children up to the cap, messageAgent to a busy child and child → parent messages, results from different Actors

Tracking cleanup

Prior art

via David Cramer.

--

View Junior Session [Sentry]

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions