Skip to content

Subagents

Eshan Roy edited this page Jun 16, 2026 · 3 revisions

Subagents

M31 Autonomous (M31A) supports parallel subagents that run in isolated git worktrees. Subagents allow the LLM to spawn child agents for independent tasks, each with their own dispatcher and working directory.

Overview

Parent Agent (main TUI session)
    │
    ├── Subagent 1 (isolated worktree, own dispatcher)
    ├── Subagent 2 (isolated worktree, own dispatcher)
    └── Subagent 3 (isolated worktree, own dispatcher)

Each subagent:

  • Gets its own git worktree (created via git worktree add)
  • Gets its own tool dispatcher (with independent permissions)
  • Runs in a background goroutine
  • Reports results via an event channel

Architecture

Manager

Source: internal/tools/subagent/manager.go

type Dependencies struct {
    WorkDir        string
    Registry       *provider.Registry
    ActiveModel    *types.ModelInfo
    Logger         *slog.Logger
    Worktrees      WorktreeProvider
    NewDispatcher  DispatcherFactory
}

The Manager:

  • Tracks active subagents by ID
  • Provides Spawn() to create new subagents
  • Provides Cancel() and Shutdown() for cleanup
  • Exposes an Events() channel for TUI integration

Agent Loop

Source: internal/tools/subagent/loop.go

Each subagent runs its own agent loop:

  1. Builds system prompt and tool definitions
  2. Sends messages to the LLM
  3. Parses tool calls from the response
  4. Executes tools via its own dispatcher
  5. Feeds results back to the LLM
  6. Repeats until the task is complete or context is exhausted

Loop Parser

Source: internal/tools/subagent/loop_parse.go

Parses LLM responses for tool calls, handling both native tool_call chunks and text-embedded tool invocations.

Git Worktree Isolation

Source: internal/tools/subagent/worktree.go

Each subagent gets an isolated working directory:

git worktree add .m31a/worktrees/agent-<id> -b m31a/agent-<id>

Benefits:

  • File edits don't conflict between parallel agents
  • Each agent can commit independently
  • Cleanup on completion: git worktree remove + branch deletion

Stale Worktree Sweep

On startup, Sweep() removes leftover worktrees and branches from previous crashes:

  • Removes orphaned .m31a/worktrees/ directories
  • Cleans up m31a/agent-* branches

Event System

Source: internal/tools/subagent/events.go

Subagent events are streamed to the TUI:

Event Description
SubagentStartedMsg Agent spawned with ID and description
SubagentProgressMsg Intermediate output from the agent
SubagentCompleteMsg Agent finished with result or error
SubagentToolCallMsg Tool invocation within a subagent

The TUI listens via subagentListenerCmd() and renders events as toast notifications or sidebar entries.

The Agent Tool

Source: internal/tools/agent.go

The Agent tool is registered on the parent dispatcher, allowing the LLM to spawn subagents:

{
    "name": "Agent",
    "description": "Spawn a parallel subagent...",
    "params": {
        "description": "Short task description",
        "prompt": "Detailed instructions for the subagent"
    }
}

Reentrancy Prevention

Child agents are created with isChild=true, which prevents them from spawning grandchildren in background. This avoids runaway recursion.

Slash Commands

Command Description
/agent [desc]: [prompt] Spawn a new subagent
/agent List active subagents
/agent-cancel <id|all> Cancel a running subagent

TUI Integration

Source: internal/tui/subagents_model.go, internal/tui/subagent_bridge.go

The TUI maintains a SubagentsModel that:

  • Lists active subagents with status
  • Shows progress and results
  • Provides cancel functionality
  • Integrates with the sidebar for status display

Clone this wiki locally