From b33a411427191d21759325c06b3b3405f02ece55 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Sun, 26 Apr 2026 20:34:27 +0200 Subject: [PATCH] subagent: add -name flag, document roster convention subagent_spawn now passes -name through to b, letting the parent assign predictable session IDs. Updated coordination docs: parent passes full peer roster in seeding prompts, names prefixed with parent session ID for global uniqueness. Noted silent failure on duplicate names. --- prompts/tools-subagent.md | 33 ++++++++++++++++++++------------- tools/subagent_spawn | 3 ++- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/prompts/tools-subagent.md b/prompts/tools-subagent.md index 5e56b19..61190fd 100644 --- a/prompts/tools-subagent.md +++ b/prompts/tools-subagent.md @@ -14,6 +14,7 @@ execute_code: steps=[{tool: "subagent_spawn", args: ["-n", "N", "-agent", "A", " | Flag | Default | Description | |---|---|---| | `-n N` | 1 | Number of parallel subagents, all receiving the same prompt (homogeneous fan-out) | +| `-name NAME` | auto | Session name; predictable IDs let you build a roster before agents start | | `-agent A` | server default | Agent config name | | `-backend B` | server default | Backend override | | `-model M` | server default | Model override | @@ -53,10 +54,13 @@ general mandate. entry tracking the overall work. This is the one field the parent must always provide. -**Peers** can be discovered by convention. All sessions live under `s/` and -are named by session ID. Subagents spawned with `-n N` have predictable IDs. -Rather than listing exact peers, describe how to discover them — e.g., "other -subagents working in `$CWD`" — and let the child query `s/` if needed. +**Peers** are known at spawn time. The parent creates the full roster and +assigns `-name` to each subagent, so every peer ID is known before any agent +starts. Pass the complete roster (name → task mapping) in each seeding prompt +so agents can communicate directly without discovery. Names must be globally +unique (they become directories under `s/`); prefix with the parent session ID +to avoid collisions — e.g. `-name ${OLLIE_SESSION_ID}-impl`. Note: duplicate +session names fail silently due to 9P client limitations. **Rendezvous** is implicit. Every session has a `prompt` file at `s/{sid}/prompt`. Writing to another session's prompt file always works: @@ -74,21 +78,24 @@ fork-join; the prompt-based completion model is the intended direction. **Example coordination prompt**: ``` -You are the test-writer subagent. Spawned by session $PARENT_SESSION_ID. -Shared task: beads issue #42 ("add auth middleware"). -A peer subagent is writing pkg/auth/middleware.go concurrently. -When that file exists, write its tests to pkg/auth/middleware_test.go and run them. -When done, write your result to s/$PARENT_SESSION_ID/prompt. +You are the test-writer subagent (session: ${OLLIE_SESSION_ID}-test-writer). +Parent: $OLLIE_SESSION_ID. Shared task: beads issue #42 ("add auth middleware"). + +Roster: + ${OLLIE_SESSION_ID}-impl — writing pkg/auth/middleware.go + ${OLLIE_SESSION_ID}-test-writer (you) — writing pkg/auth/middleware_test.go + +When impl's file exists, write tests and run them. +When done, write your result to s/$OLLIE_SESSION_ID/prompt. ``` ## Heterogeneous fan-out -To run N subagents with N *different* prompts, use a `{parallel: [...]}` stage. Each entry is an independent `subagent_spawn` call with its own prompt — use this when the subtasks differ: +To run N subagents with N *different* prompts, use a `{parallel: [...]}` stage. Each entry is an independent `subagent_spawn` call with its own prompt and `-name` — use this when the subtasks differ and agents need to know about each other: ``` execute_code: steps=[{parallel: [ - {tool: "subagent_spawn", args: ["Summarize core/pkg/agent/loop.go"]}, - {tool: "subagent_spawn", args: ["Summarize core/pkg/backend/anthropic.go"]}, - {tool: "subagent_spawn", args: ["Summarize 9p/server.go"]} + {tool: "subagent_spawn", args: ["-name", "${OLLIE_SESSION_ID}-impl", "-agent", "coding", "-keep", "You are impl. Parent: $OLLIE_SESSION_ID. Roster: ${OLLIE_SESSION_ID}-impl (you) — write middleware, ${OLLIE_SESSION_ID}-test-writer — write tests. Task: beads #42. Write pkg/auth/middleware.go."]}, + {tool: "subagent_spawn", args: ["-name", "${OLLIE_SESSION_ID}-test-writer", "-agent", "qa", "-keep", "You are test-writer. Parent: $OLLIE_SESSION_ID. Roster: ${OLLIE_SESSION_ID}-impl — write middleware, ${OLLIE_SESSION_ID}-test-writer (you) — write tests. Task: beads #42. When pkg/auth/middleware.go exists, write and run its tests."]} ]}], timeout=300 ``` diff --git a/tools/subagent_spawn b/tools/subagent_spawn index 26c7b9d..b01aef1 100755 --- a/tools/subagent_spawn +++ b/tools/subagent_spawn @@ -1,6 +1,6 @@ #!/usr/bin/env bash # description: Spawn N subagents with a shared prompt, wait for all to complete, return concatenated results (fork-join). -# Args: [-n N] [-agent A] [-backend B] [-model M] [-cwd DIR] [-keep] +# Args: [-n N] [-name NAME] [-agent A] [-backend B] [-model M] [-cwd DIR] [-keep] # Output: concatenated results from all subagents, in submission order. With -n > 1, results are separated by === {id} === headers. set -euo pipefail @@ -13,6 +13,7 @@ n=1; args=() while [ $# -gt 0 ]; do case $1 in -n) n=$2; shift ;; + -name) args+=(-name "$2"); shift ;; -agent) args+=(-agent "$2"); shift ;; -backend) args+=(-backend "$2"); shift ;; -model) args+=(-model "$2"); shift ;;