ollie/prompts/tools-subagent.md

4.8 KiB

subagent_generate & subagent_spawn

Spawn independent subagent sessions with JIT-generated identities via echo JSON | subagent_generate | xargs subagent_spawn.

Trigger condition: a task decomposes into independent subtasks each requiring multi-step reasoning or multiple tool calls; you are processing N items with the same operation; or the current agent's identity would work against the quality of a subtask — delegate to an agent whose identity is aligned with it.

Calling convention:

pipe: stages=[
  {tool: "subagent_generate", args: [{"role": "ROLE", "shared_task": "TASK_DESC"}]},
  {tool: "subagent_spawn", args: ["-name", "NAME", "TASK"]}
]

Parallel — issue separate pipe calls for each subagent (subagent_spawn returns immediately, so sequential dispatch is fine):

pipe: stages=[
  {tool: "subagent_generate", args: [{"role": "ROLE_A", "roster": "a (you), b", "shared_task": "X"}]},
  {tool: "subagent_spawn", args: ["-name", "a", "TASK_A"]}
]
pipe: stages=[
  {tool: "subagent_generate", args: [{"role": "ROLE_B", "roster": "a, b (you)", "shared_task": "X"}]},
  {tool: "subagent_spawn", args: ["-name", "b", "TASK_B"]}
]

Returns: subagent_generate returns the agent config name. subagent_spawn returns the session path (e.g. s/my-session).

subagent_generate

No stdin prints the template. With JSON on stdin, creates a JIT agent config inheriting hooks and tooling from default.json with a clean prompt (SYSTEM_PROMPT + identity only).

Field Required Description
name no Config name (default: jit-<hex>)
role yes* Who this agent is and what it does
roster no Complete name → task mapping of all peers, (you) marking this agent
shared_task no Beads issue ID or tracking entry
protocol no Coordination mechanics: lead, decision path, triggers, prompt file targets
constraints no Array of constraint strings
prompt yes* Legacy: complete identity as a single string

*One of role or prompt is required. Prefer role with structured fields.

When role is provided, the fields are assembled into a markdown identity envelope:

## Role
<role>

## Roster
<roster>

## Shared Task
<shared_task>

## Coordination Protocol
<protocol>

## Constraints
- <constraint 1>
- <constraint 2>

The prompt field is a legacy fallback — use it only when the structured fields don't fit.

subagent_spawn

Flag Default Description
-name NAME auto Session name
-agent A server default Agent config name (from subagent_generate)
-backend B server default Backend override
-model M server default Model override
-cwd DIR pwd Working directory

Remaining args: the task prompt (immediate task only — coordination lives in the identity).

subagent_spawn auto-injects context headers into the prompt:

  • [parent_session_id=...] — the parent's session ID
  • [session_id=...] — the child's own session ID
  • [parent_plan_start]...[parent_plan_end] — the parent's current plan file contents (if non-empty)

Constraints:

  • Prefer the pipeline. Use subagent_generate → subagent_spawn when the subagent needs a custom identity. For simple delegation with no identity requirements, subagent_spawn alone with -agent or server defaults is fine.
  • Identity carries coordination, prompt carries task. Roster, shared task, and protocol go in the identity. The seed prompt is purely the task.
  • Subagents do not share memory. Pass context explicitly in the seed prompt.
  • Peers are known at spawn time. Assign -name to each and include the full roster in each identity.
  • Names must be globally unique under s/. Duplicate names fail silently.

Returning results to the parent

Subagents signal completion by writing directly to s/{parent_session_id}/prompt. This delivers the result as the parent's next queued turn — no polling, no blocking, no active waiting.

Critical: The parent must NEVER actively wait for subagent results. No statewait, no polling loops, no blocking reads. After spawning, the parent either continues its own work or ends its turn. When a child writes to the parent's prompt, the message queues and drains automatically when the parent next idles. This avoids wasting expensive coordinator tokens on idle waiting and eliminates coordination deadlocks.

The result written to the parent's prompt should be compact and unambiguous. Use this format:

[from={session_id}]
STATUS: done|blocked|partial
SUMMARY: <what was accomplished, one short paragraph>
ARTIFACTS: <newline-separated filesystem paths written, omit if none>
OPEN: <unresolved items, omit if none>

The [from=...] header is essential when multiple subagents report to the same parent — it lets the parent correlate results to tasks without having to infer identity from content.