Documentation
¶
Overview ¶
Package subagents provides foreground and background subagent spawning for task delegation. A subagent is a fully independent agent loop with its own LLM client, tool registry, and message history. It inherits the parent's config, persona, grimoire, and permissions but runs in isolation. Subagents may run in the foreground (blocking) or transition to background after a configurable threshold (#30), delivering their result via a channel.
Index ¶
- Variables
- func MergeWorktree(repo string, wt *Worktree) error
- func RemoveWorktree(repo string, wt *Worktree) error
- type DAGEntry
- type Mailbox
- type Manager
- func (m *Manager) GetRun(id string) (*SubagentRun, bool)
- func (m *Manager) Kill(selector string) bool
- func (m *Manager) ListRuns() []*SubagentRun
- func (m *Manager) Resume(ctx context.Context, checkpointID string, turnCb TurnCallback) (*SubagentRun, error)
- func (m *Manager) Spawn(ctx context.Context, goal string, workspace string, turnCb ...TurnCallback) (*SubagentRun, error)
- func (m *Manager) SpawnAsync(ctx context.Context, goal, workspace string, opts SpawnOptions) (<-chan *SubagentRun, *SubagentRun)
- func (m *Manager) SpawnWithOptions(ctx context.Context, goal string, workspace string, opts SpawnOptions) (*SubagentRun, error)
- type Message
- type PostMessageTool
- func (t *PostMessageTool) Description() string
- func (t *PostMessageTool) Execute(_ context.Context, input map[string]any, _ chan<- tools.ProgressEvent) (tools.ToolResult, error)
- func (t *PostMessageTool) InterruptBehavior() tools.InterruptBehavior
- func (t *PostMessageTool) IsConcurrencySafe(input map[string]any) bool
- func (t *PostMessageTool) IsReadOnly() bool
- func (t *PostMessageTool) Name() string
- func (t *PostMessageTool) Parameters() json.RawMessage
- func (t *PostMessageTool) ValidateInput(input map[string]any) error
- type SpawnAgentTool
- func (t *SpawnAgentTool) Description() string
- func (t *SpawnAgentTool) Execute(ctx context.Context, input map[string]any, progress chan<- tools.ProgressEvent) (tools.ToolResult, error)
- func (t *SpawnAgentTool) InterruptBehavior() tools.InterruptBehavior
- func (t *SpawnAgentTool) IsConcurrencySafe(input map[string]any) bool
- func (t *SpawnAgentTool) IsReadOnly() bool
- func (t *SpawnAgentTool) Name() string
- func (t *SpawnAgentTool) Parameters() json.RawMessage
- func (t *SpawnAgentTool) ValidateInput(input map[string]any) error
- type SpawnOptions
- type SubagentRun
- type TurnCallback
- type Worktree
Constants ¶
This section is empty.
Variables ¶
var StaggerDelay = 500 * time.Millisecond
StaggerDelay is the configurable pause between concurrent subagent launches to avoid hitting provider rate limits. Zero means no delay. Default 500ms — safe for xAI's grok-build-0.1 at 6 concurrent agents.
Functions ¶
func MergeWorktree ¶ added in v1.10.0
MergeWorktree merges the worktree's branch back into the repo's current branch. Returns an error on conflict so the caller can surface it.
func RemoveWorktree ¶ added in v1.10.0
RemoveWorktree force-removes the worktree dir and deletes its branch.
Types ¶
type DAGEntry ¶ added in v1.10.0
type DAGEntry struct {
Run *SubagentRun
Goal string // the full goal including persona overrides
Workspace string
TurnCb TurnCallback
MaxTurns int
IsolateWorktree bool
ResultCh chan *SubagentRun // result sent here when complete
}
DAGEntry is a queued subagent waiting for dependencies to clear.
type Mailbox ¶ added in v1.10.0
type Mailbox struct {
// contains filtered or unexported fields
}
Mailbox is a concurrency-safe per-address message store keyed by an agent's address (its element name). Drain is destructive.
func NewMailbox ¶ added in v1.10.0
func NewMailbox() *Mailbox
NewMailbox creates a new empty Mailbox.
type Manager ¶
type Manager struct {
// OnBackgroundComplete is an optional callback invoked when a backgrounded
// subagent finishes. The TUI may set this to surface a completion notice.
// It is called from a goroutine; implementations must be goroutine-safe.
// nil = no notification (default; non-TUI callers are unaffected).
OnBackgroundComplete func(*SubagentRun)
// contains filtered or unexported fields
}
Manager handles subagent lifecycle and execution.
func NewManager ¶
NewManager creates a subagent manager. Pass isChild=true when the manager itself is running inside a subagent to block recursive spawning.
func (*Manager) GetRun ¶
func (m *Manager) GetRun(id string) (*SubagentRun, bool)
GetRun returns a subagent run by ID.
func (*Manager) Kill ¶ added in v1.10.0
Kill cancels a specific in-flight subagent (task 6ffb5a7c). The selector may be the run id, the task id, OR the element/display name the user sees in /agents (e.g. "mizu" or "water") — users refer to agents by the name on screen, not the internal id (#d15ac448). Returns true if a cancellable run was found. The run's context is cancelled (which the runtime honors — task 349f1f14) and its status is marked failed so ListRuns reflects the kill immediately. A run that has already finished is left untouched and returns false.
func (*Manager) ListRuns ¶
func (m *Manager) ListRuns() []*SubagentRun
ListRuns returns all subagent runs, most recent first.
func (*Manager) Resume ¶ added in v1.10.0
func (m *Manager) Resume(ctx context.Context, checkpointID string, turnCb TurnCallback) (*SubagentRun, error)
Resume continues a previously-failed subagent from its last checkpoint. checkpointID is the RunID returned by RunGoal and stored in SubagentRun.CheckpointID. It constructs a runner with the same options as executeSubagent so the resumed run shares the same workspace, turn limits, and callback wiring.
func (*Manager) Spawn ¶
func (m *Manager) Spawn(ctx context.Context, goal string, workspace string, turnCb ...TurnCallback) (*SubagentRun, error)
Spawn creates and runs a subagent with the given goal. It blocks until the subagent completes or the context is cancelled.
func (*Manager) SpawnAsync ¶ added in v1.10.0
func (m *Manager) SpawnAsync(ctx context.Context, goal, workspace string, opts SpawnOptions) (<-chan *SubagentRun, *SubagentRun)
SpawnAsync starts a subagent in a goroutine and returns a buffered channel that receives the final *SubagentRun when it completes, plus the live run handle (status "running"). The channel has capacity 1 so the exec goroutine never blocks or leaks if the caller abandons the channel. The caller may wait on the channel or ignore it (e.g., after transitioning to background).
SpawnAsync does NOT handle DAG dependencies; use SpawnWithOptions for that.
func (*Manager) SpawnWithOptions ¶ added in v1.10.0
func (m *Manager) SpawnWithOptions(ctx context.Context, goal string, workspace string, opts SpawnOptions) (*SubagentRun, error)
SpawnWithOptions creates and runs a subagent with full options including DAG dependencies. If depends_on contains task IDs that haven't completed yet, the subagent blocks in "waiting" state until all dependencies clear, then auto-starts.
When opts.BackgroundAfter > 0, the call blocks up to that duration waiting for the subagent to finish. If the subagent is still running at the threshold, it transitions to "background" status and SpawnWithOptions returns the live (background) run immediately so the parent can resume. The result is later delivered via a goroutine that updates the run state and invokes m.OnBackgroundComplete (if set).
Default behavior (BackgroundAfter == 0) is unchanged: fully blocking.
type PostMessageTool ¶ added in v1.10.0
type PostMessageTool struct {
// contains filtered or unexported fields
}
PostMessageTool is a built-in tool that allows a subagent to post a message to another subagent's mailbox. The recipient is identified by its element name (e.g. "fire", "water"). Messages are delivered at spawn time when the recipient agent next starts (spawn-time injection; live mid-run injection is a follow-up, see issue #31).
func NewPostMessageTool ¶ added in v1.10.0
func NewPostMessageTool(manager *Manager, from string) *PostMessageTool
NewPostMessageTool creates a post_message tool backed by the given manager. from should be the element name of the agent that holds this tool instance, or "parent" when the tool is held by the top-level orchestrator.
func (*PostMessageTool) Description ¶ added in v1.10.0
func (t *PostMessageTool) Description() string
func (*PostMessageTool) Execute ¶ added in v1.10.0
func (t *PostMessageTool) Execute(_ context.Context, input map[string]any, _ chan<- tools.ProgressEvent) (tools.ToolResult, error)
func (*PostMessageTool) InterruptBehavior ¶ added in v1.10.0
func (t *PostMessageTool) InterruptBehavior() tools.InterruptBehavior
func (*PostMessageTool) IsConcurrencySafe ¶ added in v1.10.0
func (t *PostMessageTool) IsConcurrencySafe(input map[string]any) bool
func (*PostMessageTool) IsReadOnly ¶ added in v1.10.0
func (t *PostMessageTool) IsReadOnly() bool
func (*PostMessageTool) Name ¶ added in v1.10.0
func (t *PostMessageTool) Name() string
func (*PostMessageTool) Parameters ¶ added in v1.10.0
func (t *PostMessageTool) Parameters() json.RawMessage
func (*PostMessageTool) ValidateInput ¶ added in v1.10.0
func (t *PostMessageTool) ValidateInput(input map[string]any) error
type SpawnAgentTool ¶
type SpawnAgentTool struct {
// contains filtered or unexported fields
}
SpawnAgentTool is a built-in tool that allows the model to spawn subagents for task delegation. The subagent runs in the foreground (blocks until complete) and returns its final result.
func NewSpawnAgentTool ¶
func NewSpawnAgentTool(manager *Manager) *SpawnAgentTool
NewSpawnAgentTool creates a new spawn_agent tool backed by the given manager.
func (*SpawnAgentTool) Description ¶
func (t *SpawnAgentTool) Description() string
func (*SpawnAgentTool) Execute ¶
func (t *SpawnAgentTool) Execute(ctx context.Context, input map[string]any, progress chan<- tools.ProgressEvent) (tools.ToolResult, error)
func (*SpawnAgentTool) InterruptBehavior ¶
func (t *SpawnAgentTool) InterruptBehavior() tools.InterruptBehavior
func (*SpawnAgentTool) IsConcurrencySafe ¶
func (t *SpawnAgentTool) IsConcurrencySafe(input map[string]any) bool
func (*SpawnAgentTool) IsReadOnly ¶
func (t *SpawnAgentTool) IsReadOnly() bool
func (*SpawnAgentTool) Name ¶
func (t *SpawnAgentTool) Name() string
func (*SpawnAgentTool) Parameters ¶
func (t *SpawnAgentTool) Parameters() json.RawMessage
func (*SpawnAgentTool) ValidateInput ¶
func (t *SpawnAgentTool) ValidateInput(input map[string]any) error
type SpawnOptions ¶ added in v1.10.0
type SpawnOptions struct {
TaskID string // user-assigned task ID for DAG references
DependsOn []string // task IDs that must complete before this starts
TurnCb TurnCallback // nested progress callback
MaxTurns int // 0 = default (20)
IsolateWorktree bool // run this subagent in its own git worktree (#32)
BackgroundAfter time.Duration // >0: auto-transition to background if the subagent runs longer than this (#30). 0 = always foreground (unchanged).
}
SpawnOptions holds optional parameters for Spawn.
type SubagentRun ¶
type SubagentRun struct {
ID string `json:"id"`
TaskID string `json:"task_id,omitempty"` // user-assigned ID for DAG dependencies
Name string `json:"name"` // display name (e.g., "火 hi")
Element string `json:"element"` // english element (e.g., "fire")
Goal string `json:"goal"`
Workspace string `json:"workspace"`
Status string `json:"status"` // "waiting", "running", "background", "completed", "failed"
DependsOn []string `json:"depends_on,omitempty"` // task_ids that must complete first
Result string `json:"result"`
Error string `json:"error,omitempty"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at,omitempty"`
Turns int `json:"turns"`
CheckpointID string `json:"checkpoint_id,omitempty"` // run id to resume from on failure
}
SubagentRun tracks the state and result of a spawned subagent.
type TurnCallback ¶ added in v1.10.0
TurnCallback is called on each subagent turn so the parent can display nested progress. turn is 1-indexed, toolName is the tool being called on this turn (empty if the turn is a text response).
type Worktree ¶ added in v1.10.0
Worktree is an isolated git worktree for a subagent.
func AddWorktree ¶ added in v1.10.0
AddWorktree creates a worktree for `name` on a new branch under <repo>/.celeste/worktrees/<name>.