Skip to main content

Subagents System

The subagents system enables task delegation to specialized agents, allowing Qwen Code to handle complex, multi-step tasks autonomously through parallel execution and specialized expertise.

Overview

Subagents are lightweight, single-use AI agents that:
  • Execute tasks autonomously with their own tool access
  • Run in parallel for improved performance
  • Have specialized system prompts and configurations
  • Communicate through events for real-time UI updates
  • Are stateless and terminate after completing their task

Architecture

Core Components

SubagentManager

├── Subagent Configuration (Markdown + YAML)
│   ├── name: string
│   ├── description: string
│   ├── tools: string[]
│   ├── systemPrompt: string
│   └── modelConfig: {...}

├── SubAgentScope (Runtime)
│   ├── GeminiChat
│   ├── ToolRegistry (subset)
│   ├── ContextState
│   └── Event Emitter

└── TaskTool (Interface)
    └── Delegates to subagents

Configuration Storage

Subagents are configured as Markdown files with YAML frontmatter: File Format:
---
name: code-reviewer
description: Reviews code for quality, security, and best practices
tools:
  - read_file
  - grep_search
  - glob
modelConfig:
  model: qwen-coder-plus
  temperature: 0.3
runConfig:
  max_turns: 10
  max_time_minutes: 5
color: blue
---

# Code Review Agent

You are a code review specialist. Your task is to:

1. Analyze code for quality and maintainability
2. Identify security vulnerabilities
3. Check for best practices compliance
4. Suggest improvements

Be thorough but concise in your feedback.

Storage Hierarchy

Subagents are stored at different levels with priority:
  1. Session Level (highest priority)
    • Provided at runtime
    • Read-only
    • Use: Temporary, specialized agents for specific sessions
  2. Project Level
    • Location: .qwen/agents/ in project directory
    • Use: Project-specific agents
  3. User Level
    • Location: ~/.qwen/agents/ in home directory
    • Use: Personal agents across all projects
  4. Extension Level
    • Provided by installed extensions
    • Read-only
  5. Built-in Level (lowest priority)
    • Embedded in codebase
    • Always available

Creating Subagents

Using the SubagentManager

import { SubagentManager } from '@qwen-code/qwen-code-core';

const manager = new SubagentManager(config);

const subagentConfig = {
  name: 'test-runner',
  description: 'Runs tests and analyzes results',
  tools: ['run_shell_command', 'read_file', 'grep_search'],
  systemPrompt: `
    You are a test execution specialist.
    
    Your responsibilities:
    1. Run the test suite
    2. Analyze failures
    3. Provide clear summaries
    4. Suggest fixes when possible
  `,
  modelConfig: {
    model: 'qwen-coder-plus',
    temperature: 0.2,
  },
  runConfig: {
    max_turns: 15,
    max_time_minutes: 10,
  },
};

await manager.createSubagent(subagentConfig, {
  level: 'project',  // or 'user'
  overwrite: false,
});

Via Command Line

Users can create subagents using the /agents command:
# In Qwen Code CLI
/agents create test-runner
This opens an interactive wizard to configure the subagent.

Manual File Creation

Create a Markdown file in the appropriate directory:
# Project-level agent
.qwen/agents/my-agent.md

# User-level agent
~/.qwen/agents/my-agent.md

Configuration Options

Required Fields

name: string           # Unique identifier
description: string    # When and how to use this agent
tools: string[]       # Array of tool names
systemPrompt: string  # Agent's instructions

Optional Fields

modelConfig:
  model: string              # Model name (default: uses main config)
  temperature: number        # 0.0-2.0 (default: 1.0)
  topP: number              # 0.0-1.0 (default: 0.95)

runConfig:
  max_turns: number         # Max conversation turns (default: 20)
  max_time_minutes: number  # Max execution time (default: 30)
  terminate_mode: string    # 'graceful' or 'immediate'

color: string               # Display color in UI

Tool Configuration

Available Tools:
  • File system: read_file, write_file, edit, glob, grep_search, list_directory
  • Shell: run_shell_command
  • Memory: save_memory
  • Task: task (for nested delegation)
  • Web: web_fetch, web_search
  • LSP: lsp_* tools
  • MCP: Dynamically loaded MCP tools
Example Tool Configuration:
tools:
  - read_file
  - edit
  - run_shell_command
  - grep_search
If tools is omitted, the subagent inherits all available tools.

Runtime Execution

Executing a Subagent

Subagents are invoked through the task tool:
// Model uses task tool
task({
  description: 'Code review',
  prompt: 'Review the authentication module for security issues',
  subagent_type: 'code-reviewer',
});

Execution Flow

  1. Initialization:
    • Load subagent configuration
    • Create SubAgentScope instance
    • Initialize tool registry with allowed tools
    • Set up event emitter
  2. Context Setup:
    • Apply system prompt with variable substitution
    • Set initial chat history
    • Configure model parameters
  3. Execution Loop:
    • Send prompt to model
    • Process tool calls
    • Handle confirmations (if needed)
    • Execute tools
    • Send results back to model
    • Repeat until completion or limits
  4. Termination:
    • Model returns final text response
    • Emit finish event
    • Clean up resources
    • Return result to parent agent

Event-Driven Updates

Subagents emit events for real-time UI updates:
// Event types
export enum SubAgentEventType {
  START = 'start',
  ROUND = 'round',
  TOOL_CALL = 'tool_call',
  TOOL_RESULT = 'tool_result',
  APPROVAL_REQUEST = 'approval_request',
  FINISH = 'finish',
  ERROR = 'error',
  USAGE = 'usage',
}

