A comprehensive tutorial guide for beginners, summarized from real-world practices.
Table of Contents
- 1. What is Dynamic Workflow
- 2. Quick Overview of Core Concepts
- 3. Directory Structure
- 4. First Workflow: Hello World
- 5. Built-in API Details
- 6. Practice: Math Problem Pipeline
- 7. Defining Agents within Workflows
- 8. ⚠️ Limitations and Pitfalls
- 9. Architecture Comparison
- 10. Summary
1. What is Dynamic Workflow
Dynamic Workflow is a multi-agent orchestration engine introduced in Claude Code v2.1.154+. You write a JavaScript script, and it automatically spawns multiple sub-agents according to your logic, executing tasks in parallel or sequentially, and ultimately aggregating the results.
In short: Use code to control multiple AI agents to collaborate on tasks.
Applicable Scenarios
| Scenario | Example |
|---|---|
| Batch Processing | Solving 8 math problems in parallel |
| Pipeline | Solve → Verify → Score |
| Large-scale Review | Reviewing 100 files in parallel |
| Multi-perspective Analysis | Evaluating the same issue separately from security, performance, and readability perspectives |
2. Quick Overview of Core Concepts
| Concept | Description |
|---|---|
| meta | Script header declaration, defining name, description, and phases |
| agent() | Spawns a sub-agent and returns the result |
| pipeline() | Sequential pipeline: each data item passes through multiple stages in order |
| parallel() | Parallel execution: multiple tasks run simultaneously |
| phase() | Declares the current phase (used for UI progress display) |
| log() | Outputs logs to the user interface |
| args | Parameters passed from the outside |
| budget | Token budget control for the current turn |
Execution Model
mermaid graph TD A[User triggers Workflow] --> B[Parse meta] B --> C{Orchestration logic} C -->|Sequential| D[pipeline: item → stage1 → stage2 → stage3] C -->|Parallel| E[parallel: task1 | task2 | task3 run simultaneously] C -->|Mixed| F[parallel + pipeline nested] D --> G[Aggregate and return results] E --> G F --> G
3. Directory Structure
.claude/
├── workflows/ # Directory for Workflow scripts
│ └── math-problems.js # One workflow = One .js file
├── agents/ # Custom agent definitions (⚠️ cannot be referenced by workflows)
│ ├── math-solver.md # Only used for automatic routing in the main session
│ └── math-verifier.md
└── settings.json # Project configuration
Workflow File Structure
Fixed format for each .js file:
export const meta = {
name: 'my-workflow', // Required: Unique identifier
description: 'Description of purpose', // Required: Description of purpose
phases: [ // Optional: Define phases (for UI display)
{ title: 'Analyze' },
{ title: 'Execute' },
],
}
// ... Your orchestration logic
// Orchestrate using agent() / pipeline() / parallel()
// Finally, return the result
4. First Workflow: Hello World
Minimal Version
export const meta = {
name: 'hello',
description: 'The simplest workflow',
phases: [{ title: 'Greet' }],
}
const result = await agent('Say hello world', { phase: 'Greet' })
return result
Parameterized Version
export const meta = {
name: 'hello-name',
description: 'Greeting',
}
// args are passed from the outside
const name = (args && args.name) || 'World'
const result = await agent(`Say hello to ${name} and introduce yourself`)
return result
⚠️ IMPORTANT: When referencing a workflow by name, args might not be passed! It is recommended to always provide default values or use inline script calls.
5. Built-in API Details
5.1 agent() — Spawn a Sub-agent
// Basic usage
const result = await agent('Your prompt')
// Full parameters
const result = await agent('Your prompt', {
label: 'Display Name', // Label displayed in the UI
phase: 'Solve', // Assigned phase
schema: { // Enforce structured output (JSON Schema)
type: 'object',
properties: {
answer: { type: 'string' },
confidence: { type: 'number' }
}
},
model: 'sonnet', // Optional model override
agentType: 'Explore', // ⚠️ Only supports built-in types, custom types are not supported
})
5.2 pipeline() — Sequential Pipeline
Data passes through each stage sequentially; the output of the previous stage becomes the input for the next stage:
graph LR
A[Data item] -->|stage1| B[Intermediate result 1]
B -->|stage2| C[Intermediate result 2]
C -->|stage3| D[Final result]
style A fill:#e1f5fe
style D fill:#c8e6c9const results = await pipeline(
['Problem 1', 'Problem 2', 'Problem 3'], // Data array
(item) => agent(`Process: ${item}`), // stage 1
(prev, item) => agent(`Review: ${prev}`), // stage 2
)
// results[0] = Result of stage2(Problem 1)
// results[1] = Result of stage2(Problem 2)
// Each data item completes the entire pipeline independently; different items run in parallel
Key Feature: Inside a pipeline, each data item flows independently. Item A might be at stage 3 while item B is still at stage 1. Total time = the slowest single-item chain, not the sum of all stages.
5.3 parallel() — Parallel Barrier
All tasks start simultaneously and return only when all are completed:
graph TD
A[parallel starts] --> B[Task 1]
A --> C[Task 2]
A --> D[Task 3]
B --> E[Aggregate results]
C --> E
D --> E
style A fill:#fff9c4
style E fill:#c8e6c9const results = await parallel([
() => agent('Analyze frontend code'),
() => agent('Analyze backend code'),
() => agent('Analyze database'),
])
// results = [Frontend analysis, Backend analysis, Database analysis]
// Returns null if any fails; filter using .filter(Boolean)
5.4 phase() and log()
phase('Review') // Switch to the Review phase (UI progress bar grouping)
log('Processed 3/10 files') // Output progress information
6. Practice: Math Problem Pipeline
Design Principle: Write problems directly into the prompt. Each group of problems is treated as a whole and passed to the agent via a prompt template, allowing beginners to see the grouping structure and data flow at a glance.
Architecture Diagram
graph TD
subgraph "Problem Grouping (written directly in prompt)"
G1["Group 1 (Basic Math)
12×15, √144+3², 2^10, ..."]
G2["Group 2 (Advanced Math)
Trailing zeros of 100!, sin30°×cos60°, ..."]
end
subgraph "Pipeline (processed as a whole per group)"
S1["🧮 Solve
Entire group of problems in prompt"]
V1["✅ Verify
Problems + solutions in prompt"]
SC1["📊 Score
Problems + verification results in prompt"]
S1 --> V1 --> SC1
end
G1 -->|"prompt contains Group 1 problems"| S1
G2 -->|"prompt contains Group 2 problems"| S1
SC1 --> R["Aggregate results by group"]
style G1 fill:#e3f2fd
style G2 fill:#fce4ec
style S1 fill:#bbdefb
style V1 fill:#c8e6c9
style SC1 fill:#fff9c4
style R fill:#f8bbd0Data Flow Details
Data flow per group (using Group 1 as an example):
┌─────────────────────────────────────────────────┐
│ Stage 1: Solver │
│ prompt = SOLVER_PROMPT + all Group 1 problems │
│ output = detailed solutions for 5 problems │
└──────────────────────┬──────────────────────────┘
│ solution (output from previous stage)
┌──────────────────────▼──────────────────────────┐
│ Stage 2: Verifier │
│ prompt = VERIFIER_PROMPT + Group 1 problems + solution │
│ output = step-by-step verification results (✅/❌) │
└──────────────────────┬──────────────────────────┘
│ verification (output from previous stage)
┌──────────────────────▼──────────────────────────┐
│ Stage 3: Scorer │
│ prompt = SCORER_PROMPT + Group 1 problems + verification │
│ output = score and comments for each problem │
└─────────────────────────────────────────────────┘
Actual Prompt Examples (After Template Replacement)
Below is the complete prompt actually sent to the agent after executing .replace('{problems_block}', ...).
Stage 1 — Prompt received by Solver (Group 1)
You are a math problem-solving expert. Please solve the following math problems one by one.
1. 12 × 15 = ?
2. √144 + 3² = ?
3. 2^10 = ?
4. 1 + 2 + 3 + ... + 100 = ?
5. 1/2 + 1/3 + 1/6 = ?
Output format (per problem):
- Problem: {Original problem}
- Solution process: {Step-by-step derivation}
- Answer: {Final result}
Stage 1 — Prompt received by Solver (Group 2)
You are a math problem-solving expert. Please solve the following math problems one by one.
6. How many trailing zeros are in 100!?
7. sin30° × cos60° = ?
8. log₂1024 = ?
9. The circumference of a circle is 31.4cm, find its area (π≈3.14)
10. Solve the equation: 2x + 5 = 17
Output format (per problem):
- Problem: {Original problem}
- Solution process: {Step-by-step derivation}
- Answer: {Final result}
Stage 2 — Prompt received by Verifier (Group 1, with solutions)
You are a math verification expert. Independently re-solve the problems and compare them with the solutions below.
1. 12 × 15 = ?
2. √144 + 3² = ?
3. 2^10 = ?
4. 1 + 2 + 3 + ... + 100 = ?
5. 1/2 + 1/3 + 1/6 = ?
=== Solutions to Verify ===
[Solver's complete output will be inserted here]
=== Requirements ===
- Calculate independently; do not trust the provided solutions.
- Compare step-by-step and mark as correct or incorrect.
- If there is an error, pinpoint its exact location.
Output format:
- Judgment: ✅ Correct / ❌ Incorrect
- Verification process: {Independent derivation}
- Reason for error: {If any}
Stage 3 — Prompt received by Scorer (Group 1, with verification results)
You are a math scoring expert. Score based on the solutions and verification results.
1. 12 × 15 = ?
2. √144 + 3² = ?
3. 2^10 = ?
4. 1 + 2 + 3 + ... + 100 = ?
5. 1/2 + 1/3 + 1/6 = ?
=== Verification Results ===
[Verifier's complete output will be inserted here]
Scoring: 10=Perfect | 7-9=Correct but improvable | 4-6=Partially correct | 0-3=Incorrect
Output format:
- Score: {0-10}
- Comment: {One sentence}
Key Point:
{problems_block}is replaced by the same group of problems at each stage, while{solution}/{verification}are replaced by the output of the previous stage. Each agent can see the full context and does not need to guess what the problems are.
Complete Code
export const meta = {
name: 'math-problems',
description: 'Math problem workflow — problems written into prompt by group, 3-stage pipeline (Solve→Verify→Score)',
phases: [
{ title: 'Solve', detail: 'Solve problems in parallel per group' },
{ title: 'Verify', detail: 'Independently verify solutions per group' },
{ title: 'Score', detail: 'Comprehensive scoring' },
],
}
// ─── Prompt Templates (Defined at the top for clarity) ──────────────
// {problems_block} → All problems in the group
// {solution} → Solver's output
// {verification} → Verifier's output
const SOLVER_PROMPT = `You are a math problem-solving expert. Please solve the following math problems one by one.
{problems_block}
Output format (per problem):
- Problem: {Original problem}
- Solution process: {Step-by-step derivation}
- Answer: {Final result}`
const VERIFIER_PROMPT = `You are a math verification expert. Independently re-solve the problems and compare them with the solutions below.
{problems_block}
=== Solutions to Verify ===
{solution}
=== Requirements ===
- Calculate independently; do not trust the provided solutions.
- Compare step-by-step and mark as correct or incorrect.
- If there is an error, pinpoint its exact location.
Output format:
- Judgment: ✅ Correct / ❌ Incorrect
- Verification process: {Independent derivation}
- Reason for error: {If any}`
const SCORER_PROMPT = `You are a math scoring expert. Score based on the solutions and verification results.
{problems_block}
=== Verification Results ===
{verification}
Scoring: 10=Perfect | 7-9=Correct but improvable | 4-6=Partially correct | 0-3=Incorrect
Output format:
- Score: {0-10}
- Comment: {One sentence}`
// ─── Problem Grouping (Written directly here, easy for beginners to modify) ──────────
const DEFAULT_GROUPS = [
{
name: 'Group 1 (Basic Math)',
problems: [
'1. 12 × 15 = ?',
'2. √144 + 3² = ?',
'3. 2^10 = ?',
'4. 1 + 2 + 3 + ... + 100 = ?',
'5. 1/2 + 1/3 + 1/6 = ?',
],
},
{
name: 'Group 2 (Advanced Math)',
problems: [
'6. How many trailing zeros are in 100!?',
'7. sin30° × cos60° = ?',
'8. log₂1024 = ?',
'9. The circumference of a circle is 31.4cm, find its area (π≈3.14)',
'10. Solve the equation: 2x + 5 = 17',
],
},
]
// ─── Main Flow ─────────────────────────────────────────
const groups = (args && args.groups && args.groups.length)
? args.groups
: DEFAULT_GROUPS
log(`Total ${groups.reduce((n, g) => n + g.problems.length, 0)} problems, ${groups.length} groups`)
groups.forEach((g) => log(` ${g.name}: ${g.problems.join(', ')}`))
// Run pipeline in parallel for each group, problems written directly in prompt
const results = await parallel(
groups.map((group) => () => {
const problemsBlock = group.problems.join('\n')
return pipeline(
[group], // The entire group as a single unit
// Stage 1: Solve
(grp) => agent(
SOLVER_PROMPT.replace('{problems_block}', grp.problems.join('\n')),
{ label: `${grp.name}-Solve`, phase: 'Solve' }
),
// Stage 2: Verify
(solution, grp) => agent(
VERIFIER_PROMPT
.replace('{problems_block}', grp.problems.join('\n'))
.replace('{solution}', solution),
{ label: `${grp.name}-Verify`, phase: 'Verify' }
),
// Stage 3: Score
(verification, grp) => agent(
SCORER_PROMPT
.replace('{problems_block}', grp.problems.join('\n'))
.replace('{verification}', verification),
{ label: `${grp.name}-Score`, phase: 'Score' }
),
)
})
)
// Return by group
const output = {}
groups.forEach((g, i) => output[g.name] = results[i][0])
return output
Invocation Methods
Just say "run workflow math-problems" in Claude Code. Claude will call the
Workflowtool to execute it.
Method 1: Use Default Problems (10 problems in 2 groups)
Ask Claude to run it directly:
run workflow math-problems
Claude executes:
Workflow({ name: 'math-problems' })
Method 2: Custom Problem Grouping (Passed via args)
Tell Claude the specific problems and groupings:
run workflow math-problems, 8 problems divided into 4 groups:
12×15, √144+3², 2^10, trailing zeros of 100!,
1+2+...+100, sin30°×cos60°, log₂1024, 1/2+1/3+1/6
Claude executes:
Workflow({
name: 'math-problems',
args: {
groups: [
{ name: 'Group 1', problems: ['1. 12×15', '2. √144+3²'] },
{ name: 'Group 2', problems: ['3. 2^10', '4. trailing zeros of 100!'] },
{ name: 'Group 3', problems: ['5. 1+2+...+100', '6. sin30°×cos60°'] },
{ name: 'Group 4', problems: ['7. log₂1024', '8. 1/2+1/3+1/6'] },
]
}
})
Method 3: Custom Grouping (Arbitrary Problems)
run workflow math-problems, divided into 2 groups:
Geometry: Find the area of a circle with radius 5, find the volume of a cube with side length 3
Algebra: Solve x²-4=0, find x for 3x+2=14
Claude executes:
Workflow({
name: 'math-problems',
args: {
groups: [
{ name: 'Geometry', problems: ['Find the area of a circle with radius 5', 'Find the volume of a cube with side length 3'] },
{ name: 'Algebra', problems: ['Solve x²-4=0', 'Find x for 3x+2=14'] },
]
}
})
Tip: Use
/workflowsto view real-time progress. After the workflow finishes, the results are automatically returned to the conversation.
Why write problems in the prompt?
| Method | Beginner Experience | Maintainability |
|---|---|---|
| Dynamic Round-Robin Grouping | Hard to tell which problem is in which group; requires mentally mapping the grouping logic | Modifying problems requires understanding round-robin |
| Problems written in prompt (✅ Current) | DEFAULT_GROUPS directly shows the grouping; modifying problems means just modifying the array |
Intuitive to modify problems and groupings |
7. Defining Agents within Workflows
The agentType in Workflows does not support custom agents from .claude/agents/. Solution: Define agent roles within the script using Prompt Templates.
Prompt Template Pattern (Recommended)
Write the complete instructions for each agent as a string template, using {placeholder} to mark data insertion points:
// ─── Prompt Templates (Defined at the top, clear view of all agents) ──────────
const SOLVER_PROMPT = `You are a math problem-solving expert. Please solve the following math problems one by one.
{problems_block}
Output format (per problem):
- Problem: {Original problem}
- Solution process: {Step-by-step derivation}
- Answer: {Final result}`
const VERIFIER_PROMPT = `You are a math verification expert. Independently re-solve the problems and compare them with the solutions below.
{problems_block}
=== Solutions to Verify ===
{solution}
=== Requirements ===
- Calculate independently; do not trust the provided solutions.
- Compare step-by-step and mark as correct or incorrect.
Output format:
- Judgment: ✅ Correct / ❌ Incorrect
- Reason for error: {If any}`
const SCORER_PROMPT = `You are a math scoring expert. Score based on the solutions and verification results.
{problems_block}
=== Verification Results ===
{verification}
Scoring: 10=Perfect | 7-9=Correct but improvable | 4-6=Partially correct | 0-3=Incorrect
Output format:
- Score: {0-10}
- Comment: {One sentence}`
// ─── End of Templates ─────────────────────────────────────────
Usage: Fill data using `.replace()`
// Use .replace() in the pipeline to fill data into templates
pipeline(
[group], // Entire group of data
// Stage 1: Solve
(grp) => agent(
SOLVER_PROMPT.replace('{problems_block}', grp.problems.join('\n')),
{ label: `${grp.name}-Solve`, phase: 'Solve' }
),
// Stage 2: Verify (solution is the output of the previous stage)
(solution, grp) => agent(
VERIFIER_PROMPT
.replace('{problems_block}', grp.problems.join('\n'))
.replace('{solution}', solution),
{ label: `${grp.name}-Verify`, phase: 'Verify' }
),
// Stage 3: Score (verification is the output of the previous stage)
(verification, grp) => agent(
SCORER_PROMPT
.replace('{problems_block}', grp.problems.join('\n'))
.replace('{verification}', verification),
{ label: `${grp.name}-Score`, phase: 'Score' }
),
)
Comparison of Three Agent Definition Methods
| Method | Pros | Cons | Applicable Scenarios |
|---|---|---|---|
| Prompt Template (✅ Recommended) | Clear separation of instructions and data; .replace() is easy to understand |
Templates can get long with multiple stages | Pipelines with ≥2 stages |
| Agent Object + buildPrompt() | Well-encapsulated, reusable | Requires understanding this binding |
Reusing the same agent in multiple places |
| Inline Strings | Simplest | Prompts and logic are mixed | Single stage, demos |
Recommendation: Beginners should use the Prompt Template pattern. Having templates at the top of the file provides a clear view of all agent roles and data flows at a glance.
8. ⚠️ Limitations and Pitfalls
Known Limitations
| Issue | Description | Solution |
|---|---|---|
| Custom agents unavailable | agentType only supports built-in types; definitions in .claude/agents/ are ignored |
Define Agent objects within the script |
| args might be lost | args might be undefined when referencing a workflow by name |
Use inline scripts or provide default values |
| TypeScript not supported | Scripts are pure JS; type annotations will cause errors | Use pure JS, replace types with comments |
| No Date/Math.random | Date.now(), Math.random(), etc., are unavailable (affects caching) |
Pass timestamps via args |
| Concurrency limit | Simultaneous running agents ≈ min(16, CPU cores - 2) |
Automatically queues, no handling needed |
| Total limit | Max 1000 agents per workflow | Group reasonably |
| 7-day auto-expiration | Looping tasks stop automatically after 7 days | Recreate when needed |
Supported agentType List (Built-in)
claude, claude-code-guide, Explore, general-purpose, Plan
gsd-*, glm-plan-usage:usage-query-agent, statusline-setup
❌ Not supported: Custom names in
.claude/agents/
9. Architecture Comparison
Workflow vs. Direct Agent Tool Usage
graph TB
subgraph "Workflow Method"
W1[JS Script Control Flow] --> W2[agent]
W1 --> W3[agent]
W1 --> W4[agent]
W2 --> W5[pipeline/parallel orchestration]
W3 --> W5
W4 --> W5
W5 --> W6[Structured return]
end
subgraph "Agent Tool Method"
A1[Main session prompt] --> A2[Agent subagent_type]
A1 --> A3[Agent subagent_type]
A2 --> A4[Manual aggregation]
A3 --> A4
end
style W1 fill:#bbdefb
style A1 fill:#fff9c4| Dimension | Workflow | Agent Tool |
|---|---|---|
| Orchestration Method | JS code control flow | Prompt-driven |
| Parallel Capability | Natively supported by parallel() |
Requires manually spawning multiple |
| Pipeline | Done in one line with pipeline() |
Requires manual chaining |
| Custom Agents | ❌ Built-in types only | ✅ subagent_type supports custom |
| args Passing | ⚠️ Might be lost when referenced by name |
✅ Passed via prompt |
| Applicable Scenarios | Batch, multi-stage, structured | Flexible, small number of agents |
| Complexity | Requires writing JS scripts | Simple prompts |
Choosing between pipeline and parallel
graph LR
Q{Are there dependencies
between data items?} -->|Yes| P[Use pipeline]
Q -->|No| PR[Use parallel]
Q{Do all results need to be
processed together?} -->|Yes| PR
Q -->|No| P
style Q fill:#fff9c4| Pattern | When to Use | Analogy |
|---|---|---|
| pipeline | Each data item goes through multiple stages, items are independent | Factory assembly line |
| parallel | Multiple tasks run simultaneously, aggregated after all complete | Parallel engineering team |
| pipeline + parallel | Parallel grouping, pipeline within groups | Multiple assembly lines operating simultaneously |
10. Summary
Core Takeaways
- Dynamic Workflow = JS script orchestration of multiple agents
- Three primitives:
agent(),pipeline(),parallel() - Custom agents must be defined within the script; cannot reference
.claude/agents/ - args passing is unstable; provide default values or use inline scripts
- Scripts are pure JS; TS syntax,
Date.now(), andMath.random()are not supported
Recommended Template
export const meta = {
name: 'my-workflow',
description: 'Description',
phases: [{ title: 'Phase1' }, { title: 'Phase2' }],
}
// 1. Prompt Templates (Defined at the top, {placeholder} marks data positions)
const AGENT_PROMPT = `You are an expert.
{data_block}
Please process the above data as required.`
// 2. Data Grouping (Defined directly, easy for beginners to understand at a glance)
const DEFAULT_GROUPS = [
{ name: 'Group A', items: ['Data 1', 'Data 2'] },
{ name: 'Group B', items: ['Data 3', 'Data 4'] },
]
const groups = (args && args.groups) || DEFAULT_GROUPS
// 3. Orchestration: Parallel per group, pipeline within group
const results = await parallel(
groups.map(group => () => pipeline(
[group],
(grp) => agent(
AGENT_PROMPT.replace('{data_block}', grp.items.join('\n')),
{ label: `${grp.name}-Stage 1`, phase: 'Phase1' }
),
(prev, grp) => agent(
'Further process based on the result:\n' + prev,
{ label: `${grp.name}-Stage 2`, phase: 'Phase2' }
),
))
)
// 4. Return by group
const output = {}
groups.forEach((g, i) => output[g.name] = results[i][0])
return output
Further Learning
Official Documentation:
- Dynamic Workflows Official Documentation — Complete reference for orchestrating sub-agents, covering running, saving, managing, and limitations
- Official Documentation — Custom Subagents
- Official Documentation — Skills
Community Resources:
📝 This guide is summarized from practical experience with Claude Code Dynamic Workflow. All code has been verified through actual execution. Official documentation reference: Dynamic Workflows.