// Example event listener
const emitter = new SubAgentEventEmitter();

emitter.on(SubAgentEventType.START, (event: SubAgentStartEvent) => {
  console.log(`Subagent ${event.name} started`);
});

emitter.on(SubAgentEventType.TOOL_CALL, (event: SubAgentToolCallEvent) => {
  console.log(`Calling tool: ${event.tool.name}`);
});

emitter.on(SubAgentEventType.FINISH, (event: SubAgentFinishEvent) => {
  console.log(`Subagent finished: ${event.result}`);
});

Context State and Templating

Subagents support variable substitution in system prompts:
// Define context
const context = new ContextState();
context.set('project_name', 'my-app');
context.set('language', 'TypeScript');

// System prompt with variables
const systemPrompt = `
You are working on the ${project_name} project.
This is a ${language} codebase.

Your task: ...
`;

// Variables are replaced at runtime:
// "You are working on the my-app project."
// "This is a TypeScript codebase."

Parallel Execution

Multiple subagents can run simultaneously:
// Launch multiple tasks in parallel
await Promise.all([
  task({
    description: 'Code review',
    prompt: 'Review the auth module',
    subagent_type: 'code-reviewer',
  }),
  task({
    description: 'Run tests',
    prompt: 'Execute the test suite',
    subagent_type: 'test-runner',
  }),
  task({
    description: 'Update docs',
    prompt: 'Generate API documentation',
    subagent_type: 'documentation-writer',
  }),
]);
The Task tool supports parallel execution when multiple tool calls are made in a single model response.

Statistics and Telemetry

Subagents track execution statistics:
export interface SubagentStatsSummary {
  totalDurationMs: number;
  rounds: number;
  totalToolCalls: number;
  successfulToolCalls: number;
  failedToolCalls: number;
  inputTokens?: number;
  outputTokens?: number;
  totalTokens?: number;
  estimatedCost?: number;
}
Statistics are logged for analytics (respecting privacy settings):
logSubagentExecution(
  config,
  new SubagentExecutionEvent(
    subagentName,
    stats.totalDurationMs,
    stats.rounds,
    stats.totalToolCalls,
    outcome,
  ),
);

Best Practices

Design Guidelines

  1. Single Responsibility: Each subagent should have a clear, focused purpose
  2. Minimal Tools: Only grant access to necessary tools
  3. Clear Instructions: Write detailed, unambiguous system prompts
  4. Appropriate Limits: Set reasonable time and turn limits
  5. Error Handling: Account for failures in parent agent logic

System Prompt Tips

# Good System Prompt Structure

## Role
You are a [specific role] specialist.

## Responsibilities
1. [Specific task 1]
2. [Specific task 2]
3. [Specific task 3]

## Guidelines
- [Important guideline 1]
- [Important guideline 2]

## Output Format
Provide your response in this format:
[Expected format description]

Tool Selection

Read-only Tools (always safe):
  • read_file
  • grep_search
  • glob
  • list_directory
Modifying Tools (require careful consideration):
  • write_file
  • edit
  • run_shell_command
Delegation Tools (for complex tasks):
  • task (enable nested delegation)

Built-in Subagents

Qwen Code includes built-in subagents:

General Purpose Agent

name: general-purpose
description: Handles complex multi-step tasks with full tool access
tools: [all tools]

Code Search Agent

name: code-search
description: Specialized in finding code and patterns across the codebase
tools:
  - read_file
  - grep_search
  - glob
  - list_directory
See packages/core/src/subagents/builtin-agents.ts for all built-in agents.

Validation

Subagent configurations are validated on:
  • Creation
  • Loading
  • Execution
Validation Rules:
  1. Name must be valid (alphanumeric, hyphens, underscores)
  2. Description must not be empty
  3. System prompt must not be empty
  4. Tools must exist in the tool registry
  5. Model config must be valid
  6. Run config must have reasonable limits

Error Handling

export enum SubagentErrorCode {
  NOT_FOUND = 'NOT_FOUND',
  ALREADY_EXISTS = 'ALREADY_EXISTS',
  INVALID_CONFIG = 'INVALID_CONFIG',
  FILE_ERROR = 'FILE_ERROR',
  EXECUTION_ERROR = 'EXECUTION_ERROR',
  TIMEOUT = 'TIMEOUT',
  MAX_TURNS_EXCEEDED = 'MAX_TURNS_EXCEEDED',
}

export class SubagentError extends Error {
  constructor(
    message: string,
    public code: SubagentErrorCode,
    public subagentName?: string,
  ) {
    super(message);
    this.name = 'SubagentError';
  }
}

Testing Subagents

Test subagent configurations before deployment:
import { describe, it, expect } from 'vitest';
import { SubagentManager } from '@qwen-code/qwen-code-core';

describe('MySubagent', () => {
  it('should validate configuration', async () => {
    const config = {
      name: 'my-agent',
      description: 'Test agent',
      tools: ['read_file'],
      systemPrompt: 'Test prompt',
    };

    const manager = new SubagentManager(mockConfig);
    await expect(
      manager.createSubagent(config, { level: 'user' }),
    ).resolves.not.toThrow();
  });

  it('should execute successfully', async () => {
    // Test execution logic
  });
});

Next Steps