claude_swarm 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/commands/release.md +1 -1
- data/.claude/hooks/lint-code-files.rb +65 -0
- data/.rubocop.yml +22 -2
- data/CHANGELOG.md +14 -1
- data/CLAUDE.md +1 -1
- data/CONTRIBUTING.md +69 -0
- data/README.md +27 -2
- data/Rakefile +71 -3
- data/analyze_coverage.rb +94 -0
- data/docs/v2/CHANGELOG.swarm_cli.md +43 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +379 -0
- data/docs/v2/CHANGELOG.swarm_sdk.md +362 -0
- data/docs/v2/README.md +308 -0
- data/docs/v2/guides/claude-code-agents.md +262 -0
- data/docs/v2/guides/complete-tutorial.md +3088 -0
- data/docs/v2/guides/getting-started.md +1456 -0
- data/docs/v2/guides/memory-adapters.md +998 -0
- data/docs/v2/guides/plugins.md +816 -0
- data/docs/v2/guides/quick-start-cli.md +1745 -0
- data/docs/v2/guides/rails-integration.md +1902 -0
- data/docs/v2/guides/swarm-memory.md +599 -0
- data/docs/v2/reference/cli.md +729 -0
- data/docs/v2/reference/ruby-dsl.md +2154 -0
- data/docs/v2/reference/yaml.md +1835 -0
- data/docs-team-swarm.yml +2222 -0
- data/examples/learning-assistant/assistant.md +7 -0
- data/examples/learning-assistant/example-memories/concept-example.md +90 -0
- data/examples/learning-assistant/example-memories/experience-example.md +66 -0
- data/examples/learning-assistant/example-memories/fact-example.md +76 -0
- data/examples/learning-assistant/example-memories/memory-index.md +78 -0
- data/examples/learning-assistant/example-memories/skill-example.md +168 -0
- data/examples/learning-assistant/learning_assistant.rb +34 -0
- data/examples/learning-assistant/learning_assistant.yml +20 -0
- data/examples/v2/dsl/01_basic.rb +44 -0
- data/examples/v2/dsl/02_core_parameters.rb +59 -0
- data/examples/v2/dsl/03_capabilities.rb +71 -0
- data/examples/v2/dsl/04_llm_parameters.rb +56 -0
- data/examples/v2/dsl/05_advanced_flags.rb +73 -0
- data/examples/v2/dsl/06_permissions.rb +80 -0
- data/examples/v2/dsl/07_mcp_server.rb +62 -0
- data/examples/v2/dsl/08_swarm_hooks.rb +53 -0
- data/examples/v2/dsl/09_agent_hooks.rb +67 -0
- data/examples/v2/dsl/10_all_agents_hooks.rb +67 -0
- data/examples/v2/dsl/11_delegation.rb +60 -0
- data/examples/v2/dsl/12_complete_integration.rb +137 -0
- data/examples/v2/file_tools_swarm.yml +102 -0
- data/examples/v2/hooks/01_basic_hooks.rb +133 -0
- data/examples/v2/hooks/02_usage_tracking.rb +201 -0
- data/examples/v2/hooks/03_production_monitoring.rb +429 -0
- data/examples/v2/hooks/agent_stop_exit_0.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_1.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_2.yml +26 -0
- data/examples/v2/hooks/multiple_hooks_all_pass.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_first_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_second_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_warnings.yml +37 -0
- data/examples/v2/hooks/post_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_2.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_2.yml +27 -0
- data/examples/v2/hooks/swarm_summary.sh +44 -0
- data/examples/v2/hooks/user_prompt_exit_0.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_1.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_2.yml +21 -0
- data/examples/v2/hooks/validate_bash.rb +59 -0
- data/examples/v2/multi_directory_permissions.yml +221 -0
- data/examples/v2/node_context_demo.rb +127 -0
- data/examples/v2/node_workflow.rb +173 -0
- data/examples/v2/path_resolution_demo.rb +216 -0
- data/examples/v2/simple-swarm-v2.rb +90 -0
- data/examples/v2/simple-swarm-v2.yml +62 -0
- data/examples/v2/swarm.yml +71 -0
- data/examples/v2/swarm_with_hooks.yml +61 -0
- data/examples/v2/swarm_with_hooks_simple.yml +25 -0
- data/examples/v2/think_tool_demo.rb +62 -0
- data/exe/swarm +6 -0
- data/lib/claude_swarm/claude_mcp_server.rb +0 -6
- data/lib/claude_swarm/cli.rb +10 -3
- data/lib/claude_swarm/commands/ps.rb +19 -20
- data/lib/claude_swarm/commands/show.rb +1 -1
- data/lib/claude_swarm/configuration.rb +10 -12
- data/lib/claude_swarm/mcp_generator.rb +10 -1
- data/lib/claude_swarm/orchestrator.rb +73 -49
- data/lib/claude_swarm/system_utils.rb +37 -11
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm/worktree_manager.rb +1 -0
- data/lib/claude_swarm/yaml_loader.rb +22 -0
- data/lib/claude_swarm.rb +7 -2
- data/lib/swarm_cli/cli.rb +201 -0
- data/lib/swarm_cli/command_registry.rb +61 -0
- data/lib/swarm_cli/commands/mcp_serve.rb +130 -0
- data/lib/swarm_cli/commands/mcp_tools.rb +148 -0
- data/lib/swarm_cli/commands/migrate.rb +55 -0
- data/lib/swarm_cli/commands/run.rb +173 -0
- data/lib/swarm_cli/config_loader.rb +97 -0
- data/lib/swarm_cli/formatters/human_formatter.rb +711 -0
- data/lib/swarm_cli/formatters/json_formatter.rb +51 -0
- data/lib/swarm_cli/interactive_repl.rb +918 -0
- data/lib/swarm_cli/mcp_serve_options.rb +44 -0
- data/lib/swarm_cli/mcp_tools_options.rb +59 -0
- data/lib/swarm_cli/migrate_options.rb +54 -0
- data/lib/swarm_cli/migrator.rb +132 -0
- data/lib/swarm_cli/options.rb +151 -0
- data/lib/swarm_cli/ui/components/agent_badge.rb +33 -0
- data/lib/swarm_cli/ui/components/content_block.rb +120 -0
- data/lib/swarm_cli/ui/components/divider.rb +57 -0
- data/lib/swarm_cli/ui/components/panel.rb +62 -0
- data/lib/swarm_cli/ui/components/usage_stats.rb +70 -0
- data/lib/swarm_cli/ui/formatters/cost.rb +49 -0
- data/lib/swarm_cli/ui/formatters/number.rb +58 -0
- data/lib/swarm_cli/ui/formatters/text.rb +77 -0
- data/lib/swarm_cli/ui/formatters/time.rb +73 -0
- data/lib/swarm_cli/ui/icons.rb +59 -0
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +188 -0
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +45 -0
- data/lib/swarm_cli/ui/state/depth_tracker.rb +40 -0
- data/lib/swarm_cli/ui/state/spinner_manager.rb +170 -0
- data/lib/swarm_cli/ui/state/usage_tracker.rb +62 -0
- data/lib/swarm_cli/version.rb +5 -0
- data/lib/swarm_cli.rb +44 -0
- data/lib/swarm_memory/adapters/base.rb +141 -0
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +845 -0
- data/lib/swarm_memory/chat_extension.rb +34 -0
- data/lib/swarm_memory/cli/commands.rb +306 -0
- data/lib/swarm_memory/core/entry.rb +37 -0
- data/lib/swarm_memory/core/frontmatter_parser.rb +108 -0
- data/lib/swarm_memory/core/metadata_extractor.rb +68 -0
- data/lib/swarm_memory/core/path_normalizer.rb +75 -0
- data/lib/swarm_memory/core/semantic_index.rb +244 -0
- data/lib/swarm_memory/core/storage.rb +288 -0
- data/lib/swarm_memory/core/storage_read_tracker.rb +63 -0
- data/lib/swarm_memory/dsl/builder_extension.rb +40 -0
- data/lib/swarm_memory/dsl/memory_config.rb +113 -0
- data/lib/swarm_memory/embeddings/embedder.rb +36 -0
- data/lib/swarm_memory/embeddings/informers_embedder.rb +152 -0
- data/lib/swarm_memory/errors.rb +21 -0
- data/lib/swarm_memory/integration/cli_registration.rb +30 -0
- data/lib/swarm_memory/integration/configuration.rb +43 -0
- data/lib/swarm_memory/integration/registration.rb +31 -0
- data/lib/swarm_memory/integration/sdk_plugin.rb +531 -0
- data/lib/swarm_memory/optimization/analyzer.rb +244 -0
- data/lib/swarm_memory/optimization/defragmenter.rb +863 -0
- data/lib/swarm_memory/prompts/memory.md.erb +109 -0
- data/lib/swarm_memory/prompts/memory_assistant.md.erb +181 -0
- data/lib/swarm_memory/prompts/memory_researcher.md.erb +281 -0
- data/lib/swarm_memory/prompts/memory_retrieval.md.erb +78 -0
- data/lib/swarm_memory/search/semantic_search.rb +112 -0
- data/lib/swarm_memory/search/text_search.rb +42 -0
- data/lib/swarm_memory/search/text_similarity.rb +80 -0
- data/lib/swarm_memory/skills/meta/deep-learning.md +101 -0
- data/lib/swarm_memory/skills/meta/deep-learning.yml +14 -0
- data/lib/swarm_memory/tools/load_skill.rb +313 -0
- data/lib/swarm_memory/tools/memory_defrag.rb +382 -0
- data/lib/swarm_memory/tools/memory_delete.rb +99 -0
- data/lib/swarm_memory/tools/memory_edit.rb +185 -0
- data/lib/swarm_memory/tools/memory_glob.rb +160 -0
- data/lib/swarm_memory/tools/memory_grep.rb +247 -0
- data/lib/swarm_memory/tools/memory_multi_edit.rb +281 -0
- data/lib/swarm_memory/tools/memory_read.rb +123 -0
- data/lib/swarm_memory/tools/memory_write.rb +231 -0
- data/lib/swarm_memory/utils.rb +50 -0
- data/lib/swarm_memory/version.rb +5 -0
- data/lib/swarm_memory.rb +166 -0
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +127 -0
- data/lib/swarm_sdk/agent/builder.rb +461 -0
- data/lib/swarm_sdk/agent/chat/context_tracker.rb +314 -0
- data/lib/swarm_sdk/agent/chat/hook_integration.rb +372 -0
- data/lib/swarm_sdk/agent/chat/logging_helpers.rb +116 -0
- data/lib/swarm_sdk/agent/chat/system_reminder_injector.rb +152 -0
- data/lib/swarm_sdk/agent/chat.rb +1159 -0
- data/lib/swarm_sdk/agent/context.rb +112 -0
- data/lib/swarm_sdk/agent/context_manager.rb +309 -0
- data/lib/swarm_sdk/agent/definition.rb +556 -0
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +205 -0
- data/lib/swarm_sdk/configuration.rb +296 -0
- data/lib/swarm_sdk/context_compactor/metrics.rb +147 -0
- data/lib/swarm_sdk/context_compactor/token_counter.rb +106 -0
- data/lib/swarm_sdk/context_compactor.rb +340 -0
- data/lib/swarm_sdk/hooks/adapter.rb +359 -0
- data/lib/swarm_sdk/hooks/context.rb +197 -0
- data/lib/swarm_sdk/hooks/definition.rb +80 -0
- data/lib/swarm_sdk/hooks/error.rb +29 -0
- data/lib/swarm_sdk/hooks/executor.rb +146 -0
- data/lib/swarm_sdk/hooks/registry.rb +147 -0
- data/lib/swarm_sdk/hooks/result.rb +150 -0
- data/lib/swarm_sdk/hooks/shell_executor.rb +254 -0
- data/lib/swarm_sdk/hooks/tool_call.rb +35 -0
- data/lib/swarm_sdk/hooks/tool_result.rb +62 -0
- data/lib/swarm_sdk/log_collector.rb +51 -0
- data/lib/swarm_sdk/log_stream.rb +69 -0
- data/lib/swarm_sdk/markdown_parser.rb +75 -0
- data/lib/swarm_sdk/model_aliases.json +5 -0
- data/lib/swarm_sdk/models.json +1 -0
- data/lib/swarm_sdk/models.rb +120 -0
- data/lib/swarm_sdk/node/agent_config.rb +49 -0
- data/lib/swarm_sdk/node/builder.rb +439 -0
- data/lib/swarm_sdk/node/transformer_executor.rb +248 -0
- data/lib/swarm_sdk/node_context.rb +170 -0
- data/lib/swarm_sdk/node_orchestrator.rb +384 -0
- data/lib/swarm_sdk/permissions/config.rb +239 -0
- data/lib/swarm_sdk/permissions/error_formatter.rb +121 -0
- data/lib/swarm_sdk/permissions/path_matcher.rb +35 -0
- data/lib/swarm_sdk/permissions/validator.rb +173 -0
- data/lib/swarm_sdk/permissions_builder.rb +122 -0
- data/lib/swarm_sdk/plugin.rb +147 -0
- data/lib/swarm_sdk/plugin_registry.rb +101 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +243 -0
- data/lib/swarm_sdk/providers/openai_with_responses.rb +582 -0
- data/lib/swarm_sdk/result.rb +97 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +334 -0
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +140 -0
- data/lib/swarm_sdk/swarm/builder.rb +586 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +151 -0
- data/lib/swarm_sdk/swarm/tool_configurator.rb +419 -0
- data/lib/swarm_sdk/swarm.rb +982 -0
- data/lib/swarm_sdk/tools/bash.rb +274 -0
- data/lib/swarm_sdk/tools/clock.rb +44 -0
- data/lib/swarm_sdk/tools/delegate.rb +164 -0
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +83 -0
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +99 -0
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +101 -0
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +78 -0
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +194 -0
- data/lib/swarm_sdk/tools/edit.rb +150 -0
- data/lib/swarm_sdk/tools/glob.rb +158 -0
- data/lib/swarm_sdk/tools/grep.rb +228 -0
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +43 -0
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +163 -0
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +65 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +232 -0
- data/lib/swarm_sdk/tools/path_resolver.rb +43 -0
- data/lib/swarm_sdk/tools/read.rb +251 -0
- data/lib/swarm_sdk/tools/registry.rb +93 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +96 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +76 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +91 -0
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +61 -0
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +224 -0
- data/lib/swarm_sdk/tools/stores/storage.rb +148 -0
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +65 -0
- data/lib/swarm_sdk/tools/think.rb +95 -0
- data/lib/swarm_sdk/tools/todo_write.rb +216 -0
- data/lib/swarm_sdk/tools/web_fetch.rb +261 -0
- data/lib/swarm_sdk/tools/write.rb +117 -0
- data/lib/swarm_sdk/utils.rb +50 -0
- data/lib/swarm_sdk/version.rb +5 -0
- data/lib/swarm_sdk.rb +157 -0
- data/llm.v2.txt +13407 -0
- data/rubocop/cop/security/no_reflection_methods.rb +47 -0
- data/rubocop/cop/security/no_ruby_llm_logger.rb +32 -0
- data/swarm_cli.gemspec +57 -0
- data/swarm_memory.gemspec +28 -0
- data/swarm_sdk.gemspec +41 -0
- data/team.yml +1 -1
- data/team_full.yml +1875 -0
- data/{team_v2.yml → team_sdk.yml} +121 -52
- metadata +249 -6
- data/EXAMPLES.md +0 -164
|
@@ -0,0 +1,3088 @@
|
|
|
1
|
+
# SwarmSDK Complete Tutorial
|
|
2
|
+
|
|
3
|
+
**A comprehensive, in-depth guide covering every SwarmSDK feature**
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Part 1: Fundamentals](#part-1-fundamentals)
|
|
8
|
+
- [Part 2: Tools and Permissions](#part-2-tools-and-permissions)
|
|
9
|
+
- [Part 3: Agent Collaboration](#part-3-agent-collaboration)
|
|
10
|
+
- [Part 4: Hooks System](#part-4-hooks-system)
|
|
11
|
+
- [Part 5: Node Workflows](#part-5-node-workflows)
|
|
12
|
+
- [Part 6: Advanced Configuration](#part-6-advanced-configuration)
|
|
13
|
+
- [Part 7: Production Features](#part-7-production-features)
|
|
14
|
+
- [Part 8: Best Practices](#part-8-best-practices)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Part 1: Fundamentals
|
|
19
|
+
|
|
20
|
+
### 1.1 Agent Configuration Basics
|
|
21
|
+
|
|
22
|
+
Every agent needs three essential fields:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
agent :backend do
|
|
26
|
+
description "Backend developer" # Required: What the agent does
|
|
27
|
+
model "gpt-4" # Which LLM to use
|
|
28
|
+
system_prompt "You build APIs" # Instructions for the agent
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**YAML equivalent**:
|
|
33
|
+
```yaml
|
|
34
|
+
backend:
|
|
35
|
+
description: "Backend developer"
|
|
36
|
+
model: "gpt-4"
|
|
37
|
+
system_prompt: "You build APIs"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 1.2 Models and Providers
|
|
41
|
+
|
|
42
|
+
**OpenAI models**:
|
|
43
|
+
```ruby
|
|
44
|
+
agent :gpt_agent do
|
|
45
|
+
description "GPT agent"
|
|
46
|
+
model "gpt-4" # GPT-4
|
|
47
|
+
# Also: "gpt-4-turbo", "gpt-3.5-turbo", "gpt-4o"
|
|
48
|
+
provider "openai" # Default provider
|
|
49
|
+
end
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Anthropic models**:
|
|
53
|
+
```yaml
|
|
54
|
+
claude_agent:
|
|
55
|
+
description: "Claude agent"
|
|
56
|
+
model: "claude-sonnet-4"
|
|
57
|
+
provider: "anthropic"
|
|
58
|
+
# Also: "claude-opus-4", "claude-haiku-4"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Using custom providers**:
|
|
62
|
+
```ruby
|
|
63
|
+
agent :custom_agent do
|
|
64
|
+
description "Custom provider agent"
|
|
65
|
+
model "my-custom-model"
|
|
66
|
+
provider "custom" # Any custom provider
|
|
67
|
+
base_url "https://api.example.com/v1" # Custom endpoint
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Why different providers?** Different models have different strengths:
|
|
72
|
+
- GPT-4: Strong reasoning, code generation
|
|
73
|
+
- Claude Sonnet: Fast, cost-effective, great at following instructions
|
|
74
|
+
- Claude Opus: Best reasoning and analysis
|
|
75
|
+
- Claude Haiku: Fastest, cheapest for simple tasks
|
|
76
|
+
|
|
77
|
+
### 1.3 Working Directories
|
|
78
|
+
|
|
79
|
+
Each agent operates in a specific directory:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
agent :frontend do
|
|
83
|
+
description "Frontend developer"
|
|
84
|
+
model "gpt-4"
|
|
85
|
+
system_prompt "You work on React components"
|
|
86
|
+
directory "./frontend" # Agent's working directory
|
|
87
|
+
tools :Write, :Edit
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Why directories matter**:
|
|
92
|
+
- File tools (Read, Write, Edit) operate relative to the agent's directory
|
|
93
|
+
- Permissions are enforced within this scope
|
|
94
|
+
- Multiple agents can work in different directories simultaneously
|
|
95
|
+
|
|
96
|
+
**YAML example**:
|
|
97
|
+
```yaml
|
|
98
|
+
frontend:
|
|
99
|
+
description: "Frontend developer"
|
|
100
|
+
model: "gpt-4"
|
|
101
|
+
system_prompt: "You work on React components"
|
|
102
|
+
directory: "./frontend"
|
|
103
|
+
tools:
|
|
104
|
+
- Write
|
|
105
|
+
- Edit
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 1.4 System Prompts
|
|
109
|
+
|
|
110
|
+
System prompts define agent behavior and expertise:
|
|
111
|
+
|
|
112
|
+
**Simple prompt**:
|
|
113
|
+
```ruby
|
|
114
|
+
agent :helper do
|
|
115
|
+
description "Helpful assistant"
|
|
116
|
+
model "gpt-4"
|
|
117
|
+
system_prompt "You are a helpful assistant. Answer questions clearly."
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Detailed prompt with examples**:
|
|
122
|
+
```yaml
|
|
123
|
+
code_reviewer:
|
|
124
|
+
description: "Code reviewer"
|
|
125
|
+
model: "claude-sonnet-4"
|
|
126
|
+
system_prompt: |
|
|
127
|
+
You are an expert code reviewer.
|
|
128
|
+
|
|
129
|
+
Your responsibilities:
|
|
130
|
+
- Check for bugs and edge cases
|
|
131
|
+
- Verify error handling
|
|
132
|
+
- Suggest performance improvements
|
|
133
|
+
- Ensure code follows best practices
|
|
134
|
+
|
|
135
|
+
When reviewing:
|
|
136
|
+
1. Start with overall assessment
|
|
137
|
+
2. List specific issues with line numbers
|
|
138
|
+
3. Suggest concrete improvements
|
|
139
|
+
4. Highlight what was done well
|
|
140
|
+
|
|
141
|
+
Format your reviews as:
|
|
142
|
+
## Summary
|
|
143
|
+
[Overall assessment]
|
|
144
|
+
|
|
145
|
+
## Issues Found
|
|
146
|
+
- [Issue with line number]
|
|
147
|
+
|
|
148
|
+
## Suggestions
|
|
149
|
+
- [Specific improvements]
|
|
150
|
+
|
|
151
|
+
## Positive Feedback
|
|
152
|
+
- [What was done well]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**When to use detailed prompts**: For complex, specialized tasks where specific behavior is needed.
|
|
156
|
+
|
|
157
|
+
### 1.5 Coding Agent Flag
|
|
158
|
+
|
|
159
|
+
The `coding_agent` flag includes SwarmSDK's base system prompt for coding tasks:
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
agent :coder do
|
|
163
|
+
description "Programmer"
|
|
164
|
+
model "gpt-4"
|
|
165
|
+
coding_agent true # Include base coding prompt
|
|
166
|
+
system_prompt "You write clean Ruby code"
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**What the base prompt includes**:
|
|
171
|
+
- File operation best practices
|
|
172
|
+
- TodoWrite tool usage instructions
|
|
173
|
+
- Scratchpad tool documentation
|
|
174
|
+
- General coding guidelines
|
|
175
|
+
|
|
176
|
+
**When to use**:
|
|
177
|
+
- `coding_agent: true` - For agents that write/modify code
|
|
178
|
+
- `coding_agent: false` (default) - For agents that don't code (analysts, reviewers, planners)
|
|
179
|
+
|
|
180
|
+
### 1.6 Running Swarms
|
|
181
|
+
|
|
182
|
+
**CLI (Interactive)**:
|
|
183
|
+
```bash
|
|
184
|
+
swarm run config.yml
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**CLI (Non-interactive)**:
|
|
188
|
+
```bash
|
|
189
|
+
swarm run config.yml -p "Build a REST API"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**SDK (Ruby)**:
|
|
193
|
+
```ruby
|
|
194
|
+
swarm = SwarmSDK.build do
|
|
195
|
+
name "Dev Team"
|
|
196
|
+
lead :coder
|
|
197
|
+
agent :coder do
|
|
198
|
+
description "Programmer"
|
|
199
|
+
model "gpt-4"
|
|
200
|
+
system_prompt "You write code"
|
|
201
|
+
tools :Write, :Edit
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
result = swarm.execute("Build a REST API")
|
|
206
|
+
puts result.content
|
|
207
|
+
puts "Cost: $#{result.total_cost}"
|
|
208
|
+
puts "Duration: #{result.duration}s"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**When to use each**:
|
|
212
|
+
- CLI interactive: Exploratory work, conversations
|
|
213
|
+
- CLI non-interactive: Automation, scripting
|
|
214
|
+
- SDK: Custom applications, complex workflows
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Part 2: Tools and Permissions
|
|
219
|
+
|
|
220
|
+
### 2.1 Built-In Tools
|
|
221
|
+
|
|
222
|
+
SwarmSDK provides comprehensive tools for file operations, search, and execution.
|
|
223
|
+
|
|
224
|
+
#### Read Tool
|
|
225
|
+
|
|
226
|
+
Read files from the filesystem:
|
|
227
|
+
|
|
228
|
+
```ruby
|
|
229
|
+
agent :reader do
|
|
230
|
+
description "File reader"
|
|
231
|
+
model "gpt-4"
|
|
232
|
+
system_prompt "Read and analyze files"
|
|
233
|
+
directory "/projects/app"
|
|
234
|
+
# Read included by default
|
|
235
|
+
end
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Usage by agent**:
|
|
239
|
+
```
|
|
240
|
+
Read(file_path: "src/main.rb")
|
|
241
|
+
Read(file_path: "config/database.yml")
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Features**:
|
|
245
|
+
- Reads files relative to agent's directory
|
|
246
|
+
- Supports line ranges (offset, limit)
|
|
247
|
+
- Handles large files efficiently
|
|
248
|
+
|
|
249
|
+
#### Write Tool
|
|
250
|
+
|
|
251
|
+
Create new files:
|
|
252
|
+
|
|
253
|
+
```yaml
|
|
254
|
+
writer:
|
|
255
|
+
description: "File writer"
|
|
256
|
+
model: "gpt-4"
|
|
257
|
+
system_prompt: "Create new files"
|
|
258
|
+
directory: "./output"
|
|
259
|
+
tools:
|
|
260
|
+
- Write
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Usage**:
|
|
264
|
+
```
|
|
265
|
+
Write(file_path: "result.txt", content: "...")
|
|
266
|
+
Write(file_path: "src/new_module.rb", content: "class NewModule\n...")
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Security**: Write is restricted to agent's directory by default (configurable with permissions).
|
|
270
|
+
|
|
271
|
+
#### Edit Tool
|
|
272
|
+
|
|
273
|
+
Modify existing files with string replacement:
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
agent :editor do
|
|
277
|
+
description "Code editor"
|
|
278
|
+
model "gpt-4"
|
|
279
|
+
system_prompt "Modify existing files"
|
|
280
|
+
tools :Edit
|
|
281
|
+
end
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Usage**:
|
|
285
|
+
```
|
|
286
|
+
Edit(file_path: "main.rb", old_string: "def old_method", new_string: "def new_method")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Why Edit over Write**: Precise changes without rewriting entire files.
|
|
290
|
+
|
|
291
|
+
#### MultiEdit Tool
|
|
292
|
+
|
|
293
|
+
Apply multiple edits to a file in one operation:
|
|
294
|
+
|
|
295
|
+
```ruby
|
|
296
|
+
agent :refactorer do
|
|
297
|
+
description "Code refactorer"
|
|
298
|
+
model "gpt-4"
|
|
299
|
+
system_prompt "Refactor code efficiently"
|
|
300
|
+
tools :MultiEdit
|
|
301
|
+
end
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Usage**:
|
|
305
|
+
```
|
|
306
|
+
MultiEdit(
|
|
307
|
+
file_path: "main.rb",
|
|
308
|
+
edits: [
|
|
309
|
+
{old_string: "old1", new_string: "new1"},
|
|
310
|
+
{old_string: "old2", new_string: "new2"}
|
|
311
|
+
]
|
|
312
|
+
)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**When to use**: When making many changes to one file.
|
|
316
|
+
|
|
317
|
+
#### Bash Tool
|
|
318
|
+
|
|
319
|
+
Execute shell commands:
|
|
320
|
+
|
|
321
|
+
```yaml
|
|
322
|
+
executor:
|
|
323
|
+
description: "Command executor"
|
|
324
|
+
model: "gpt-4"
|
|
325
|
+
system_prompt: "Run commands and analyze output"
|
|
326
|
+
tools:
|
|
327
|
+
- Bash
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Usage**:
|
|
331
|
+
```
|
|
332
|
+
Bash(command: "ls -la")
|
|
333
|
+
Bash(command: "git status")
|
|
334
|
+
Bash(command: "npm test")
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Security considerations**: Can run any command, so use with permissions.
|
|
338
|
+
|
|
339
|
+
#### Grep Tool
|
|
340
|
+
|
|
341
|
+
Search file contents with regex:
|
|
342
|
+
|
|
343
|
+
```ruby
|
|
344
|
+
agent :searcher do
|
|
345
|
+
description "Code searcher"
|
|
346
|
+
model "gpt-4"
|
|
347
|
+
system_prompt "Find code patterns"
|
|
348
|
+
# Grep included by default
|
|
349
|
+
end
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**Usage**:
|
|
353
|
+
```
|
|
354
|
+
Grep(pattern: "def .*authenticate", path: ".")
|
|
355
|
+
Grep(pattern: "TODO", path: "src", output_mode: "content", -n: true)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Output modes**:
|
|
359
|
+
- `files_with_matches` (default): File paths only
|
|
360
|
+
- `content`: Matching lines with context
|
|
361
|
+
- `count`: Match counts per file
|
|
362
|
+
|
|
363
|
+
**Options**:
|
|
364
|
+
- `-i`: Case insensitive
|
|
365
|
+
- `-n`: Show line numbers
|
|
366
|
+
- `-A`, `-B`, `-C`: Show context lines
|
|
367
|
+
- `glob`: Filter by file pattern
|
|
368
|
+
- `type`: Filter by file type (js, py, rb, etc.)
|
|
369
|
+
|
|
370
|
+
#### Glob Tool
|
|
371
|
+
|
|
372
|
+
Find files by pattern:
|
|
373
|
+
|
|
374
|
+
```yaml
|
|
375
|
+
finder:
|
|
376
|
+
description: "File finder"
|
|
377
|
+
model: "gpt-4"
|
|
378
|
+
system_prompt: "Locate files"
|
|
379
|
+
# Glob included by default
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Usage**:
|
|
383
|
+
```
|
|
384
|
+
Glob(pattern: "**/*.rb")
|
|
385
|
+
Glob(pattern: "src/**/*.{js,ts}")
|
|
386
|
+
Glob(pattern: "test_*.py", path: "tests/")
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### TodoWrite Tool
|
|
390
|
+
|
|
391
|
+
Track multi-step tasks:
|
|
392
|
+
|
|
393
|
+
```ruby
|
|
394
|
+
agent :planner do
|
|
395
|
+
description "Task planner"
|
|
396
|
+
model "gpt-4"
|
|
397
|
+
system_prompt "Plan and track work"
|
|
398
|
+
# TodoWrite included by default
|
|
399
|
+
end
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Usage**:
|
|
403
|
+
```
|
|
404
|
+
TodoWrite(
|
|
405
|
+
todos: [
|
|
406
|
+
{content: "Read config", status: "completed", activeForm: "Reading config"},
|
|
407
|
+
{content: "Parse data", status: "in_progress", activeForm: "Parsing data"},
|
|
408
|
+
{content: "Write output", status: "pending", activeForm: "Writing output"}
|
|
409
|
+
]
|
|
410
|
+
)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**When to use**: Multi-step tasks where tracking progress helps.
|
|
414
|
+
|
|
415
|
+
#### Scratchpad Tools (Shared, Volatile)
|
|
416
|
+
|
|
417
|
+
Share work-in-progress data between agents in the same swarm. Scratchpad is **volatile** (in-memory only, cleared when swarm ends) and **shared** (all agents access the same scratchpad).
|
|
418
|
+
|
|
419
|
+
```ruby
|
|
420
|
+
agent :processor do
|
|
421
|
+
description "Data processor"
|
|
422
|
+
model "gpt-4"
|
|
423
|
+
system_prompt "Process and store intermediate results"
|
|
424
|
+
# Scratchpad tools included by default
|
|
425
|
+
end
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**ScratchpadWrite** - Store temporary data:
|
|
429
|
+
```
|
|
430
|
+
ScratchpadWrite(file_path: "task/batch1/result", content: "...", title: "Batch 1 Result")
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**ScratchpadRead** - Read shared data:
|
|
434
|
+
```
|
|
435
|
+
ScratchpadRead(file_path: "task/batch1/result")
|
|
436
|
+
# Returns: Content without line numbers (simpler than Memory tools)
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**ScratchpadList** - List all entries:
|
|
440
|
+
```
|
|
441
|
+
ScratchpadList(prefix: "task/") # List entries under task/
|
|
442
|
+
ScratchpadList() # List all entries
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Features**:
|
|
446
|
+
- **Volatile**: Cleared when swarm ends (no persistence)
|
|
447
|
+
- **Shared**: All agents access the same scratchpad
|
|
448
|
+
- **Simple**: Just write, read, list (no edit/grep/glob)
|
|
449
|
+
- **Fast**: In-memory only, no disk I/O
|
|
450
|
+
|
|
451
|
+
**Use cases**:
|
|
452
|
+
- Sharing intermediate results between agents
|
|
453
|
+
- Coordinating parallel work
|
|
454
|
+
- Passing data in delegation chains
|
|
455
|
+
|
|
456
|
+
#### Memory Tools (Per-Agent, Persistent)
|
|
457
|
+
|
|
458
|
+
Build persistent knowledge over time with per-agent memory. Memory is **persistent** (survives sessions) and **isolated** (each agent has its own memory).
|
|
459
|
+
|
|
460
|
+
```ruby
|
|
461
|
+
agent :learning_assistant do
|
|
462
|
+
description "Assistant that learns over time"
|
|
463
|
+
model "gpt-4"
|
|
464
|
+
system_prompt "Build knowledge in memory"
|
|
465
|
+
|
|
466
|
+
# Configure persistent memory
|
|
467
|
+
memory do
|
|
468
|
+
adapter :filesystem # default, optional
|
|
469
|
+
directory ".swarm/learning-assistant" # required
|
|
470
|
+
end
|
|
471
|
+
# Memory tools automatically added when memory is configured
|
|
472
|
+
end
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**YAML equivalent:**
|
|
476
|
+
```yaml
|
|
477
|
+
learning_assistant:
|
|
478
|
+
description: "Assistant that learns over time"
|
|
479
|
+
model: "gpt-4"
|
|
480
|
+
memory:
|
|
481
|
+
adapter: filesystem # optional
|
|
482
|
+
directory: .swarm/learning-assistant # required
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**MemoryWrite** - Store knowledge permanently:
|
|
486
|
+
```
|
|
487
|
+
MemoryWrite(file_path: "concepts/ruby/classes.md", content: "...", title: "Ruby Classes")
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**MemoryRead** - Recall knowledge (with line numbers):
|
|
491
|
+
```
|
|
492
|
+
MemoryRead(file_path: "concepts/ruby/classes.md")
|
|
493
|
+
# Returns:
|
|
494
|
+
# 1→---
|
|
495
|
+
# 2→type: concept
|
|
496
|
+
# 3→...
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**MemoryEdit** - Update knowledge:
|
|
500
|
+
```
|
|
501
|
+
MemoryEdit(file_path: "facts/user.md", old_string: "...", new_string: "...")
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**MemoryGlob** - Browse knowledge by pattern:
|
|
505
|
+
```
|
|
506
|
+
MemoryGlob(pattern: "concepts/ruby/**") # All Ruby concepts
|
|
507
|
+
MemoryGlob(pattern: "skills/**") # All skills
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**MemoryGrep** - Search knowledge by content:
|
|
511
|
+
```
|
|
512
|
+
MemoryGrep(pattern: "authentication", output_mode: "content")
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**MemoryDelete** - Remove obsolete knowledge:
|
|
516
|
+
```
|
|
517
|
+
MemoryDelete(file_path: "concepts/outdated.md")
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Features**:
|
|
521
|
+
- **Persistent**: Saved to disk, survives sessions
|
|
522
|
+
- **Per-agent**: Each agent has isolated memory
|
|
523
|
+
- **Comprehensive**: Full edit/search/browse capabilities
|
|
524
|
+
- **Ordered**: Search results show most recent first
|
|
525
|
+
|
|
526
|
+
**Use cases**:
|
|
527
|
+
- Learning agents that build expertise over time
|
|
528
|
+
- Agents that remember user preferences
|
|
529
|
+
- Agents that accumulate domain knowledge
|
|
530
|
+
- Persisting results across swarm restarts
|
|
531
|
+
|
|
532
|
+
#### Think Tool
|
|
533
|
+
|
|
534
|
+
Enable explicit reasoning and planning:
|
|
535
|
+
|
|
536
|
+
```ruby
|
|
537
|
+
agent :problem_solver do
|
|
538
|
+
description "Problem solver"
|
|
539
|
+
model "gpt-4"
|
|
540
|
+
system_prompt "Use the Think tool frequently to reason through problems"
|
|
541
|
+
# Think included by default
|
|
542
|
+
end
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Usage**:
|
|
546
|
+
```
|
|
547
|
+
Think(thoughts: "Let me break this down: 1) Read the file, 2) Analyze structure, 3) Make changes")
|
|
548
|
+
Think(thoughts: "If we have 150 requests/sec and each takes 20ms, that's 150 * 0.02 = 3 seconds")
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Why use Think**:
|
|
552
|
+
- **Better reasoning**: Explicit thinking leads to better outcomes
|
|
553
|
+
- **Step-by-step planning**: Break complex tasks into manageable steps
|
|
554
|
+
- **Arithmetic accuracy**: Work through calculations methodically
|
|
555
|
+
- **Context maintenance**: Remember important details across multiple steps
|
|
556
|
+
|
|
557
|
+
**When to use**:
|
|
558
|
+
1. **Before starting tasks**: Understand the problem and create a plan
|
|
559
|
+
2. **For arithmetic**: Work through calculations step by step
|
|
560
|
+
3. **After sub-tasks**: Summarize progress and plan next actions
|
|
561
|
+
4. **When debugging**: Track investigation process
|
|
562
|
+
5. **For complex decisions**: Break down logic and options
|
|
563
|
+
|
|
564
|
+
**How it works**: The Think tool records thoughts as function calls in the conversation history. These create "attention sinks" that the model can reference throughout the task, leading to better reasoning than just thinking in the system prompt.
|
|
565
|
+
|
|
566
|
+
**Best practice**: Successful agents use Think 5-10 times per task on average. If you haven't used Think in the last 2-3 actions, you probably should.
|
|
567
|
+
|
|
568
|
+
**Example workflow**:
|
|
569
|
+
```
|
|
570
|
+
1. Think: "User wants X. Breaking into: 1) Read code, 2) Identify changes, 3) Implement, 4) Test"
|
|
571
|
+
2. Read relevant files
|
|
572
|
+
3. Think: "I see the structure. Key files are A, B. Need to modify B's function foo()"
|
|
573
|
+
4. Make changes
|
|
574
|
+
5. Think: "Changes made. Next: verify tests pass"
|
|
575
|
+
6. Run tests
|
|
576
|
+
7. Think: "Tests pass. Task complete."
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
#### WebFetch Tool
|
|
580
|
+
|
|
581
|
+
Fetch and analyze web content:
|
|
582
|
+
|
|
583
|
+
```ruby
|
|
584
|
+
agent :researcher do
|
|
585
|
+
description "Web researcher"
|
|
586
|
+
model "gpt-4"
|
|
587
|
+
system_prompt "Research information from web sources"
|
|
588
|
+
# WebFetch included by default
|
|
589
|
+
end
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**Usage without LLM processing** (default):
|
|
593
|
+
```
|
|
594
|
+
WebFetch(url: "https://example.com/docs")
|
|
595
|
+
# Returns: Raw markdown conversion of the page
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Usage with LLM processing** (requires configuration):
|
|
599
|
+
```ruby
|
|
600
|
+
# First, configure WebFetch globally
|
|
601
|
+
SwarmSDK.configure do |config|
|
|
602
|
+
config.webfetch_provider = "anthropic"
|
|
603
|
+
config.webfetch_model = "claude-3-5-haiku-20241022"
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# Then agents can use it with prompts
|
|
607
|
+
WebFetch(url: "https://example.com/api-docs", prompt: "List all available API endpoints")
|
|
608
|
+
# Returns: LLM's analysis of the page content
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**Features**:
|
|
612
|
+
- Fetches web content and converts HTML to Markdown
|
|
613
|
+
- Optional LLM processing with user-defined prompts
|
|
614
|
+
- 15-minute cache to avoid redundant fetches
|
|
615
|
+
- Handles redirects and errors gracefully
|
|
616
|
+
- Supports custom providers and models via configuration
|
|
617
|
+
|
|
618
|
+
**HTML to Markdown conversion**:
|
|
619
|
+
- Uses `reverse_markdown` gem if installed (handles complex HTML, tables, etc.)
|
|
620
|
+
- Falls back to built-in converter for common HTML elements
|
|
621
|
+
- Always strips scripts and styles
|
|
622
|
+
|
|
623
|
+
**When to use**:
|
|
624
|
+
- Fetching API documentation
|
|
625
|
+
- Reading blog posts or articles
|
|
626
|
+
- Extracting information from web pages
|
|
627
|
+
- Researching technical content
|
|
628
|
+
|
|
629
|
+
**Disable specific default tools** (if needed):
|
|
630
|
+
```ruby
|
|
631
|
+
agent :agent_name do
|
|
632
|
+
description "..."
|
|
633
|
+
model "gpt-4"
|
|
634
|
+
disable_default_tools [:Think, :WebFetch] # Disable specific tools
|
|
635
|
+
# Or disable multiple: [:Think, :TodoWrite, :Grep]
|
|
636
|
+
end
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
```yaml
|
|
640
|
+
agent_name:
|
|
641
|
+
description: "..."
|
|
642
|
+
model: "gpt-4"
|
|
643
|
+
disable_default_tools: # Disable specific tools
|
|
644
|
+
- Think
|
|
645
|
+
- WebFetch
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### 2.2 Default Tools
|
|
649
|
+
|
|
650
|
+
Some tools are included automatically:
|
|
651
|
+
|
|
652
|
+
```ruby
|
|
653
|
+
agent :agent_name do
|
|
654
|
+
description "..."
|
|
655
|
+
model "gpt-4"
|
|
656
|
+
# These are included by default:
|
|
657
|
+
# - Read, Grep, Glob (file operations)
|
|
658
|
+
# - TodoWrite (task tracking)
|
|
659
|
+
# - ScratchpadWrite, ScratchpadRead, ScratchpadEdit, ScratchpadMultiEdit, ScratchpadGlob, ScratchpadGrep (shared persistent storage)
|
|
660
|
+
# - Think (explicit reasoning)
|
|
661
|
+
|
|
662
|
+
# Add additional tools:
|
|
663
|
+
tools :Write, :Edit, :Bash
|
|
664
|
+
end
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
**Disable default tools**:
|
|
668
|
+
```ruby
|
|
669
|
+
# Disable ALL default tools
|
|
670
|
+
agent :minimal_agent do
|
|
671
|
+
description "Minimal agent"
|
|
672
|
+
model "gpt-4"
|
|
673
|
+
disable_default_tools true
|
|
674
|
+
tools :Read # Only Read available
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# Disable SPECIFIC default tools
|
|
678
|
+
agent :selective_agent do
|
|
679
|
+
description "Selective agent"
|
|
680
|
+
model "gpt-4"
|
|
681
|
+
disable_default_tools [:Think, :TodoWrite] # Disable these
|
|
682
|
+
# Still has: Read, Grep, Glob, Scratchpad tools
|
|
683
|
+
end
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
```yaml
|
|
687
|
+
# Disable ALL default tools
|
|
688
|
+
minimal_agent:
|
|
689
|
+
description: "Minimal agent"
|
|
690
|
+
model: "gpt-4"
|
|
691
|
+
disable_default_tools: true
|
|
692
|
+
tools:
|
|
693
|
+
- Read # Only Read available
|
|
694
|
+
|
|
695
|
+
# Disable SPECIFIC default tools
|
|
696
|
+
selective_agent:
|
|
697
|
+
description: "Selective agent"
|
|
698
|
+
model: "gpt-4"
|
|
699
|
+
disable_default_tools:
|
|
700
|
+
- Think
|
|
701
|
+
- TodoWrite
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**When to disable**: When you want precise control over agent capabilities.
|
|
705
|
+
|
|
706
|
+
### 2.3 Path Permissions
|
|
707
|
+
|
|
708
|
+
Control which files agents can access:
|
|
709
|
+
|
|
710
|
+
**Allow specific paths**:
|
|
711
|
+
```ruby
|
|
712
|
+
agent :backend_dev do
|
|
713
|
+
description "Backend developer"
|
|
714
|
+
model "gpt-4"
|
|
715
|
+
directory "."
|
|
716
|
+
tools :Write, :Edit
|
|
717
|
+
|
|
718
|
+
permissions do
|
|
719
|
+
tool(:Write).allow_paths "backend/**/*"
|
|
720
|
+
tool(:Write).deny_paths "backend/secrets/**"
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
**YAML equivalent**:
|
|
726
|
+
```yaml
|
|
727
|
+
backend_dev:
|
|
728
|
+
description: "Backend developer"
|
|
729
|
+
model: "gpt-4"
|
|
730
|
+
directory: "."
|
|
731
|
+
tools:
|
|
732
|
+
- Write:
|
|
733
|
+
allowed_paths:
|
|
734
|
+
- "backend/**/*"
|
|
735
|
+
denied_paths:
|
|
736
|
+
- "backend/secrets/**"
|
|
737
|
+
- Edit:
|
|
738
|
+
allowed_paths:
|
|
739
|
+
- "backend/**/*"
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
**How it works**:
|
|
743
|
+
1. Agent attempts to write to `backend/api/users.rb` → Allowed
|
|
744
|
+
2. Agent attempts to write to `backend/secrets/keys.rb` → Denied (explicit deny)
|
|
745
|
+
3. Agent attempts to write to `frontend/app.js` → Denied (not in allowed paths)
|
|
746
|
+
|
|
747
|
+
**Default behavior**: Write, Edit, and MultiEdit are restricted to `**/*` (everything in agent's directory) by default.
|
|
748
|
+
|
|
749
|
+
### 2.4 Command Permissions
|
|
750
|
+
|
|
751
|
+
Restrict which bash commands agents can run:
|
|
752
|
+
|
|
753
|
+
```ruby
|
|
754
|
+
agent :safe_executor do
|
|
755
|
+
description "Safe command executor"
|
|
756
|
+
model "gpt-4"
|
|
757
|
+
tools :Bash
|
|
758
|
+
|
|
759
|
+
permissions do
|
|
760
|
+
tool(:Bash).allow_commands "ls", "pwd", "echo", "cat"
|
|
761
|
+
tool(:Bash).deny_commands "rm", "dd", "sudo"
|
|
762
|
+
end
|
|
763
|
+
end
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**YAML**:
|
|
767
|
+
```yaml
|
|
768
|
+
safe_executor:
|
|
769
|
+
description: "Safe command executor"
|
|
770
|
+
model: "gpt-4"
|
|
771
|
+
tools:
|
|
772
|
+
- Bash:
|
|
773
|
+
allowed_commands:
|
|
774
|
+
- ls
|
|
775
|
+
- pwd
|
|
776
|
+
- echo
|
|
777
|
+
- cat
|
|
778
|
+
denied_commands:
|
|
779
|
+
- rm
|
|
780
|
+
- dd
|
|
781
|
+
- sudo
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
**Why restrict commands**: Prevent agents from running dangerous operations.
|
|
785
|
+
|
|
786
|
+
### 2.5 All-Agents Permissions
|
|
787
|
+
|
|
788
|
+
Apply permissions to all agents at once:
|
|
789
|
+
|
|
790
|
+
**Ruby DSL**:
|
|
791
|
+
```ruby
|
|
792
|
+
SwarmSDK.build do
|
|
793
|
+
name "Team"
|
|
794
|
+
lead :dev
|
|
795
|
+
|
|
796
|
+
all_agents do
|
|
797
|
+
tools :Write, :Edit
|
|
798
|
+
|
|
799
|
+
permissions do
|
|
800
|
+
tool(:Write).allow_paths "src/**/*", "docs/**/*"
|
|
801
|
+
tool(:Write).deny_paths "**/secrets/**"
|
|
802
|
+
end
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
agent :dev do
|
|
806
|
+
description "Developer"
|
|
807
|
+
model "gpt-4"
|
|
808
|
+
# Inherits all_agents permissions
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
agent :tester do
|
|
812
|
+
description "Tester"
|
|
813
|
+
model "gpt-4"
|
|
814
|
+
# Also inherits all_agents permissions
|
|
815
|
+
end
|
|
816
|
+
end
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
**YAML**:
|
|
820
|
+
```yaml
|
|
821
|
+
version: 2
|
|
822
|
+
swarm:
|
|
823
|
+
name: "Team"
|
|
824
|
+
lead: dev
|
|
825
|
+
|
|
826
|
+
all_agents:
|
|
827
|
+
tools:
|
|
828
|
+
- Write:
|
|
829
|
+
allowed_paths:
|
|
830
|
+
- "src/**/*"
|
|
831
|
+
- "docs/**/*"
|
|
832
|
+
denied_paths:
|
|
833
|
+
- "**/secrets/**"
|
|
834
|
+
- Edit
|
|
835
|
+
|
|
836
|
+
agents:
|
|
837
|
+
dev:
|
|
838
|
+
description: "Developer"
|
|
839
|
+
model: "gpt-4"
|
|
840
|
+
|
|
841
|
+
tester:
|
|
842
|
+
description: "Tester"
|
|
843
|
+
model: "gpt-4"
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
**Override for specific agents**:
|
|
847
|
+
```ruby
|
|
848
|
+
agent :admin do
|
|
849
|
+
description "Admin with more access"
|
|
850
|
+
model "gpt-4"
|
|
851
|
+
|
|
852
|
+
permissions do
|
|
853
|
+
tool(:Write).allow_paths "**/*" # Overrides all_agents
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
### 2.6 Bypass Permissions
|
|
859
|
+
|
|
860
|
+
Disable permission checking for trusted agents:
|
|
861
|
+
|
|
862
|
+
```ruby
|
|
863
|
+
agent :trusted_admin do
|
|
864
|
+
description "Trusted admin"
|
|
865
|
+
model "gpt-4"
|
|
866
|
+
tools :Write, :Edit, :Bash
|
|
867
|
+
bypass_permissions true # No permission checks
|
|
868
|
+
end
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
**When to use**: Internal tools, admin agents, fully trusted scenarios.
|
|
872
|
+
|
|
873
|
+
**Warning**: Use sparingly - bypassed agents can modify any file and run any command.
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## Part 3: Agent Collaboration
|
|
878
|
+
|
|
879
|
+
### 3.1 Basic Delegation
|
|
880
|
+
|
|
881
|
+
Agents collaborate by delegating work to specialists:
|
|
882
|
+
|
|
883
|
+
**Ruby DSL**:
|
|
884
|
+
```ruby
|
|
885
|
+
swarm = SwarmSDK.build do
|
|
886
|
+
name "Code Review Team"
|
|
887
|
+
lead :developer
|
|
888
|
+
|
|
889
|
+
agent :developer do
|
|
890
|
+
description "Writes code"
|
|
891
|
+
model "gpt-4"
|
|
892
|
+
system_prompt "You write code and send it for review"
|
|
893
|
+
tools :Write, :Edit
|
|
894
|
+
delegates_to :reviewer
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
agent :reviewer do
|
|
898
|
+
description "Reviews code"
|
|
899
|
+
model "claude-sonnet-4"
|
|
900
|
+
system_prompt "You review code for bugs and improvements"
|
|
901
|
+
end
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
result = swarm.execute("Write an email validation function and get it reviewed")
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
**YAML**:
|
|
908
|
+
```yaml
|
|
909
|
+
version: 2
|
|
910
|
+
swarm:
|
|
911
|
+
name: "Code Review Team"
|
|
912
|
+
lead: developer
|
|
913
|
+
|
|
914
|
+
agents:
|
|
915
|
+
developer:
|
|
916
|
+
description: "Writes code"
|
|
917
|
+
model: "gpt-4"
|
|
918
|
+
system_prompt: "You write code and send it for review"
|
|
919
|
+
tools:
|
|
920
|
+
- Write
|
|
921
|
+
- Edit
|
|
922
|
+
delegates_to:
|
|
923
|
+
- reviewer
|
|
924
|
+
|
|
925
|
+
reviewer:
|
|
926
|
+
description: "Reviews code"
|
|
927
|
+
model: "claude-sonnet-4"
|
|
928
|
+
system_prompt: "You review code for bugs and improvements"
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
**How delegation works**:
|
|
932
|
+
1. You send task to `developer`
|
|
933
|
+
2. Developer writes code using Write tool
|
|
934
|
+
3. Developer calls `DelegateTaskToReviewer(task: "Review this code")`
|
|
935
|
+
4. Reviewer analyzes code and returns feedback
|
|
936
|
+
5. Developer receives feedback and can iterate
|
|
937
|
+
6. Developer returns final result to you
|
|
938
|
+
|
|
939
|
+
**The delegation tool**: When you configure `delegates_to: [reviewer]`, the developer automatically gets a `DelegateTaskToReviewer` tool.
|
|
940
|
+
|
|
941
|
+
### 3.2 Multi-Level Delegation
|
|
942
|
+
|
|
943
|
+
Build hierarchical teams:
|
|
944
|
+
|
|
945
|
+
```ruby
|
|
946
|
+
swarm = SwarmSDK.build do
|
|
947
|
+
name "Software Team"
|
|
948
|
+
lead :architect
|
|
949
|
+
|
|
950
|
+
agent :architect do
|
|
951
|
+
description "Lead architect"
|
|
952
|
+
model "gpt-4"
|
|
953
|
+
system_prompt "You coordinate the team and break down work"
|
|
954
|
+
delegates_to :backend, :frontend
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
agent :backend do
|
|
958
|
+
description "Backend developer"
|
|
959
|
+
model "gpt-4"
|
|
960
|
+
system_prompt "You build APIs and databases"
|
|
961
|
+
tools :Write, :Edit
|
|
962
|
+
delegates_to :database, :tester
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
agent :frontend do
|
|
966
|
+
description "Frontend developer"
|
|
967
|
+
model "gpt-4"
|
|
968
|
+
system_prompt "You build UI components"
|
|
969
|
+
tools :Write, :Edit
|
|
970
|
+
delegates_to :designer, :tester
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
agent :database do
|
|
974
|
+
description "Database specialist"
|
|
975
|
+
model "gpt-4"
|
|
976
|
+
system_prompt "You design schemas and write migrations"
|
|
977
|
+
tools :Write
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
agent :designer do
|
|
981
|
+
description "UI designer"
|
|
982
|
+
model "claude-sonnet-4"
|
|
983
|
+
system_prompt "You design user interfaces"
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
agent :tester do
|
|
987
|
+
description "QA engineer"
|
|
988
|
+
model "claude-sonnet-4"
|
|
989
|
+
system_prompt "You write tests and verify functionality"
|
|
990
|
+
tools :Write
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
result = swarm.execute("Build a user authentication system")
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
**Execution flow**:
|
|
998
|
+
1. Architect receives task
|
|
999
|
+
2. Architect delegates to backend: "Build auth API"
|
|
1000
|
+
3. Backend delegates to database: "Design user schema"
|
|
1001
|
+
4. Database designs schema, returns to backend
|
|
1002
|
+
5. Backend delegates to tester: "Test auth endpoints"
|
|
1003
|
+
6. Tester writes tests, returns to backend
|
|
1004
|
+
7. Backend returns completed API to architect
|
|
1005
|
+
8. Architect delegates to frontend: "Build login UI"
|
|
1006
|
+
9. Frontend delegates to designer: "Design login form"
|
|
1007
|
+
10. Designer creates design, returns to frontend
|
|
1008
|
+
11. Frontend implements UI, returns to architect
|
|
1009
|
+
12. Architect returns complete system to you
|
|
1010
|
+
|
|
1011
|
+
**Why multi-level delegation**: Complex tasks need specialized sub-teams.
|
|
1012
|
+
|
|
1013
|
+
### 3.3 Peer Collaboration
|
|
1014
|
+
|
|
1015
|
+
Agents at the same level can collaborate:
|
|
1016
|
+
|
|
1017
|
+
```yaml
|
|
1018
|
+
version: 2
|
|
1019
|
+
swarm:
|
|
1020
|
+
name: "Peer Collaboration"
|
|
1021
|
+
lead: backend
|
|
1022
|
+
|
|
1023
|
+
agents:
|
|
1024
|
+
backend:
|
|
1025
|
+
description: "Backend developer"
|
|
1026
|
+
model: "gpt-4"
|
|
1027
|
+
system_prompt: "You build APIs"
|
|
1028
|
+
tools:
|
|
1029
|
+
- Write
|
|
1030
|
+
delegates_to:
|
|
1031
|
+
- frontend
|
|
1032
|
+
- database
|
|
1033
|
+
|
|
1034
|
+
frontend:
|
|
1035
|
+
description: "Frontend developer"
|
|
1036
|
+
model: "gpt-4"
|
|
1037
|
+
system_prompt: "You build UI"
|
|
1038
|
+
tools:
|
|
1039
|
+
- Write
|
|
1040
|
+
delegates_to:
|
|
1041
|
+
- backend # Can delegate back!
|
|
1042
|
+
- database
|
|
1043
|
+
|
|
1044
|
+
database:
|
|
1045
|
+
description: "Database specialist"
|
|
1046
|
+
model: "gpt-4"
|
|
1047
|
+
system_prompt: "You design databases"
|
|
1048
|
+
tools:
|
|
1049
|
+
- Write
|
|
1050
|
+
delegates_to:
|
|
1051
|
+
- backend
|
|
1052
|
+
- frontend
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
**Use case**: Backend and frontend need to coordinate API contracts, database schema affects both.
|
|
1056
|
+
|
|
1057
|
+
**Note**: SwarmSDK prevents circular delegation (A → B → A) within a single task to avoid infinite loops.
|
|
1058
|
+
|
|
1059
|
+
### 3.4 Delegation Patterns
|
|
1060
|
+
|
|
1061
|
+
**Pattern 1: Linear Pipeline**
|
|
1062
|
+
```
|
|
1063
|
+
You → Planner → Coder → Tester → You
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
**Pattern 2: Hub and Spoke**
|
|
1067
|
+
```
|
|
1068
|
+
┌──→ Backend ──┐
|
|
1069
|
+
You → Architect → You
|
|
1070
|
+
└──→ Frontend ─┘
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
**Pattern 3: Specialist Pool**
|
|
1074
|
+
```
|
|
1075
|
+
┌──→ Database
|
|
1076
|
+
├──→ Cache
|
|
1077
|
+
Lead ──┼──→ Security
|
|
1078
|
+
├──→ Testing
|
|
1079
|
+
└──→ Docs
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
**Choosing a pattern**:
|
|
1083
|
+
- **Linear**: Sequential tasks with clear order
|
|
1084
|
+
- **Hub and Spoke**: Parallel tasks coordinated by lead
|
|
1085
|
+
- **Specialist Pool**: Lead delegates to any specialist as needed
|
|
1086
|
+
|
|
1087
|
+
### 3.5 Markdown Agent Files
|
|
1088
|
+
|
|
1089
|
+
Define agents in separate markdown files for better organization:
|
|
1090
|
+
|
|
1091
|
+
**agents/backend.md**:
|
|
1092
|
+
```markdown
|
|
1093
|
+
---
|
|
1094
|
+
description: "Backend developer specializing in Ruby on Rails"
|
|
1095
|
+
model: "gpt-4"
|
|
1096
|
+
tools:
|
|
1097
|
+
- Write
|
|
1098
|
+
- Edit
|
|
1099
|
+
- Bash
|
|
1100
|
+
---
|
|
1101
|
+
|
|
1102
|
+
# Backend Developer
|
|
1103
|
+
|
|
1104
|
+
You are an expert backend developer specializing in Ruby on Rails.
|
|
1105
|
+
|
|
1106
|
+
## Responsibilities
|
|
1107
|
+
- Build RESTful APIs
|
|
1108
|
+
- Design database schemas
|
|
1109
|
+
- Write tests
|
|
1110
|
+
- Handle authentication
|
|
1111
|
+
|
|
1112
|
+
## Best Practices
|
|
1113
|
+
- Follow Rails conventions
|
|
1114
|
+
- Use strong parameters
|
|
1115
|
+
- Write comprehensive tests
|
|
1116
|
+
- Document API endpoints
|
|
1117
|
+
|
|
1118
|
+
## Tools
|
|
1119
|
+
You have access to file operations and bash commands.
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
**Note**: Markdown agent files MUST include YAML frontmatter between `---` delimiters. The frontmatter contains description, model, tools, etc. Content after frontmatter becomes the system_prompt.
|
|
1123
|
+
|
|
1124
|
+
**Load in YAML**:
|
|
1125
|
+
```yaml
|
|
1126
|
+
version: 2
|
|
1127
|
+
swarm:
|
|
1128
|
+
name: "Team"
|
|
1129
|
+
lead: backend
|
|
1130
|
+
|
|
1131
|
+
agents:
|
|
1132
|
+
backend: "agents/backend.md"
|
|
1133
|
+
|
|
1134
|
+
# Or with overrides:
|
|
1135
|
+
# backend:
|
|
1136
|
+
# agent_file: "agents/backend.md"
|
|
1137
|
+
# timeout: 120
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
**Why markdown files**:
|
|
1141
|
+
- Better organization for complex prompts
|
|
1142
|
+
- Version control friendly
|
|
1143
|
+
- Easy to review and edit
|
|
1144
|
+
- Supports rich formatting
|
|
1145
|
+
|
|
1146
|
+
**What goes in the file**: The markdown file contains both:
|
|
1147
|
+
1. **Frontmatter** (YAML between `---` delimiters): description, model, tools, delegates_to, etc.
|
|
1148
|
+
2. **System prompt** (content after frontmatter): Agent's instructions and behavior
|
|
1149
|
+
|
|
1150
|
+
You can override frontmatter settings in YAML using the hash format with `agent_file` key.
|
|
1151
|
+
|
|
1152
|
+
### 3.6 Delegation Tracking
|
|
1153
|
+
|
|
1154
|
+
SwarmSDK tracks which agents were involved:
|
|
1155
|
+
|
|
1156
|
+
```ruby
|
|
1157
|
+
result = swarm.execute("Build auth system")
|
|
1158
|
+
|
|
1159
|
+
# See which agents participated (returns array of symbols)
|
|
1160
|
+
puts result.agents_involved
|
|
1161
|
+
# => [:architect, :backend, :database, :tester]
|
|
1162
|
+
|
|
1163
|
+
# Check if specific agent was involved
|
|
1164
|
+
if result.agents_involved.include?(:reviewer)
|
|
1165
|
+
puts "Code was reviewed!"
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
# See logs organized by agent
|
|
1169
|
+
result.logs.group_by { |log| log[:agent] }.each do |agent, logs|
|
|
1170
|
+
puts "#{agent}: #{logs.size} events"
|
|
1171
|
+
end
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
**CLI output** shows delegation in real-time:
|
|
1175
|
+
```
|
|
1176
|
+
architect • thinking...
|
|
1177
|
+
architect → backend: Build auth API
|
|
1178
|
+
|
|
1179
|
+
backend • thinking...
|
|
1180
|
+
backend → database: Design user schema
|
|
1181
|
+
|
|
1182
|
+
database • thinking...
|
|
1183
|
+
database • Complete
|
|
1184
|
+
|
|
1185
|
+
backend • Complete
|
|
1186
|
+
architect • Complete
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
**Why tracking matters**: Understanding agent collaboration helps optimize team structure.
|
|
1190
|
+
|
|
1191
|
+
---
|
|
1192
|
+
|
|
1193
|
+
## Part 4: Hooks System
|
|
1194
|
+
|
|
1195
|
+
Hooks let you customize behavior at every step of execution.
|
|
1196
|
+
|
|
1197
|
+
### 4.1 Hook Events
|
|
1198
|
+
|
|
1199
|
+
SwarmSDK provides 13 hook events:
|
|
1200
|
+
|
|
1201
|
+
**Swarm Lifecycle**:
|
|
1202
|
+
- `swarm_start` - When Swarm.execute is called (before first message)
|
|
1203
|
+
- `swarm_stop` - When execution completes
|
|
1204
|
+
- `first_message` - When first user message is sent
|
|
1205
|
+
|
|
1206
|
+
**Agent/LLM**:
|
|
1207
|
+
- `user_prompt` - Before sending message to LLM
|
|
1208
|
+
- `agent_step` - After agent makes intermediate response with tool calls
|
|
1209
|
+
- `agent_stop` - After agent completes (no more tool calls)
|
|
1210
|
+
|
|
1211
|
+
**Tool Usage**:
|
|
1212
|
+
- `pre_tool_use` - Before tool execution (can block)
|
|
1213
|
+
- `post_tool_use` - After tool execution
|
|
1214
|
+
|
|
1215
|
+
**Delegation**:
|
|
1216
|
+
- `pre_delegation` - Before delegating to another agent
|
|
1217
|
+
- `post_delegation` - After delegation completes
|
|
1218
|
+
|
|
1219
|
+
**Context**:
|
|
1220
|
+
- `context_warning` - When context usage crosses threshold (80%, 90%)
|
|
1221
|
+
|
|
1222
|
+
**Debug**:
|
|
1223
|
+
- `breakpoint_enter` - When entering interactive debugging
|
|
1224
|
+
- `breakpoint_exit` - When exiting debugging
|
|
1225
|
+
|
|
1226
|
+
### 4.2 Hook Actions
|
|
1227
|
+
|
|
1228
|
+
Hooks can take different actions by returning specific values:
|
|
1229
|
+
|
|
1230
|
+
**Continue (default)**: Return nil or nothing
|
|
1231
|
+
```ruby
|
|
1232
|
+
hook :pre_tool_use do |ctx|
|
|
1233
|
+
puts "Tool: #{ctx.tool_call.name}"
|
|
1234
|
+
# Continues execution
|
|
1235
|
+
end
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
**Halt**: Stop execution with error
|
|
1239
|
+
```ruby
|
|
1240
|
+
hook :pre_tool_use, matcher: "Bash" do |ctx|
|
|
1241
|
+
if ctx.tool_call.parameters[:command].include?("rm -rf")
|
|
1242
|
+
SwarmSDK::Hooks::Result.halt("Dangerous command blocked")
|
|
1243
|
+
end
|
|
1244
|
+
end
|
|
1245
|
+
```
|
|
1246
|
+
|
|
1247
|
+
**Replace**: Modify tool result
|
|
1248
|
+
```ruby
|
|
1249
|
+
hook :post_tool_use do |ctx|
|
|
1250
|
+
if ctx.tool_result.content.length > 10000
|
|
1251
|
+
SwarmSDK::Hooks::Result.replace("Content truncated (too long)")
|
|
1252
|
+
end
|
|
1253
|
+
end
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
**Reprompt**: Continue execution with new prompt (swarm_stop only)
|
|
1257
|
+
```ruby
|
|
1258
|
+
hook :swarm_stop do |ctx|
|
|
1259
|
+
result = ctx.metadata[:result]
|
|
1260
|
+
if result.content.include?("TODO")
|
|
1261
|
+
SwarmSDK::Hooks::Result.reprompt("Complete all TODOs before finishing")
|
|
1262
|
+
end
|
|
1263
|
+
end
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
**Finish Agent**: End current agent's turn and return control
|
|
1267
|
+
```ruby
|
|
1268
|
+
hook :agent_step do |ctx|
|
|
1269
|
+
if ctx.metadata[:tool_calls].size > 10
|
|
1270
|
+
SwarmSDK::Hooks::Result.finish_agent("Too many tool calls")
|
|
1271
|
+
end
|
|
1272
|
+
end
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
**Finish Swarm**: End entire swarm execution immediately
|
|
1276
|
+
```ruby
|
|
1277
|
+
hook :pre_tool_use do |ctx|
|
|
1278
|
+
if ctx.tool_call.name == "Bash" && ctx.tool_call.parameters[:command] == "shutdown"
|
|
1279
|
+
SwarmSDK::Hooks::Result.finish_swarm("Emergency shutdown requested")
|
|
1280
|
+
end
|
|
1281
|
+
end
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
### 4.3 Ruby Block Hooks
|
|
1285
|
+
|
|
1286
|
+
Define hooks as Ruby blocks in the DSL:
|
|
1287
|
+
|
|
1288
|
+
**Swarm-level hook**:
|
|
1289
|
+
```ruby
|
|
1290
|
+
swarm = SwarmSDK.build do
|
|
1291
|
+
name "Team"
|
|
1292
|
+
lead :dev
|
|
1293
|
+
|
|
1294
|
+
# Hook applies to entire swarm
|
|
1295
|
+
hook :swarm_start do |ctx|
|
|
1296
|
+
puts "Starting: #{ctx.metadata[:prompt]}"
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
agent :dev do
|
|
1300
|
+
description "Developer"
|
|
1301
|
+
model "gpt-4"
|
|
1302
|
+
end
|
|
1303
|
+
end
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
**All-agents hook**:
|
|
1307
|
+
```ruby
|
|
1308
|
+
SwarmSDK.build do
|
|
1309
|
+
name "Team"
|
|
1310
|
+
lead :dev
|
|
1311
|
+
|
|
1312
|
+
all_agents do
|
|
1313
|
+
# Hook applies to all agents
|
|
1314
|
+
hook :pre_tool_use, matcher: "Write|Edit" do |ctx|
|
|
1315
|
+
puts "[#{ctx.agent_name}] Modifying: #{ctx.tool_call.parameters[:file_path]}"
|
|
1316
|
+
end
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
agent :dev do
|
|
1320
|
+
description "Developer"
|
|
1321
|
+
model "gpt-4"
|
|
1322
|
+
tools :Write, :Edit
|
|
1323
|
+
end
|
|
1324
|
+
end
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
**Agent-specific hook**:
|
|
1328
|
+
```ruby
|
|
1329
|
+
agent :dev do
|
|
1330
|
+
description "Developer"
|
|
1331
|
+
model "gpt-4"
|
|
1332
|
+
tools :Write, :Edit
|
|
1333
|
+
|
|
1334
|
+
# Hook applies only to this agent
|
|
1335
|
+
hook :post_tool_use, matcher: "Write" do |ctx|
|
|
1336
|
+
if ctx.tool_result.success?
|
|
1337
|
+
puts "File created: #{ctx.tool_result.tool_name}"
|
|
1338
|
+
end
|
|
1339
|
+
end
|
|
1340
|
+
end
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
**Hook with matcher**:
|
|
1344
|
+
```ruby
|
|
1345
|
+
agent :dev do
|
|
1346
|
+
description "Developer"
|
|
1347
|
+
model "gpt-4"
|
|
1348
|
+
tools :Write, :Edit, :Bash
|
|
1349
|
+
|
|
1350
|
+
# Only runs for Bash tool
|
|
1351
|
+
hook :pre_tool_use, matcher: "Bash" do |ctx|
|
|
1352
|
+
cmd = ctx.tool_call.parameters[:command]
|
|
1353
|
+
if cmd.start_with?("rm ")
|
|
1354
|
+
SwarmSDK::Hooks::Result.halt("rm command not allowed")
|
|
1355
|
+
end
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
### 4.4 Shell Command Hooks (YAML)
|
|
1361
|
+
|
|
1362
|
+
Define hooks as shell commands in YAML:
|
|
1363
|
+
|
|
1364
|
+
```yaml
|
|
1365
|
+
version: 2
|
|
1366
|
+
swarm:
|
|
1367
|
+
name: "Team with Hooks"
|
|
1368
|
+
lead: dev
|
|
1369
|
+
|
|
1370
|
+
hooks:
|
|
1371
|
+
swarm_start:
|
|
1372
|
+
- type: command
|
|
1373
|
+
command: "echo 'Swarm started' >> /tmp/swarm.log"
|
|
1374
|
+
|
|
1375
|
+
all_agents:
|
|
1376
|
+
hooks:
|
|
1377
|
+
pre_tool_use:
|
|
1378
|
+
- matcher: "Write|Edit"
|
|
1379
|
+
type: command
|
|
1380
|
+
command: "scripts/validate_write.sh"
|
|
1381
|
+
timeout: 10
|
|
1382
|
+
|
|
1383
|
+
agents:
|
|
1384
|
+
dev:
|
|
1385
|
+
description: "Developer"
|
|
1386
|
+
model: "gpt-4"
|
|
1387
|
+
tools:
|
|
1388
|
+
- Write
|
|
1389
|
+
- Edit
|
|
1390
|
+
hooks:
|
|
1391
|
+
post_tool_use:
|
|
1392
|
+
- matcher: "Write"
|
|
1393
|
+
type: command
|
|
1394
|
+
command: "scripts/notify_write.sh"
|
|
1395
|
+
```
|
|
1396
|
+
|
|
1397
|
+
**Hook script receives JSON on stdin**:
|
|
1398
|
+
|
|
1399
|
+
**scripts/validate_write.sh**:
|
|
1400
|
+
```bash
|
|
1401
|
+
#!/bin/bash
|
|
1402
|
+
# Read JSON from stdin
|
|
1403
|
+
INPUT=$(cat)
|
|
1404
|
+
|
|
1405
|
+
# Extract tool and parameters
|
|
1406
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool')
|
|
1407
|
+
FILE=$(echo "$INPUT" | jq -r '.parameters.file_path')
|
|
1408
|
+
|
|
1409
|
+
# Validate
|
|
1410
|
+
if [[ "$FILE" == *"production"* ]]; then
|
|
1411
|
+
echo "Cannot write to production" >&2
|
|
1412
|
+
exit 2 # Halt with error
|
|
1413
|
+
fi
|
|
1414
|
+
|
|
1415
|
+
# Allow
|
|
1416
|
+
exit 0
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
**Exit codes**:
|
|
1420
|
+
- `0`: Success, continue execution
|
|
1421
|
+
- `2`: Halt execution with error from stderr
|
|
1422
|
+
- Other: Non-blocking warning
|
|
1423
|
+
|
|
1424
|
+
### 4.5 Hook Context
|
|
1425
|
+
|
|
1426
|
+
Hooks receive a context object with event-specific data:
|
|
1427
|
+
|
|
1428
|
+
**pre_tool_use context**:
|
|
1429
|
+
```ruby
|
|
1430
|
+
hook :pre_tool_use do |ctx|
|
|
1431
|
+
ctx.event # => :pre_tool_use
|
|
1432
|
+
ctx.agent_name # => "developer"
|
|
1433
|
+
ctx.swarm # => Swarm instance
|
|
1434
|
+
|
|
1435
|
+
# Tool call info
|
|
1436
|
+
ctx.tool_call.id # => "call_abc123"
|
|
1437
|
+
ctx.tool_call.name # => "Write"
|
|
1438
|
+
ctx.tool_call.parameters # => {file_path: "...", content: "..."}
|
|
1439
|
+
|
|
1440
|
+
# Metadata (event-specific)
|
|
1441
|
+
ctx.metadata[:message_count] # Number of messages so far
|
|
1442
|
+
end
|
|
1443
|
+
```
|
|
1444
|
+
|
|
1445
|
+
**post_tool_use context**:
|
|
1446
|
+
```ruby
|
|
1447
|
+
hook :post_tool_use do |ctx|
|
|
1448
|
+
ctx.tool_result.tool_call_id # => "call_abc123"
|
|
1449
|
+
ctx.tool_result.tool_name # => "Write"
|
|
1450
|
+
ctx.tool_result.content # Tool output
|
|
1451
|
+
ctx.tool_result.success? # => true/false
|
|
1452
|
+
end
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
**swarm_stop context**:
|
|
1456
|
+
```ruby
|
|
1457
|
+
hook :swarm_stop do |ctx|
|
|
1458
|
+
ctx.metadata[:result] # Final Result object
|
|
1459
|
+
ctx.metadata[:success] # => true/false
|
|
1460
|
+
ctx.metadata[:duration] # Execution time
|
|
1461
|
+
ctx.metadata[:total_cost] # Total cost
|
|
1462
|
+
ctx.metadata[:agents_involved] # Array of agent names
|
|
1463
|
+
end
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1466
|
+
### 4.6 Breakpoint Debugging
|
|
1467
|
+
|
|
1468
|
+
Insert interactive breakpoints for debugging:
|
|
1469
|
+
|
|
1470
|
+
```ruby
|
|
1471
|
+
agent :dev do
|
|
1472
|
+
description "Developer"
|
|
1473
|
+
model "gpt-4"
|
|
1474
|
+
tools :Write
|
|
1475
|
+
|
|
1476
|
+
hook :post_tool_use, matcher: "Write" do |ctx|
|
|
1477
|
+
# Drop into IRB to inspect context
|
|
1478
|
+
require 'irb'
|
|
1479
|
+
binding.irb
|
|
1480
|
+
end
|
|
1481
|
+
end
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
**In the IRB session**:
|
|
1485
|
+
```ruby
|
|
1486
|
+
irb(main)> ctx.tool_result.content
|
|
1487
|
+
# => "class NewClass\n..."
|
|
1488
|
+
|
|
1489
|
+
irb(main)> ctx.agent_name
|
|
1490
|
+
# => "dev"
|
|
1491
|
+
|
|
1492
|
+
irb(main)> exit # Continue execution
|
|
1493
|
+
```
|
|
1494
|
+
|
|
1495
|
+
**When to use**: Debugging complex workflows, inspecting tool results, understanding agent behavior.
|
|
1496
|
+
|
|
1497
|
+
### 4.7 Practical Hook Examples
|
|
1498
|
+
|
|
1499
|
+
**Example 1: Usage Tracking**
|
|
1500
|
+
```ruby
|
|
1501
|
+
all_agents do
|
|
1502
|
+
hook :agent_stop do |ctx|
|
|
1503
|
+
File.open("usage.log", "a") do |f|
|
|
1504
|
+
f.puts "#{ctx.agent_name},#{ctx.metadata[:usage][:total_tokens]},#{ctx.metadata[:usage][:cost]}"
|
|
1505
|
+
end
|
|
1506
|
+
end
|
|
1507
|
+
end
|
|
1508
|
+
```
|
|
1509
|
+
|
|
1510
|
+
**Example 2: Dangerous Command Prevention**
|
|
1511
|
+
```ruby
|
|
1512
|
+
agent :executor do
|
|
1513
|
+
description "Command executor"
|
|
1514
|
+
model "gpt-4"
|
|
1515
|
+
tools :Bash
|
|
1516
|
+
|
|
1517
|
+
hook :pre_tool_use, matcher: "Bash" do |ctx|
|
|
1518
|
+
cmd = ctx.tool_call.parameters[:command]
|
|
1519
|
+
|
|
1520
|
+
dangerous = ["rm -rf", "dd if=", "sudo", ">", "mkfs"]
|
|
1521
|
+
if dangerous.any? { |d| cmd.include?(d) }
|
|
1522
|
+
SwarmSDK::Hooks::Result.halt("Dangerous command blocked: #{cmd}")
|
|
1523
|
+
end
|
|
1524
|
+
end
|
|
1525
|
+
end
|
|
1526
|
+
```
|
|
1527
|
+
|
|
1528
|
+
**Example 3: Automatic Code Review**
|
|
1529
|
+
```ruby
|
|
1530
|
+
agent :dev do
|
|
1531
|
+
description "Developer"
|
|
1532
|
+
model "gpt-4"
|
|
1533
|
+
tools :Write, :Edit
|
|
1534
|
+
delegates_to :reviewer
|
|
1535
|
+
|
|
1536
|
+
hook :post_tool_use, matcher: "Write|Edit" do |ctx|
|
|
1537
|
+
if ctx.tool_result.success? && ctx.tool_call.parameters[:file_path].end_with?(".rb")
|
|
1538
|
+
# Automatically send for review
|
|
1539
|
+
SwarmSDK::Hooks::Result.finish_agent("Code written, delegating to reviewer")
|
|
1540
|
+
end
|
|
1541
|
+
end
|
|
1542
|
+
end
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1545
|
+
**Example 4: Context Warning Handler**
|
|
1546
|
+
```ruby
|
|
1547
|
+
all_agents do
|
|
1548
|
+
hook :context_warning do |ctx|
|
|
1549
|
+
percentage = ctx.metadata[:percentage]
|
|
1550
|
+
|
|
1551
|
+
if percentage.to_f > 90
|
|
1552
|
+
# Emergency: Finish agent to prevent context overflow
|
|
1553
|
+
SwarmSDK::Hooks::Result.finish_agent("Context limit reached (#{percentage})")
|
|
1554
|
+
else
|
|
1555
|
+
# Just log the warning
|
|
1556
|
+
puts "⚠️ Context usage: #{percentage}"
|
|
1557
|
+
end
|
|
1558
|
+
end
|
|
1559
|
+
end
|
|
1560
|
+
```
|
|
1561
|
+
|
|
1562
|
+
---
|
|
1563
|
+
|
|
1564
|
+
## Part 5: Node Workflows
|
|
1565
|
+
|
|
1566
|
+
Node workflows enable multi-stage pipelines where different agent teams handle each stage.
|
|
1567
|
+
|
|
1568
|
+
### 5.1 Basic Node Workflow
|
|
1569
|
+
|
|
1570
|
+
**Concept**: Each node is a mini-swarm execution stage:
|
|
1571
|
+
|
|
1572
|
+
```ruby
|
|
1573
|
+
swarm = SwarmSDK.build do
|
|
1574
|
+
name "Development Pipeline"
|
|
1575
|
+
|
|
1576
|
+
# Define agents (shared across nodes)
|
|
1577
|
+
agent :planner do
|
|
1578
|
+
description "Plans work"
|
|
1579
|
+
model "gpt-4"
|
|
1580
|
+
system_prompt "Break down tasks into steps"
|
|
1581
|
+
end
|
|
1582
|
+
|
|
1583
|
+
agent :coder do
|
|
1584
|
+
description "Writes code"
|
|
1585
|
+
model "gpt-4"
|
|
1586
|
+
system_prompt "Implement features"
|
|
1587
|
+
tools :Write, :Edit
|
|
1588
|
+
end
|
|
1589
|
+
|
|
1590
|
+
agent :tester do
|
|
1591
|
+
description "Tests code"
|
|
1592
|
+
model "claude-sonnet-4"
|
|
1593
|
+
system_prompt "Write and run tests"
|
|
1594
|
+
tools :Write, :Bash
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
# Define nodes (execution stages)
|
|
1598
|
+
node :planning do
|
|
1599
|
+
agent(:planner)
|
|
1600
|
+
end
|
|
1601
|
+
|
|
1602
|
+
node :implementation do
|
|
1603
|
+
agent(:coder)
|
|
1604
|
+
depends_on :planning # Depends on planning
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
node :testing do
|
|
1608
|
+
agent(:tester)
|
|
1609
|
+
depends_on :implementation # Depends on implementation
|
|
1610
|
+
end
|
|
1611
|
+
|
|
1612
|
+
# Start from planning
|
|
1613
|
+
start_node :planning
|
|
1614
|
+
end
|
|
1615
|
+
|
|
1616
|
+
result = swarm.execute("Build a user authentication system")
|
|
1617
|
+
```
|
|
1618
|
+
|
|
1619
|
+
**Execution flow**:
|
|
1620
|
+
1. Planning node runs with planner agent
|
|
1621
|
+
2. Planner creates a plan
|
|
1622
|
+
3. Implementation node runs with coder agent
|
|
1623
|
+
4. Coder receives plan and implements it
|
|
1624
|
+
5. Testing node runs with tester agent
|
|
1625
|
+
6. Tester receives implementation and tests it
|
|
1626
|
+
7. Final result returned
|
|
1627
|
+
|
|
1628
|
+
**Why nodes**: Different stages need different agent teams and can transform data between stages.
|
|
1629
|
+
|
|
1630
|
+
### 5.2 Node Dependencies
|
|
1631
|
+
|
|
1632
|
+
Nodes can depend on multiple previous nodes:
|
|
1633
|
+
|
|
1634
|
+
```ruby
|
|
1635
|
+
node :planning do
|
|
1636
|
+
agent(:planner)
|
|
1637
|
+
end
|
|
1638
|
+
|
|
1639
|
+
node :frontend_impl do
|
|
1640
|
+
agent(:frontend_dev)
|
|
1641
|
+
depends_on :planning
|
|
1642
|
+
end
|
|
1643
|
+
|
|
1644
|
+
node :backend_impl do
|
|
1645
|
+
agent(:backend_dev)
|
|
1646
|
+
depends_on :planning
|
|
1647
|
+
end
|
|
1648
|
+
|
|
1649
|
+
node :integration do
|
|
1650
|
+
agent(:integration_tester)
|
|
1651
|
+
depends_on :frontend_impl, :backend_impl # Waits for both
|
|
1652
|
+
end
|
|
1653
|
+
```
|
|
1654
|
+
|
|
1655
|
+
**Execution order**:
|
|
1656
|
+
1. planning
|
|
1657
|
+
2. frontend_impl and backend_impl (parallel conceptually, but sequential in execution)
|
|
1658
|
+
3. integration (after both complete)
|
|
1659
|
+
|
|
1660
|
+
**Note**: All node dependencies use `depends_on`:
|
|
1661
|
+
- `depends_on :node` - Single dependency, receives that node's output
|
|
1662
|
+
- `depends_on :node1, :node2` - Multiple dependencies, receives hash of results
|
|
1663
|
+
|
|
1664
|
+
### 5.3 Input Transformers
|
|
1665
|
+
|
|
1666
|
+
Transform data flowing into a node:
|
|
1667
|
+
|
|
1668
|
+
**Ruby transformer**:
|
|
1669
|
+
```ruby
|
|
1670
|
+
node :implementation do
|
|
1671
|
+
agent(:coder)
|
|
1672
|
+
depends_on :planning
|
|
1673
|
+
|
|
1674
|
+
# Transform planning output before sending to coder
|
|
1675
|
+
input do |ctx|
|
|
1676
|
+
plan = ctx.content
|
|
1677
|
+
|
|
1678
|
+
"Here is the plan:\n#{plan}\n\nImplement step 1 first: #{extract_first_step(plan)}"
|
|
1679
|
+
end
|
|
1680
|
+
end
|
|
1681
|
+
|
|
1682
|
+
def extract_first_step(plan)
|
|
1683
|
+
plan.lines.grep(/^\d+\./).first
|
|
1684
|
+
end
|
|
1685
|
+
```
|
|
1686
|
+
|
|
1687
|
+
**Context object**:
|
|
1688
|
+
```ruby
|
|
1689
|
+
input do |ctx|
|
|
1690
|
+
ctx.content # Previous node's output
|
|
1691
|
+
ctx.original_prompt # Original user prompt
|
|
1692
|
+
ctx.previous_result # Full Result object from previous node
|
|
1693
|
+
ctx.all_results # Hash of all completed nodes
|
|
1694
|
+
ctx.node_name # Current node name
|
|
1695
|
+
ctx.dependencies # Array of dependency node names
|
|
1696
|
+
end
|
|
1697
|
+
```
|
|
1698
|
+
|
|
1699
|
+
**Use cases**:
|
|
1700
|
+
- Extracting specific information
|
|
1701
|
+
- Formatting data for the next stage
|
|
1702
|
+
- Adding instructions or context
|
|
1703
|
+
- Filtering large outputs
|
|
1704
|
+
|
|
1705
|
+
### 5.4 Output Transformers
|
|
1706
|
+
|
|
1707
|
+
Transform data flowing out of a node:
|
|
1708
|
+
|
|
1709
|
+
```ruby
|
|
1710
|
+
node :planning do
|
|
1711
|
+
agent(:planner)
|
|
1712
|
+
|
|
1713
|
+
# Extract just the steps from planner's response
|
|
1714
|
+
output do |ctx|
|
|
1715
|
+
response = ctx.content
|
|
1716
|
+
response.scan(/^\d+\.\s+(.+)$/).flatten.join("\n")
|
|
1717
|
+
end
|
|
1718
|
+
end
|
|
1719
|
+
```
|
|
1720
|
+
|
|
1721
|
+
**Context object**:
|
|
1722
|
+
```ruby
|
|
1723
|
+
output do |ctx|
|
|
1724
|
+
ctx.content # Current node's result content
|
|
1725
|
+
ctx.result # Full Result object
|
|
1726
|
+
ctx.original_prompt # Original user prompt
|
|
1727
|
+
ctx.all_results # Hash of all completed nodes
|
|
1728
|
+
ctx.node_name # Current node name
|
|
1729
|
+
end
|
|
1730
|
+
```
|
|
1731
|
+
|
|
1732
|
+
**Use cases**:
|
|
1733
|
+
- Extracting specific data formats
|
|
1734
|
+
- Summarizing long outputs
|
|
1735
|
+
- Converting between formats
|
|
1736
|
+
- Preparing data for next node
|
|
1737
|
+
|
|
1738
|
+
### 5.5 Bash Transformers
|
|
1739
|
+
|
|
1740
|
+
Use bash scripts as transformers:
|
|
1741
|
+
|
|
1742
|
+
**Input transformer**:
|
|
1743
|
+
```ruby
|
|
1744
|
+
node :processor do
|
|
1745
|
+
agent(:processor)
|
|
1746
|
+
depends_on :analyzer
|
|
1747
|
+
|
|
1748
|
+
input_command "scripts/prepare_data.sh", timeout: 30
|
|
1749
|
+
end
|
|
1750
|
+
```
|
|
1751
|
+
|
|
1752
|
+
**scripts/prepare_data.sh**:
|
|
1753
|
+
```bash
|
|
1754
|
+
#!/bin/bash
|
|
1755
|
+
# Receives previous node output on stdin
|
|
1756
|
+
|
|
1757
|
+
# Read input
|
|
1758
|
+
INPUT=$(cat)
|
|
1759
|
+
|
|
1760
|
+
# Process
|
|
1761
|
+
PROCESSED=$(echo "$INPUT" | jq '.results[] | select(.score > 80)')
|
|
1762
|
+
|
|
1763
|
+
# Output
|
|
1764
|
+
echo "$PROCESSED"
|
|
1765
|
+
```
|
|
1766
|
+
|
|
1767
|
+
**Bash transformer exit codes**:
|
|
1768
|
+
- **Exit 0**: Use stdout as transformed content
|
|
1769
|
+
- **Exit 1**: Skip node execution, pass input unchanged
|
|
1770
|
+
- **Exit 2**: Halt workflow with error from stderr
|
|
1771
|
+
|
|
1772
|
+
**Example - Skip execution conditionally**:
|
|
1773
|
+
```bash
|
|
1774
|
+
#!/bin/bash
|
|
1775
|
+
INPUT=$(cat)
|
|
1776
|
+
|
|
1777
|
+
# Check if input is empty
|
|
1778
|
+
if [ -z "$INPUT" ]; then
|
|
1779
|
+
echo "No data to process" >&2
|
|
1780
|
+
exit 1 # Skip this node
|
|
1781
|
+
fi
|
|
1782
|
+
|
|
1783
|
+
# Process normally
|
|
1784
|
+
echo "$INPUT" | process_data
|
|
1785
|
+
exit 0
|
|
1786
|
+
```
|
|
1787
|
+
|
|
1788
|
+
**Example - Halt on error**:
|
|
1789
|
+
```bash
|
|
1790
|
+
#!/bin/bash
|
|
1791
|
+
INPUT=$(cat)
|
|
1792
|
+
|
|
1793
|
+
# Validate input
|
|
1794
|
+
if ! echo "$INPUT" | jq . > /dev/null 2>&1; then
|
|
1795
|
+
echo "Invalid JSON input" >&2
|
|
1796
|
+
exit 2 # Halt workflow
|
|
1797
|
+
fi
|
|
1798
|
+
|
|
1799
|
+
echo "$INPUT" | jq '.data'
|
|
1800
|
+
exit 0
|
|
1801
|
+
```
|
|
1802
|
+
|
|
1803
|
+
### 5.6 Agent-Less Nodes
|
|
1804
|
+
|
|
1805
|
+
Nodes can run pure computation without LLM:
|
|
1806
|
+
|
|
1807
|
+
```ruby
|
|
1808
|
+
node :data_extraction do
|
|
1809
|
+
# No agent - just computation
|
|
1810
|
+
|
|
1811
|
+
input do |ctx|
|
|
1812
|
+
# Input transformer runs as normal
|
|
1813
|
+
ctx.content
|
|
1814
|
+
end
|
|
1815
|
+
|
|
1816
|
+
# The "execution" is just passing through
|
|
1817
|
+
|
|
1818
|
+
output do |ctx|
|
|
1819
|
+
# Output transformer does the work
|
|
1820
|
+
data = ctx.content
|
|
1821
|
+
extract_key_metrics(data)
|
|
1822
|
+
end
|
|
1823
|
+
end
|
|
1824
|
+
|
|
1825
|
+
def extract_key_metrics(text)
|
|
1826
|
+
{
|
|
1827
|
+
word_count: text.split.size,
|
|
1828
|
+
line_count: text.lines.size,
|
|
1829
|
+
char_count: text.length
|
|
1830
|
+
}.to_json
|
|
1831
|
+
end
|
|
1832
|
+
```
|
|
1833
|
+
|
|
1834
|
+
**Output transformer with bash**:
|
|
1835
|
+
```ruby
|
|
1836
|
+
node :json_processing do
|
|
1837
|
+
output_command "jq '.items[] | {id, name}'"
|
|
1838
|
+
end
|
|
1839
|
+
```
|
|
1840
|
+
|
|
1841
|
+
**When to use agent-less nodes**:
|
|
1842
|
+
- Data transformation
|
|
1843
|
+
- Format conversion
|
|
1844
|
+
- Validation
|
|
1845
|
+
- Extraction
|
|
1846
|
+
- Any non-LLM computation
|
|
1847
|
+
|
|
1848
|
+
**Cost savings**: Agent-less nodes consume no tokens or API calls.
|
|
1849
|
+
|
|
1850
|
+
### 5.7 NodeContext API
|
|
1851
|
+
|
|
1852
|
+
Access comprehensive workflow state:
|
|
1853
|
+
|
|
1854
|
+
**Multiple dependencies**:
|
|
1855
|
+
```ruby
|
|
1856
|
+
node :merge do
|
|
1857
|
+
agent(:merger)
|
|
1858
|
+
depends_on :frontend, :backend
|
|
1859
|
+
|
|
1860
|
+
input do |ctx|
|
|
1861
|
+
# previous_result is a hash for multiple dependencies
|
|
1862
|
+
frontend_result = ctx.all_results[:frontend]
|
|
1863
|
+
backend_result = ctx.all_results[:backend]
|
|
1864
|
+
|
|
1865
|
+
"Merge these components:\n\nFrontend:\n#{frontend_result.content}\n\nBackend:\n#{backend_result.content}"
|
|
1866
|
+
end
|
|
1867
|
+
end
|
|
1868
|
+
```
|
|
1869
|
+
|
|
1870
|
+
**Access any previous node**:
|
|
1871
|
+
```ruby
|
|
1872
|
+
output do |ctx|
|
|
1873
|
+
# Access specific node results
|
|
1874
|
+
planning_content = ctx.all_results[:planning].content
|
|
1875
|
+
|
|
1876
|
+
# Include original prompt
|
|
1877
|
+
"Completed: #{ctx.original_prompt}\n\nPlan was: #{planning_content}\n\nResult: #{ctx.content}"
|
|
1878
|
+
end
|
|
1879
|
+
```
|
|
1880
|
+
|
|
1881
|
+
**Check previous node success**:
|
|
1882
|
+
```ruby
|
|
1883
|
+
input do |ctx|
|
|
1884
|
+
if ctx.previous_result.success?
|
|
1885
|
+
ctx.content
|
|
1886
|
+
else
|
|
1887
|
+
"Previous step failed, attempting recovery: #{ctx.previous_result.error.message}"
|
|
1888
|
+
end
|
|
1889
|
+
end
|
|
1890
|
+
```
|
|
1891
|
+
|
|
1892
|
+
### 5.8 Complex Workflow Example
|
|
1893
|
+
|
|
1894
|
+
**Multi-stage development pipeline**:
|
|
1895
|
+
|
|
1896
|
+
```ruby
|
|
1897
|
+
swarm = SwarmSDK.build do
|
|
1898
|
+
name "Full Development Pipeline"
|
|
1899
|
+
|
|
1900
|
+
# Define all agents
|
|
1901
|
+
agent :product_manager do
|
|
1902
|
+
description "Product manager"
|
|
1903
|
+
model "gpt-4"
|
|
1904
|
+
system_prompt "Define requirements and priorities"
|
|
1905
|
+
end
|
|
1906
|
+
|
|
1907
|
+
agent :architect do
|
|
1908
|
+
description "Software architect"
|
|
1909
|
+
model "gpt-4"
|
|
1910
|
+
system_prompt "Design system architecture"
|
|
1911
|
+
end
|
|
1912
|
+
|
|
1913
|
+
agent :backend_dev do
|
|
1914
|
+
description "Backend developer"
|
|
1915
|
+
model "gpt-4"
|
|
1916
|
+
system_prompt "Implement backend services"
|
|
1917
|
+
tools :Write, :Edit
|
|
1918
|
+
end
|
|
1919
|
+
|
|
1920
|
+
agent :frontend_dev do
|
|
1921
|
+
description "Frontend developer"
|
|
1922
|
+
model "gpt-4"
|
|
1923
|
+
system_prompt "Implement user interface"
|
|
1924
|
+
tools :Write, :Edit
|
|
1925
|
+
end
|
|
1926
|
+
|
|
1927
|
+
agent :qa_engineer do
|
|
1928
|
+
description "QA engineer"
|
|
1929
|
+
model "claude-sonnet-4"
|
|
1930
|
+
system_prompt "Test and verify implementation"
|
|
1931
|
+
tools :Write, :Bash
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
# Stage 1: Requirements gathering
|
|
1935
|
+
node :requirements do
|
|
1936
|
+
agent(:product_manager)
|
|
1937
|
+
|
|
1938
|
+
output do |ctx|
|
|
1939
|
+
# Extract structured requirements
|
|
1940
|
+
requirements = ctx.content
|
|
1941
|
+
{
|
|
1942
|
+
functional: extract_section(requirements, "Functional Requirements"),
|
|
1943
|
+
nonfunctional: extract_section(requirements, "Non-Functional Requirements"),
|
|
1944
|
+
priority: extract_section(requirements, "Priority")
|
|
1945
|
+
}.to_json
|
|
1946
|
+
end
|
|
1947
|
+
end
|
|
1948
|
+
|
|
1949
|
+
# Stage 2: Architecture design
|
|
1950
|
+
node :architecture do
|
|
1951
|
+
agent(:architect)
|
|
1952
|
+
depends_on :requirements
|
|
1953
|
+
|
|
1954
|
+
input do |ctx|
|
|
1955
|
+
reqs = JSON.parse(ctx.content)
|
|
1956
|
+
"Design architecture for these requirements:\n\n#{reqs['functional']}"
|
|
1957
|
+
end
|
|
1958
|
+
end
|
|
1959
|
+
|
|
1960
|
+
# Stage 3a: Backend implementation
|
|
1961
|
+
node :backend do
|
|
1962
|
+
agent(:backend_dev)
|
|
1963
|
+
depends_on :architecture
|
|
1964
|
+
|
|
1965
|
+
input do |ctx|
|
|
1966
|
+
arch = ctx.content
|
|
1967
|
+
"Implement backend based on this architecture:\n#{arch}\n\nFocus on API endpoints."
|
|
1968
|
+
end
|
|
1969
|
+
end
|
|
1970
|
+
|
|
1971
|
+
# Stage 3b: Frontend implementation
|
|
1972
|
+
node :frontend do
|
|
1973
|
+
agent(:frontend_dev)
|
|
1974
|
+
depends_on :architecture
|
|
1975
|
+
|
|
1976
|
+
input do |ctx|
|
|
1977
|
+
arch = ctx.content
|
|
1978
|
+
"Implement frontend based on this architecture:\n#{arch}\n\nFocus on user flows."
|
|
1979
|
+
end
|
|
1980
|
+
end
|
|
1981
|
+
|
|
1982
|
+
# Stage 4: Integration testing
|
|
1983
|
+
node :testing do
|
|
1984
|
+
agent(:qa_engineer)
|
|
1985
|
+
depends_on :backend, :frontend
|
|
1986
|
+
|
|
1987
|
+
input do |ctx|
|
|
1988
|
+
backend = ctx.all_results[:backend].content
|
|
1989
|
+
frontend = ctx.all_results[:frontend].content
|
|
1990
|
+
|
|
1991
|
+
"Test integration:\n\nBackend endpoints: #{extract_endpoints(backend)}\n\nFrontend flows: #{extract_flows(frontend)}"
|
|
1992
|
+
end
|
|
1993
|
+
end
|
|
1994
|
+
|
|
1995
|
+
# Stage 5: Final report (agent-less)
|
|
1996
|
+
node :report do
|
|
1997
|
+
depends_on :testing
|
|
1998
|
+
|
|
1999
|
+
output do |ctx|
|
|
2000
|
+
testing_result = ctx.content
|
|
2001
|
+
requirements = ctx.all_results[:requirements].content
|
|
2002
|
+
|
|
2003
|
+
generate_project_report(
|
|
2004
|
+
requirements: requirements,
|
|
2005
|
+
testing: testing_result,
|
|
2006
|
+
original_task: ctx.original_prompt
|
|
2007
|
+
)
|
|
2008
|
+
end
|
|
2009
|
+
end
|
|
2010
|
+
|
|
2011
|
+
start_node :requirements
|
|
2012
|
+
end
|
|
2013
|
+
|
|
2014
|
+
result = swarm.execute("Build a task management application")
|
|
2015
|
+
```
|
|
2016
|
+
|
|
2017
|
+
**Execution**:
|
|
2018
|
+
1. Requirements → Product manager gathers requirements
|
|
2019
|
+
2. Architecture → Architect designs system (receives requirements)
|
|
2020
|
+
3. Backend + Frontend → Parallel implementation (both receive architecture)
|
|
2021
|
+
4. Testing → QA tests integration (receives both implementations)
|
|
2022
|
+
5. Report → Generates final report (agent-less, receives all results)
|
|
2023
|
+
|
|
2024
|
+
---
|
|
2025
|
+
|
|
2026
|
+
## Part 6: Advanced Configuration
|
|
2027
|
+
|
|
2028
|
+
### 6.1 MCP Server Integration
|
|
2029
|
+
|
|
2030
|
+
Connect to external tools and services using Model Context Protocol:
|
|
2031
|
+
|
|
2032
|
+
**stdio transport** (local processes):
|
|
2033
|
+
```ruby
|
|
2034
|
+
agent :filesystem_user do
|
|
2035
|
+
description "Uses filesystem MCP server"
|
|
2036
|
+
model "gpt-4"
|
|
2037
|
+
system_prompt "You can access files via MCP"
|
|
2038
|
+
|
|
2039
|
+
mcp_server :filesystem,
|
|
2040
|
+
type: :stdio,
|
|
2041
|
+
command: "npx",
|
|
2042
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"]
|
|
2043
|
+
end
|
|
2044
|
+
```
|
|
2045
|
+
|
|
2046
|
+
**YAML equivalent**:
|
|
2047
|
+
```yaml
|
|
2048
|
+
filesystem_user:
|
|
2049
|
+
description: "Uses filesystem MCP server"
|
|
2050
|
+
model: "gpt-4"
|
|
2051
|
+
system_prompt: "You can access files via MCP"
|
|
2052
|
+
mcp_servers:
|
|
2053
|
+
- name: filesystem
|
|
2054
|
+
type: stdio
|
|
2055
|
+
command: npx
|
|
2056
|
+
args:
|
|
2057
|
+
- "-y"
|
|
2058
|
+
- "@modelcontextprotocol/server-filesystem"
|
|
2059
|
+
- "/allowed/path"
|
|
2060
|
+
```
|
|
2061
|
+
|
|
2062
|
+
**SSE transport** (server-sent events):
|
|
2063
|
+
```ruby
|
|
2064
|
+
mcp_server :web_service,
|
|
2065
|
+
type: :sse,
|
|
2066
|
+
url: "https://api.example.com/mcp",
|
|
2067
|
+
headers: {
|
|
2068
|
+
authorization: "Bearer #{ENV['API_TOKEN']}"
|
|
2069
|
+
}
|
|
2070
|
+
```
|
|
2071
|
+
|
|
2072
|
+
**HTTP transport** (streamable):
|
|
2073
|
+
```yaml
|
|
2074
|
+
mcp_servers:
|
|
2075
|
+
- name: api_service
|
|
2076
|
+
type: http
|
|
2077
|
+
url: "https://api.example.com/mcp"
|
|
2078
|
+
timeout: 60
|
|
2079
|
+
```
|
|
2080
|
+
|
|
2081
|
+
**Tool access**: MCP tools are available as `mcp__server_name__tool_name`:
|
|
2082
|
+
```
|
|
2083
|
+
# Agent can call:
|
|
2084
|
+
mcp__filesystem__read_file(path: "/allowed/path/file.txt")
|
|
2085
|
+
mcp__web_service__search(query: "...")
|
|
2086
|
+
```
|
|
2087
|
+
|
|
2088
|
+
### 6.2 Custom Providers and Base URLs
|
|
2089
|
+
|
|
2090
|
+
Use custom LLM providers:
|
|
2091
|
+
|
|
2092
|
+
**OpenRouter**:
|
|
2093
|
+
```ruby
|
|
2094
|
+
agent :openrouter_agent do
|
|
2095
|
+
description "Uses OpenRouter"
|
|
2096
|
+
model "anthropic/claude-3-opus"
|
|
2097
|
+
provider "openai" # OpenRouter is OpenAI-compatible
|
|
2098
|
+
base_url "https://openrouter.ai/api/v1"
|
|
2099
|
+
headers authorization: "Bearer #{ENV['OPENROUTER_KEY']}"
|
|
2100
|
+
end
|
|
2101
|
+
```
|
|
2102
|
+
|
|
2103
|
+
**Local LLM (Ollama)**:
|
|
2104
|
+
```yaml
|
|
2105
|
+
local_agent:
|
|
2106
|
+
description: "Local LLM via Ollama"
|
|
2107
|
+
model: "llama2"
|
|
2108
|
+
provider: "openai"
|
|
2109
|
+
base_url: "http://localhost:11434/v1"
|
|
2110
|
+
assume_model_exists: true # Skip model validation
|
|
2111
|
+
```
|
|
2112
|
+
|
|
2113
|
+
**Custom proxy**:
|
|
2114
|
+
```ruby
|
|
2115
|
+
agent :proxied do
|
|
2116
|
+
description "Through corporate proxy"
|
|
2117
|
+
model "gpt-4"
|
|
2118
|
+
provider "openai"
|
|
2119
|
+
base_url "https://internal-proxy.company.com/openai/v1"
|
|
2120
|
+
headers {
|
|
2121
|
+
"X-API-Key" => ENV['INTERNAL_KEY'],
|
|
2122
|
+
"X-Department" => "engineering"
|
|
2123
|
+
}
|
|
2124
|
+
end
|
|
2125
|
+
```
|
|
2126
|
+
|
|
2127
|
+
**When to use base_url**: Custom deployments, proxies, local models, alternative providers.
|
|
2128
|
+
|
|
2129
|
+
### 6.3 Context Window Management
|
|
2130
|
+
|
|
2131
|
+
**Override context window**:
|
|
2132
|
+
```ruby
|
|
2133
|
+
agent :large_context do
|
|
2134
|
+
description "Large context agent"
|
|
2135
|
+
model "gpt-4-turbo"
|
|
2136
|
+
context_window 128000 # Override default
|
|
2137
|
+
end
|
|
2138
|
+
```
|
|
2139
|
+
|
|
2140
|
+
**Why override**: Custom models, fine-tuned models, or correcting registry info.
|
|
2141
|
+
|
|
2142
|
+
**Context warnings**:
|
|
2143
|
+
SwarmSDK automatically warns when context usage crosses thresholds (80%, 90%):
|
|
2144
|
+
|
|
2145
|
+
```ruby
|
|
2146
|
+
all_agents do
|
|
2147
|
+
hook :context_warning do |ctx|
|
|
2148
|
+
percentage = ctx.metadata[:percentage].to_f
|
|
2149
|
+
|
|
2150
|
+
case
|
|
2151
|
+
when percentage > 90
|
|
2152
|
+
puts "🚨 Critical: #{percentage}% context used"
|
|
2153
|
+
SwarmSDK::Hooks::Result.finish_agent("Context limit reached")
|
|
2154
|
+
when percentage > 80
|
|
2155
|
+
puts "⚠️ Warning: #{percentage}% context used"
|
|
2156
|
+
else
|
|
2157
|
+
puts "ℹ️ Info: #{percentage}% context used"
|
|
2158
|
+
end
|
|
2159
|
+
end
|
|
2160
|
+
end
|
|
2161
|
+
```
|
|
2162
|
+
|
|
2163
|
+
### 6.4 Context Compaction
|
|
2164
|
+
|
|
2165
|
+
SwarmSDK can automatically compact context when approaching limits:
|
|
2166
|
+
|
|
2167
|
+
**Enable compaction** (planned feature):
|
|
2168
|
+
```ruby
|
|
2169
|
+
agent :auto_compacting do
|
|
2170
|
+
description "Auto-compacts context"
|
|
2171
|
+
model "gpt-4"
|
|
2172
|
+
context_compaction enabled: true, threshold: 80
|
|
2173
|
+
end
|
|
2174
|
+
```
|
|
2175
|
+
|
|
2176
|
+
**Manual compaction strategies**:
|
|
2177
|
+
|
|
2178
|
+
1. **Summarize old messages**:
|
|
2179
|
+
```ruby
|
|
2180
|
+
hook :context_warning do |ctx|
|
|
2181
|
+
if ctx.metadata[:percentage].to_f > 80
|
|
2182
|
+
# Summarize conversation history
|
|
2183
|
+
SwarmSDK::Hooks::Result.replace("Summary: #{summarize(ctx.metadata[:history])}")
|
|
2184
|
+
end
|
|
2185
|
+
end
|
|
2186
|
+
```
|
|
2187
|
+
|
|
2188
|
+
2. **Remove intermediate tool calls**:
|
|
2189
|
+
```ruby
|
|
2190
|
+
hook :agent_step do |ctx|
|
|
2191
|
+
# Keep only final response, remove intermediate steps
|
|
2192
|
+
if ctx.metadata[:message_count] > 20
|
|
2193
|
+
SwarmSDK::Hooks::Result.finish_agent("Compacting context")
|
|
2194
|
+
end
|
|
2195
|
+
end
|
|
2196
|
+
```
|
|
2197
|
+
|
|
2198
|
+
### 6.5 Rate Limiting
|
|
2199
|
+
|
|
2200
|
+
Control API concurrency per agent:
|
|
2201
|
+
|
|
2202
|
+
**Per-agent concurrency**:
|
|
2203
|
+
```ruby
|
|
2204
|
+
agent :parallel_worker do
|
|
2205
|
+
description "Parallel task worker"
|
|
2206
|
+
model "gpt-4"
|
|
2207
|
+
max_concurrent_tools 5 # Max 5 concurrent tool calls for this agent
|
|
2208
|
+
end
|
|
2209
|
+
```
|
|
2210
|
+
|
|
2211
|
+
**YAML**:
|
|
2212
|
+
```yaml
|
|
2213
|
+
parallel_worker:
|
|
2214
|
+
description: "Parallel task worker"
|
|
2215
|
+
model: "gpt-4"
|
|
2216
|
+
max_concurrent_tools: 5
|
|
2217
|
+
```
|
|
2218
|
+
|
|
2219
|
+
**Default values**:
|
|
2220
|
+
- Global concurrency: 50 concurrent API calls (across entire swarm)
|
|
2221
|
+
- Local concurrency: 10 concurrent tools per agent
|
|
2222
|
+
|
|
2223
|
+
**When to adjust**:
|
|
2224
|
+
- Lower `max_concurrent_tools` for rate-limited APIs
|
|
2225
|
+
- Higher for better parallelism (if API supports it)
|
|
2226
|
+
- Tune based on API quotas and performance
|
|
2227
|
+
|
|
2228
|
+
**Note**: Global concurrency cannot be configured via DSL or YAML - it uses the default of 50. For per-agent control, use `max_concurrent_tools`.
|
|
2229
|
+
|
|
2230
|
+
### 6.6 Timeout Configuration
|
|
2231
|
+
|
|
2232
|
+
Control how long operations can run:
|
|
2233
|
+
|
|
2234
|
+
```ruby
|
|
2235
|
+
agent :quick_responder do
|
|
2236
|
+
description "Fast responses required"
|
|
2237
|
+
model "gpt-4"
|
|
2238
|
+
timeout 30 # 30 second timeout for LLM calls
|
|
2239
|
+
end
|
|
2240
|
+
```
|
|
2241
|
+
|
|
2242
|
+
**Default timeout**: 300 seconds (5 minutes)
|
|
2243
|
+
|
|
2244
|
+
**When to adjust**:
|
|
2245
|
+
- Lower for simple tasks requiring quick responses
|
|
2246
|
+
- Higher for reasoning models (o1, etc.) that think longer
|
|
2247
|
+
- Set based on task complexity
|
|
2248
|
+
|
|
2249
|
+
### 6.7 LLM Parameters
|
|
2250
|
+
|
|
2251
|
+
Tune model behavior:
|
|
2252
|
+
|
|
2253
|
+
**Temperature and top_p**:
|
|
2254
|
+
```ruby
|
|
2255
|
+
agent :creative do
|
|
2256
|
+
description "Creative writer"
|
|
2257
|
+
model "gpt-4"
|
|
2258
|
+
parameters temperature: 1.5, top_p: 0.95
|
|
2259
|
+
end
|
|
2260
|
+
|
|
2261
|
+
agent :analytical do
|
|
2262
|
+
description "Analytical thinker"
|
|
2263
|
+
model "claude-sonnet-4"
|
|
2264
|
+
parameters temperature: 0.3, top_p: 0.9
|
|
2265
|
+
end
|
|
2266
|
+
```
|
|
2267
|
+
|
|
2268
|
+
**YAML**:
|
|
2269
|
+
```yaml
|
|
2270
|
+
creative:
|
|
2271
|
+
description: "Creative writer"
|
|
2272
|
+
model: "gpt-4"
|
|
2273
|
+
parameters:
|
|
2274
|
+
temperature: 1.5
|
|
2275
|
+
top_p: 0.95
|
|
2276
|
+
max_tokens: 4000
|
|
2277
|
+
```
|
|
2278
|
+
|
|
2279
|
+
**Common parameters**:
|
|
2280
|
+
- `temperature` (0.0-2.0): Randomness (higher = more creative)
|
|
2281
|
+
- `top_p` (0.0-1.0): Diversity (higher = more diverse)
|
|
2282
|
+
- `max_tokens`: Response length limit
|
|
2283
|
+
- `presence_penalty`, `frequency_penalty`: Repetition control
|
|
2284
|
+
|
|
2285
|
+
**Parameter effects**:
|
|
2286
|
+
```
|
|
2287
|
+
Temperature 0.0-0.3 → Deterministic, focused, consistent
|
|
2288
|
+
Temperature 0.7-1.0 → Balanced, natural
|
|
2289
|
+
Temperature 1.2-2.0 → Creative, diverse, unpredictable
|
|
2290
|
+
```
|
|
2291
|
+
|
|
2292
|
+
### 6.8 API Versions (Responses API)
|
|
2293
|
+
|
|
2294
|
+
Use Anthropic's Responses API (extended thinking):
|
|
2295
|
+
|
|
2296
|
+
```ruby
|
|
2297
|
+
agent :deep_thinker do
|
|
2298
|
+
description "Deep reasoning agent"
|
|
2299
|
+
model "claude-sonnet-4"
|
|
2300
|
+
provider "anthropic"
|
|
2301
|
+
api_version "v1/responses" # Use Responses API
|
|
2302
|
+
parameters thinking: { type: "enabled", budget_tokens: 10000 }
|
|
2303
|
+
end
|
|
2304
|
+
```
|
|
2305
|
+
|
|
2306
|
+
**YAML**:
|
|
2307
|
+
```yaml
|
|
2308
|
+
deep_thinker:
|
|
2309
|
+
description: "Deep reasoning agent"
|
|
2310
|
+
model: "claude-sonnet-4"
|
|
2311
|
+
provider: "anthropic"
|
|
2312
|
+
api_version: "v1/responses"
|
|
2313
|
+
parameters:
|
|
2314
|
+
thinking:
|
|
2315
|
+
type: "enabled"
|
|
2316
|
+
budget_tokens: 10000
|
|
2317
|
+
```
|
|
2318
|
+
|
|
2319
|
+
**When to use**: Tasks requiring extended reasoning, complex problem-solving.
|
|
2320
|
+
|
|
2321
|
+
**Note**: Only works with compatible providers (Anthropic).
|
|
2322
|
+
|
|
2323
|
+
### 6.9 Assume Model Exists
|
|
2324
|
+
|
|
2325
|
+
Skip model validation for custom/unknown models:
|
|
2326
|
+
|
|
2327
|
+
```ruby
|
|
2328
|
+
agent :custom_model do
|
|
2329
|
+
description "Uses custom model"
|
|
2330
|
+
model "my-finetuned-gpt-4"
|
|
2331
|
+
provider "openai"
|
|
2332
|
+
base_url "https://api.example.com/v1"
|
|
2333
|
+
assume_model_exists true # Don't validate model
|
|
2334
|
+
end
|
|
2335
|
+
```
|
|
2336
|
+
|
|
2337
|
+
**When to use**:
|
|
2338
|
+
- Custom fine-tuned models
|
|
2339
|
+
- Local models
|
|
2340
|
+
- New models not in SwarmSDK registry
|
|
2341
|
+
- Proxy with model name translation
|
|
2342
|
+
|
|
2343
|
+
**Trade-off**: Disables context tracking and model-specific optimizations.
|
|
2344
|
+
|
|
2345
|
+
---
|
|
2346
|
+
|
|
2347
|
+
## Part 7: Production Features
|
|
2348
|
+
|
|
2349
|
+
### 7.1 Structured Logging
|
|
2350
|
+
|
|
2351
|
+
SwarmSDK emits structured JSON logs for all events:
|
|
2352
|
+
|
|
2353
|
+
```ruby
|
|
2354
|
+
result = swarm.execute("Build API") do |log_entry|
|
|
2355
|
+
# log_entry is a hash with structured data
|
|
2356
|
+
case log_entry[:type]
|
|
2357
|
+
when "swarm_start"
|
|
2358
|
+
logger.info("Swarm started: #{log_entry[:swarm_name]}")
|
|
2359
|
+
|
|
2360
|
+
when "agent_step"
|
|
2361
|
+
logger.info("Agent #{log_entry[:agent]} made #{log_entry[:tool_calls].size} tool calls")
|
|
2362
|
+
|
|
2363
|
+
when "tool_call"
|
|
2364
|
+
logger.debug("Tool: #{log_entry[:tool]} with #{log_entry[:arguments]}")
|
|
2365
|
+
|
|
2366
|
+
when "agent_stop"
|
|
2367
|
+
logger.info("Agent #{log_entry[:agent]} completed")
|
|
2368
|
+
end
|
|
2369
|
+
end
|
|
2370
|
+
```
|
|
2371
|
+
|
|
2372
|
+
**Log types**:
|
|
2373
|
+
- `swarm_start`, `swarm_stop` - Swarm lifecycle
|
|
2374
|
+
- `user_prompt` - User messages
|
|
2375
|
+
- `agent_step`, `agent_stop` - Agent responses
|
|
2376
|
+
- `tool_call`, `tool_result` - Tool execution
|
|
2377
|
+
- `agent_delegation`, `delegation_result`, `delegation_error` - Agent delegation
|
|
2378
|
+
- `node_start`, `node_stop` - Node workflow stages
|
|
2379
|
+
- `model_lookup_warning` - Model validation issues
|
|
2380
|
+
- `context_limit_warning` - Context usage warnings
|
|
2381
|
+
|
|
2382
|
+
**Log entry structure**:
|
|
2383
|
+
```ruby
|
|
2384
|
+
{
|
|
2385
|
+
type: "agent_step",
|
|
2386
|
+
agent: "backend",
|
|
2387
|
+
model: "gpt-4",
|
|
2388
|
+
content: "I'll implement the API...",
|
|
2389
|
+
tool_calls: [
|
|
2390
|
+
{id: "call_123", name: "Write", arguments: {...}}
|
|
2391
|
+
],
|
|
2392
|
+
usage: {
|
|
2393
|
+
prompt_tokens: 1200,
|
|
2394
|
+
completion_tokens: 450,
|
|
2395
|
+
total_tokens: 1650,
|
|
2396
|
+
cost: 0.0825
|
|
2397
|
+
},
|
|
2398
|
+
timestamp: "2024-01-15T10:30:45Z"
|
|
2399
|
+
}
|
|
2400
|
+
```
|
|
2401
|
+
|
|
2402
|
+
### 7.2 Token Usage and Cost Tracking
|
|
2403
|
+
|
|
2404
|
+
Track usage and costs per agent:
|
|
2405
|
+
|
|
2406
|
+
```ruby
|
|
2407
|
+
result = swarm.execute("Task")
|
|
2408
|
+
|
|
2409
|
+
# Overall metrics
|
|
2410
|
+
puts "Total tokens: #{result.total_tokens}"
|
|
2411
|
+
puts "Total cost: $#{result.total_cost}"
|
|
2412
|
+
puts "LLM requests: #{result.llm_requests}"
|
|
2413
|
+
puts "Tool calls: #{result.tool_calls_count}"
|
|
2414
|
+
puts "Duration: #{result.duration}s"
|
|
2415
|
+
|
|
2416
|
+
# Agent breakdown (from logs)
|
|
2417
|
+
result.logs.select { |log| log[:type] == "agent_stop" }.each do |log|
|
|
2418
|
+
agent = log[:agent]
|
|
2419
|
+
usage = log[:usage]
|
|
2420
|
+
puts "#{agent}: #{usage[:total_tokens]} tokens, $#{usage[:cost]}"
|
|
2421
|
+
end
|
|
2422
|
+
```
|
|
2423
|
+
|
|
2424
|
+
**Real-time tracking**:
|
|
2425
|
+
```ruby
|
|
2426
|
+
total_cost = 0.0
|
|
2427
|
+
|
|
2428
|
+
swarm.execute("Task") do |log|
|
|
2429
|
+
if log[:usage]
|
|
2430
|
+
total_cost += log[:usage][:cost]
|
|
2431
|
+
puts "Running cost: $#{total_cost.round(4)}"
|
|
2432
|
+
end
|
|
2433
|
+
end
|
|
2434
|
+
```
|
|
2435
|
+
|
|
2436
|
+
**Cost optimization tips**:
|
|
2437
|
+
- Use smaller models for simple tasks (claude-haiku vs opus)
|
|
2438
|
+
- Lower temperature reduces token usage
|
|
2439
|
+
- Set max_tokens to limit responses
|
|
2440
|
+
- Use agent-less nodes for computation
|
|
2441
|
+
- Cache results in scratchpad
|
|
2442
|
+
|
|
2443
|
+
### 7.3 Error Handling and Recovery
|
|
2444
|
+
|
|
2445
|
+
Handle errors gracefully:
|
|
2446
|
+
|
|
2447
|
+
```ruby
|
|
2448
|
+
result = swarm.execute("Task")
|
|
2449
|
+
|
|
2450
|
+
if result.success?
|
|
2451
|
+
puts result.content
|
|
2452
|
+
else
|
|
2453
|
+
error = result.error
|
|
2454
|
+
|
|
2455
|
+
case error
|
|
2456
|
+
when SwarmSDK::ConfigurationError
|
|
2457
|
+
puts "Configuration error: #{error.message}"
|
|
2458
|
+
# Fix config and retry
|
|
2459
|
+
|
|
2460
|
+
when SwarmSDK::ToolExecutionError
|
|
2461
|
+
puts "Tool execution error: #{error.message}"
|
|
2462
|
+
# Check permissions or tool configuration
|
|
2463
|
+
|
|
2464
|
+
when SwarmSDK::LLMError
|
|
2465
|
+
puts "LLM API error: #{error.message}"
|
|
2466
|
+
# Check API key, connectivity
|
|
2467
|
+
|
|
2468
|
+
else
|
|
2469
|
+
puts "Unexpected error: #{error.message}"
|
|
2470
|
+
puts error.backtrace
|
|
2471
|
+
end
|
|
2472
|
+
end
|
|
2473
|
+
```
|
|
2474
|
+
|
|
2475
|
+
**Error recovery strategies**:
|
|
2476
|
+
|
|
2477
|
+
1. **Retry with backoff**:
|
|
2478
|
+
```ruby
|
|
2479
|
+
def execute_with_retry(swarm, prompt, max_attempts: 3)
|
|
2480
|
+
attempts = 0
|
|
2481
|
+
|
|
2482
|
+
loop do
|
|
2483
|
+
attempts += 1
|
|
2484
|
+
result = swarm.execute(prompt)
|
|
2485
|
+
|
|
2486
|
+
return result if result.success?
|
|
2487
|
+
|
|
2488
|
+
if attempts >= max_attempts
|
|
2489
|
+
puts "Failed after #{attempts} attempts"
|
|
2490
|
+
return result
|
|
2491
|
+
end
|
|
2492
|
+
|
|
2493
|
+
puts "Attempt #{attempts} failed, retrying..."
|
|
2494
|
+
sleep(2 ** attempts) # Exponential backoff
|
|
2495
|
+
end
|
|
2496
|
+
end
|
|
2497
|
+
```
|
|
2498
|
+
|
|
2499
|
+
2. **Fallback to simpler agent**:
|
|
2500
|
+
```ruby
|
|
2501
|
+
result = swarm.execute("Complex task")
|
|
2502
|
+
|
|
2503
|
+
# Check error message for context-related issues
|
|
2504
|
+
if !result.success? && result.error.message.include?("context")
|
|
2505
|
+
puts "Context limit reached, trying simpler agent"
|
|
2506
|
+
result = simple_swarm.execute("Simplified task")
|
|
2507
|
+
end
|
|
2508
|
+
```
|
|
2509
|
+
|
|
2510
|
+
3. **Hook-based recovery**:
|
|
2511
|
+
```ruby
|
|
2512
|
+
all_agents do
|
|
2513
|
+
hook :agent_stop do |ctx|
|
|
2514
|
+
if ctx.metadata[:finish_reason] == "max_tokens"
|
|
2515
|
+
SwarmSDK::Hooks::Result.reprompt("Continue your response")
|
|
2516
|
+
end
|
|
2517
|
+
end
|
|
2518
|
+
end
|
|
2519
|
+
```
|
|
2520
|
+
|
|
2521
|
+
### 7.4 Validation and Warnings
|
|
2522
|
+
|
|
2523
|
+
SwarmSDK validates configurations and emits warnings:
|
|
2524
|
+
|
|
2525
|
+
```ruby
|
|
2526
|
+
swarm = SwarmSDK::Swarm.load("config.yml")
|
|
2527
|
+
|
|
2528
|
+
# Check for warnings
|
|
2529
|
+
warnings = swarm.validate
|
|
2530
|
+
|
|
2531
|
+
warnings.each do |warning|
|
|
2532
|
+
case warning[:type]
|
|
2533
|
+
when :model_not_found
|
|
2534
|
+
puts "⚠️ Agent '#{warning[:agent]}' uses unknown model '#{warning[:model]}'"
|
|
2535
|
+
puts " Suggestions: #{warning[:suggestions].map { |s| s[:id] }.join(", ")}"
|
|
2536
|
+
end
|
|
2537
|
+
end
|
|
2538
|
+
```
|
|
2539
|
+
|
|
2540
|
+
**Warnings are non-fatal**: Swarm still executes, but you're informed of potential issues.
|
|
2541
|
+
|
|
2542
|
+
**Common warnings**:
|
|
2543
|
+
- Model not in registry (typo or new model)
|
|
2544
|
+
- Context tracking unavailable
|
|
2545
|
+
- Missing API keys
|
|
2546
|
+
|
|
2547
|
+
### 7.5 Document Conversion
|
|
2548
|
+
|
|
2549
|
+
SwarmSDK can read and convert documents:
|
|
2550
|
+
|
|
2551
|
+
**PDF files**:
|
|
2552
|
+
```ruby
|
|
2553
|
+
agent :pdf_reader do
|
|
2554
|
+
description "PDF analyst"
|
|
2555
|
+
model "gpt-4"
|
|
2556
|
+
system_prompt "Analyze PDF documents"
|
|
2557
|
+
# Read tool includes PDF support
|
|
2558
|
+
end
|
|
2559
|
+
```
|
|
2560
|
+
|
|
2561
|
+
**Agent usage**:
|
|
2562
|
+
```
|
|
2563
|
+
Read(file_path: "report.pdf")
|
|
2564
|
+
# Returns text content extracted from PDF
|
|
2565
|
+
```
|
|
2566
|
+
|
|
2567
|
+
**DOCX files**:
|
|
2568
|
+
```
|
|
2569
|
+
Read(file_path: "document.docx")
|
|
2570
|
+
# Returns text content from Word document
|
|
2571
|
+
```
|
|
2572
|
+
|
|
2573
|
+
**XLSX files**:
|
|
2574
|
+
```
|
|
2575
|
+
Read(file_path: "data.xlsx")
|
|
2576
|
+
# Returns CSV representation of spreadsheet
|
|
2577
|
+
```
|
|
2578
|
+
|
|
2579
|
+
**Image support**:
|
|
2580
|
+
```
|
|
2581
|
+
Read(file_path: "diagram.png")
|
|
2582
|
+
# For models with vision capabilities
|
|
2583
|
+
```
|
|
2584
|
+
|
|
2585
|
+
**Use cases**:
|
|
2586
|
+
- Document analysis
|
|
2587
|
+
- Data extraction from PDFs
|
|
2588
|
+
- Report generation
|
|
2589
|
+
- Contract review
|
|
2590
|
+
|
|
2591
|
+
---
|
|
2592
|
+
|
|
2593
|
+
## Part 8: Best Practices
|
|
2594
|
+
|
|
2595
|
+
### 8.1 When to Use Single Agent vs Multi-Agent
|
|
2596
|
+
|
|
2597
|
+
**Use single agent when**:
|
|
2598
|
+
- Task is simple and focused
|
|
2599
|
+
- One expertise domain
|
|
2600
|
+
- Speed matters (less delegation overhead)
|
|
2601
|
+
- Budget is tight (fewer LLM calls)
|
|
2602
|
+
|
|
2603
|
+
**Example - Single agent**:
|
|
2604
|
+
```ruby
|
|
2605
|
+
swarm = SwarmSDK.build do
|
|
2606
|
+
name "Simple Helper"
|
|
2607
|
+
lead :assistant
|
|
2608
|
+
|
|
2609
|
+
agent :assistant do
|
|
2610
|
+
description "General helper"
|
|
2611
|
+
model "gpt-4"
|
|
2612
|
+
system_prompt "Answer questions and help with tasks"
|
|
2613
|
+
end
|
|
2614
|
+
end
|
|
2615
|
+
```
|
|
2616
|
+
|
|
2617
|
+
**Use multi-agent when**:
|
|
2618
|
+
- Task requires multiple expertise areas
|
|
2619
|
+
- Quality matters more than speed
|
|
2620
|
+
- Different stages need different approaches
|
|
2621
|
+
- Task benefits from review/validation
|
|
2622
|
+
|
|
2623
|
+
**Example - Multi-agent**:
|
|
2624
|
+
```ruby
|
|
2625
|
+
swarm = SwarmSDK.build do
|
|
2626
|
+
name "Code Quality Team"
|
|
2627
|
+
lead :developer
|
|
2628
|
+
|
|
2629
|
+
agent :developer do
|
|
2630
|
+
description "Writes code"
|
|
2631
|
+
model "gpt-4"
|
|
2632
|
+
system_prompt "Write clean, well-tested code"
|
|
2633
|
+
tools :Write, :Edit
|
|
2634
|
+
delegates_to :reviewer, :security_checker
|
|
2635
|
+
end
|
|
2636
|
+
|
|
2637
|
+
agent :reviewer do
|
|
2638
|
+
description "Reviews code quality"
|
|
2639
|
+
model "claude-sonnet-4"
|
|
2640
|
+
system_prompt "Check for bugs and improvements"
|
|
2641
|
+
end
|
|
2642
|
+
|
|
2643
|
+
agent :security_checker do
|
|
2644
|
+
description "Security audit"
|
|
2645
|
+
model "claude-opus-4"
|
|
2646
|
+
system_prompt "Find security vulnerabilities"
|
|
2647
|
+
end
|
|
2648
|
+
end
|
|
2649
|
+
```
|
|
2650
|
+
|
|
2651
|
+
### 8.2 Organizing Large Swarms
|
|
2652
|
+
|
|
2653
|
+
**Strategy 1: Functional Teams**
|
|
2654
|
+
```
|
|
2655
|
+
Lead (Coordinator)
|
|
2656
|
+
├── Development Team
|
|
2657
|
+
│ ├── Backend Dev
|
|
2658
|
+
│ ├── Frontend Dev
|
|
2659
|
+
│ └── Database Specialist
|
|
2660
|
+
├── Quality Team
|
|
2661
|
+
│ ├── Tester
|
|
2662
|
+
│ └── Security Auditor
|
|
2663
|
+
└── Documentation Team
|
|
2664
|
+
└── Technical Writer
|
|
2665
|
+
```
|
|
2666
|
+
|
|
2667
|
+
**Strategy 2: Layered Architecture**
|
|
2668
|
+
```
|
|
2669
|
+
Executive Layer → Strategic decisions
|
|
2670
|
+
Coordination Layer → Task breakdown and planning
|
|
2671
|
+
Execution Layer → Implementation
|
|
2672
|
+
Validation Layer → Testing and review
|
|
2673
|
+
```
|
|
2674
|
+
|
|
2675
|
+
**Strategy 3: Node-Based Pipeline**
|
|
2676
|
+
```
|
|
2677
|
+
Requirements → Design → Implementation → Testing → Deployment
|
|
2678
|
+
(PM) (Arch) (Dev team) (QA) (DevOps)
|
|
2679
|
+
```
|
|
2680
|
+
|
|
2681
|
+
**Configuration structure**:
|
|
2682
|
+
```
|
|
2683
|
+
project/
|
|
2684
|
+
├── swarm.yml # Main swarm config
|
|
2685
|
+
├── agents/ # Agent definitions
|
|
2686
|
+
│ ├── backend.md
|
|
2687
|
+
│ ├── frontend.md
|
|
2688
|
+
│ └── qa.md
|
|
2689
|
+
├── scripts/ # Hook scripts
|
|
2690
|
+
│ ├── validate.sh
|
|
2691
|
+
│ └── notify.sh
|
|
2692
|
+
└── .env # API keys
|
|
2693
|
+
```
|
|
2694
|
+
|
|
2695
|
+
### 8.3 Testing Strategies
|
|
2696
|
+
|
|
2697
|
+
**Unit test agents**:
|
|
2698
|
+
```ruby
|
|
2699
|
+
RSpec.describe "Backend Agent" do
|
|
2700
|
+
let(:swarm) do
|
|
2701
|
+
SwarmSDK.build do
|
|
2702
|
+
name "Test Swarm"
|
|
2703
|
+
lead :backend
|
|
2704
|
+
|
|
2705
|
+
agent :backend do
|
|
2706
|
+
description "Backend dev"
|
|
2707
|
+
model "gpt-4"
|
|
2708
|
+
system_prompt "Write Ruby code"
|
|
2709
|
+
tools :Write
|
|
2710
|
+
end
|
|
2711
|
+
end
|
|
2712
|
+
end
|
|
2713
|
+
|
|
2714
|
+
it "creates files" do
|
|
2715
|
+
result = swarm.execute("Create a User class")
|
|
2716
|
+
|
|
2717
|
+
expect(result.success?).to be true
|
|
2718
|
+
expect(File.exist?("user.rb")).to be true
|
|
2719
|
+
end
|
|
2720
|
+
end
|
|
2721
|
+
```
|
|
2722
|
+
|
|
2723
|
+
**Integration test workflows**:
|
|
2724
|
+
```ruby
|
|
2725
|
+
RSpec.describe "Development Pipeline" do
|
|
2726
|
+
let(:swarm) { SwarmSDK::Swarm.load("swarm.yml") }
|
|
2727
|
+
|
|
2728
|
+
it "completes full workflow" do
|
|
2729
|
+
result = swarm.execute("Build auth system")
|
|
2730
|
+
|
|
2731
|
+
expect(result.success?).to be true
|
|
2732
|
+
# agents_involved returns symbols, not strings
|
|
2733
|
+
expect(result.agents_involved).to include(:planner, :coder, :tester)
|
|
2734
|
+
expect(result.logs.count { |l| l[:type] == "tool_call" }).to be > 0
|
|
2735
|
+
end
|
|
2736
|
+
end
|
|
2737
|
+
```
|
|
2738
|
+
|
|
2739
|
+
**Test hooks**:
|
|
2740
|
+
```ruby
|
|
2741
|
+
it "blocks dangerous commands" do
|
|
2742
|
+
result = swarm.execute("Run rm -rf /")
|
|
2743
|
+
|
|
2744
|
+
expect(result.success?).to be false
|
|
2745
|
+
expect(result.error.message).to include("blocked")
|
|
2746
|
+
end
|
|
2747
|
+
```
|
|
2748
|
+
|
|
2749
|
+
**Mock LLM responses** (for faster tests):
|
|
2750
|
+
```ruby
|
|
2751
|
+
# Use a test double or stub
|
|
2752
|
+
allow(LLM).to receive(:chat).and_return(
|
|
2753
|
+
{content: "Test response", usage: {tokens: 100}}
|
|
2754
|
+
)
|
|
2755
|
+
```
|
|
2756
|
+
|
|
2757
|
+
### 8.4 Performance Optimization
|
|
2758
|
+
|
|
2759
|
+
**1. Choose appropriate models**:
|
|
2760
|
+
```ruby
|
|
2761
|
+
# Fast tasks
|
|
2762
|
+
agent :quick do
|
|
2763
|
+
model "claude-haiku-4" # Fastest, cheapest
|
|
2764
|
+
end
|
|
2765
|
+
|
|
2766
|
+
# Balanced tasks
|
|
2767
|
+
agent :balanced do
|
|
2768
|
+
model "gpt-4" # Good balance
|
|
2769
|
+
end
|
|
2770
|
+
|
|
2771
|
+
# Complex tasks
|
|
2772
|
+
agent :complex do
|
|
2773
|
+
model "claude-opus-4" # Best quality
|
|
2774
|
+
end
|
|
2775
|
+
```
|
|
2776
|
+
|
|
2777
|
+
**2. Use agent-less nodes**:
|
|
2778
|
+
```ruby
|
|
2779
|
+
# Pure computation, no LLM
|
|
2780
|
+
node :data_transform do
|
|
2781
|
+
output do |ctx|
|
|
2782
|
+
JSON.parse(ctx.content).transform_values(&:upcase)
|
|
2783
|
+
end
|
|
2784
|
+
end
|
|
2785
|
+
```
|
|
2786
|
+
|
|
2787
|
+
**3. Parallelize independent work**:
|
|
2788
|
+
```ruby
|
|
2789
|
+
# These run in sequence but are independent
|
|
2790
|
+
node :frontend do
|
|
2791
|
+
agent(:frontend_dev)
|
|
2792
|
+
depends_on :planning
|
|
2793
|
+
end
|
|
2794
|
+
|
|
2795
|
+
node :backend do
|
|
2796
|
+
agent(:backend_dev)
|
|
2797
|
+
depends_on :planning # Same dependency, parallel work
|
|
2798
|
+
end
|
|
2799
|
+
```
|
|
2800
|
+
|
|
2801
|
+
**4. Cache results in scratchpad**:
|
|
2802
|
+
```ruby
|
|
2803
|
+
agent :analyzer do
|
|
2804
|
+
description "Analyzer with caching"
|
|
2805
|
+
model "gpt-4"
|
|
2806
|
+
system_prompt "Check scratchpad before analyzing"
|
|
2807
|
+
|
|
2808
|
+
hook :pre_tool_use, matcher: "ScratchpadRead" do |ctx|
|
|
2809
|
+
# Read cached result
|
|
2810
|
+
cached = ctx.tool_call.parameters[:file_path]
|
|
2811
|
+
puts "Using cached: #{cached}"
|
|
2812
|
+
end
|
|
2813
|
+
end
|
|
2814
|
+
```
|
|
2815
|
+
|
|
2816
|
+
**5. Limit context with transformers**:
|
|
2817
|
+
```ruby
|
|
2818
|
+
node :summarizer do
|
|
2819
|
+
agent(:analyst)
|
|
2820
|
+
depends_on :research
|
|
2821
|
+
|
|
2822
|
+
input do |ctx|
|
|
2823
|
+
# Summarize long research output
|
|
2824
|
+
research = ctx.content
|
|
2825
|
+
research.lines.first(50).join("\n") + "\n\n[... truncated]"
|
|
2826
|
+
end
|
|
2827
|
+
end
|
|
2828
|
+
```
|
|
2829
|
+
|
|
2830
|
+
### 8.5 Security Considerations
|
|
2831
|
+
|
|
2832
|
+
**1. Restrict file access**:
|
|
2833
|
+
```ruby
|
|
2834
|
+
agent :sandboxed do
|
|
2835
|
+
description "Sandboxed agent"
|
|
2836
|
+
model "gpt-4"
|
|
2837
|
+
directory "/safe/sandbox"
|
|
2838
|
+
tools :Write, :Read
|
|
2839
|
+
|
|
2840
|
+
permissions do
|
|
2841
|
+
tool(:Write).allow_paths "output/**"
|
|
2842
|
+
tool(:Write).deny_paths "**/*.sh", "**/.env"
|
|
2843
|
+
end
|
|
2844
|
+
end
|
|
2845
|
+
```
|
|
2846
|
+
|
|
2847
|
+
**2. Block dangerous commands**:
|
|
2848
|
+
```ruby
|
|
2849
|
+
agent :executor do
|
|
2850
|
+
description "Safe executor"
|
|
2851
|
+
model "gpt-4"
|
|
2852
|
+
tools :Bash
|
|
2853
|
+
|
|
2854
|
+
permissions do
|
|
2855
|
+
tool(:Bash).allow_commands "ls", "pwd", "echo", "cat"
|
|
2856
|
+
tool(:Bash).deny_commands "rm", "dd", "sudo", "chmod", "curl"
|
|
2857
|
+
end
|
|
2858
|
+
end
|
|
2859
|
+
```
|
|
2860
|
+
|
|
2861
|
+
**3. Validate agent outputs**:
|
|
2862
|
+
```ruby
|
|
2863
|
+
all_agents do
|
|
2864
|
+
hook :post_tool_use, matcher: "Write" do |ctx|
|
|
2865
|
+
file = ctx.tool_call.parameters[:file_path]
|
|
2866
|
+
content = ctx.tool_call.parameters[:content]
|
|
2867
|
+
|
|
2868
|
+
# Block suspicious patterns
|
|
2869
|
+
if content.include?("eval(") || content.include?("exec(")
|
|
2870
|
+
SwarmSDK::Hooks::Result.halt("Suspicious code pattern detected")
|
|
2871
|
+
end
|
|
2872
|
+
end
|
|
2873
|
+
end
|
|
2874
|
+
```
|
|
2875
|
+
|
|
2876
|
+
**4. Audit all operations**:
|
|
2877
|
+
```ruby
|
|
2878
|
+
all_agents do
|
|
2879
|
+
hook :post_tool_use do |ctx|
|
|
2880
|
+
File.open("audit.log", "a") do |f|
|
|
2881
|
+
f.puts "#{Time.now} | #{ctx.agent_name} | #{ctx.tool_call.name} | #{ctx.tool_call.parameters}"
|
|
2882
|
+
end
|
|
2883
|
+
end
|
|
2884
|
+
end
|
|
2885
|
+
```
|
|
2886
|
+
|
|
2887
|
+
**5. Use separate environments**:
|
|
2888
|
+
```
|
|
2889
|
+
Development: Full access, all tools
|
|
2890
|
+
Staging: Restricted access, validated outputs
|
|
2891
|
+
Production: Minimal access, extensive hooks
|
|
2892
|
+
```
|
|
2893
|
+
|
|
2894
|
+
### 8.6 Cost Management
|
|
2895
|
+
|
|
2896
|
+
**Track costs in real-time**:
|
|
2897
|
+
```ruby
|
|
2898
|
+
max_cost = 1.00 # $1 limit
|
|
2899
|
+
current_cost = 0.0
|
|
2900
|
+
|
|
2901
|
+
swarm.execute("Task") do |log|
|
|
2902
|
+
if log[:usage]
|
|
2903
|
+
current_cost += log[:usage][:cost]
|
|
2904
|
+
|
|
2905
|
+
if current_cost > max_cost
|
|
2906
|
+
puts "Cost limit reached: $#{current_cost}"
|
|
2907
|
+
# Stop execution
|
|
2908
|
+
end
|
|
2909
|
+
end
|
|
2910
|
+
end
|
|
2911
|
+
```
|
|
2912
|
+
|
|
2913
|
+
**Use cost hooks**:
|
|
2914
|
+
```ruby
|
|
2915
|
+
all_agents do
|
|
2916
|
+
hook :agent_step do |ctx|
|
|
2917
|
+
cost = ctx.metadata[:usage][:cost]
|
|
2918
|
+
|
|
2919
|
+
if cost > 0.10 # 10 cents per response
|
|
2920
|
+
SwarmSDK::Hooks::Result.finish_agent("Cost threshold exceeded")
|
|
2921
|
+
end
|
|
2922
|
+
end
|
|
2923
|
+
end
|
|
2924
|
+
```
|
|
2925
|
+
|
|
2926
|
+
**Budget per stage**:
|
|
2927
|
+
```ruby
|
|
2928
|
+
node :expensive_stage do
|
|
2929
|
+
agent(:analyst)
|
|
2930
|
+
|
|
2931
|
+
hook :agent_step do |ctx|
|
|
2932
|
+
if ctx.metadata[:usage][:cost] > 0.50
|
|
2933
|
+
SwarmSDK::Hooks::Result.finish_agent("Stage budget exceeded")
|
|
2934
|
+
end
|
|
2935
|
+
end
|
|
2936
|
+
end
|
|
2937
|
+
```
|
|
2938
|
+
|
|
2939
|
+
**Cost optimization checklist**:
|
|
2940
|
+
- [ ] Use smaller models for simple tasks
|
|
2941
|
+
- [ ] Set max_tokens limits
|
|
2942
|
+
- [ ] Lower temperature (fewer tokens)
|
|
2943
|
+
- [ ] Use agent-less nodes for computation
|
|
2944
|
+
- [ ] Cache results in scratchpad
|
|
2945
|
+
- [ ] Batch similar operations
|
|
2946
|
+
- [ ] Monitor and set cost alerts
|
|
2947
|
+
|
|
2948
|
+
### 8.7 Monitoring and Observability
|
|
2949
|
+
|
|
2950
|
+
**Structured logging to files**:
|
|
2951
|
+
```ruby
|
|
2952
|
+
log_file = File.open("swarm.log", "a")
|
|
2953
|
+
|
|
2954
|
+
swarm.execute("Task") do |log|
|
|
2955
|
+
log_file.puts JSON.generate(log)
|
|
2956
|
+
end
|
|
2957
|
+
|
|
2958
|
+
log_file.close
|
|
2959
|
+
```
|
|
2960
|
+
|
|
2961
|
+
**Send to external service**:
|
|
2962
|
+
```ruby
|
|
2963
|
+
swarm.execute("Task") do |log|
|
|
2964
|
+
case log[:type]
|
|
2965
|
+
when "agent_stop"
|
|
2966
|
+
metrics.track("agent.completion", {
|
|
2967
|
+
agent: log[:agent],
|
|
2968
|
+
duration: log[:usage][:duration],
|
|
2969
|
+
tokens: log[:usage][:total_tokens],
|
|
2970
|
+
cost: log[:usage][:cost]
|
|
2971
|
+
})
|
|
2972
|
+
|
|
2973
|
+
when "tool_call"
|
|
2974
|
+
metrics.increment("tool.#{log[:tool]}.calls")
|
|
2975
|
+
end
|
|
2976
|
+
end
|
|
2977
|
+
```
|
|
2978
|
+
|
|
2979
|
+
**Dashboard metrics**:
|
|
2980
|
+
```ruby
|
|
2981
|
+
# Collect over time
|
|
2982
|
+
{
|
|
2983
|
+
total_executions: 1234,
|
|
2984
|
+
success_rate: 0.95,
|
|
2985
|
+
avg_duration: 45.2,
|
|
2986
|
+
total_cost: 123.45,
|
|
2987
|
+
agent_usage: {
|
|
2988
|
+
backend: 450,
|
|
2989
|
+
frontend: 380,
|
|
2990
|
+
qa: 200
|
|
2991
|
+
},
|
|
2992
|
+
tool_usage: {
|
|
2993
|
+
Write: 890,
|
|
2994
|
+
Read: 1200,
|
|
2995
|
+
Bash: 340
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
```
|
|
2999
|
+
|
|
3000
|
+
### 8.8 Common Patterns Summary
|
|
3001
|
+
|
|
3002
|
+
**Pattern: Code Review Workflow**
|
|
3003
|
+
```
|
|
3004
|
+
Developer → Reviewer → Developer (iterate) → Final approval
|
|
3005
|
+
```
|
|
3006
|
+
|
|
3007
|
+
**Pattern: Research and Implementation**
|
|
3008
|
+
```
|
|
3009
|
+
Researcher (gathers info) → Analyst (processes) → Writer (creates)
|
|
3010
|
+
```
|
|
3011
|
+
|
|
3012
|
+
**Pattern: Multi-Stage Pipeline**
|
|
3013
|
+
```
|
|
3014
|
+
Plan → Design → Implement → Test → Deploy
|
|
3015
|
+
```
|
|
3016
|
+
|
|
3017
|
+
**Pattern: Specialist Pool**
|
|
3018
|
+
```
|
|
3019
|
+
Lead delegates to: Backend, Frontend, Database, Security, DevOps (as needed)
|
|
3020
|
+
```
|
|
3021
|
+
|
|
3022
|
+
**Pattern: Peer Collaboration**
|
|
3023
|
+
```
|
|
3024
|
+
Backend ↔ Frontend (coordinate), both → QA (validate)
|
|
3025
|
+
```
|
|
3026
|
+
|
|
3027
|
+
**Pattern: Hierarchical Teams**
|
|
3028
|
+
```
|
|
3029
|
+
Manager
|
|
3030
|
+
├── Team Lead (Backend)
|
|
3031
|
+
│ ├── Senior Dev
|
|
3032
|
+
│ └── Junior Dev
|
|
3033
|
+
└── Team Lead (Frontend)
|
|
3034
|
+
├── UI Dev
|
|
3035
|
+
└── UX Designer
|
|
3036
|
+
```
|
|
3037
|
+
|
|
3038
|
+
---
|
|
3039
|
+
|
|
3040
|
+
## Summary
|
|
3041
|
+
|
|
3042
|
+
You've now learned **100% of SwarmSDK features**:
|
|
3043
|
+
|
|
3044
|
+
✅ **Part 1: Fundamentals** - Agents, models, providers, directories, system prompts, coding_agent flag
|
|
3045
|
+
|
|
3046
|
+
✅ **Part 2: Tools and Permissions** - All built-in tools, path/command permissions, bypass, scratchpad
|
|
3047
|
+
|
|
3048
|
+
✅ **Part 3: Agent Collaboration** - Delegation patterns, multi-level teams, markdown agents, delegation tracking
|
|
3049
|
+
|
|
3050
|
+
✅ **Part 4: Hooks System** - All 13 hook events, 6 hook actions, Ruby blocks, shell commands, breakpoints
|
|
3051
|
+
|
|
3052
|
+
✅ **Part 5: Node Workflows** - Multi-stage pipelines, dependencies, input/output transformers (Ruby + Bash), agent-less nodes, NodeContext API
|
|
3053
|
+
|
|
3054
|
+
✅ **Part 6: Advanced Configuration** - MCP integration (stdio/SSE/HTTP), custom providers, context management, rate limiting, timeout, LLM parameters, Responses API
|
|
3055
|
+
|
|
3056
|
+
✅ **Part 7: Production Features** - Structured logging, token/cost tracking, error handling, validation, document conversion
|
|
3057
|
+
|
|
3058
|
+
✅ **Part 8: Best Practices** - Architecture patterns, testing strategies, performance optimization, security, cost management, monitoring
|
|
3059
|
+
|
|
3060
|
+
## Next Steps
|
|
3061
|
+
|
|
3062
|
+
**Master specific features**:
|
|
3063
|
+
- [Node Workflows Guide](node-workflows-guide.md) - Deep dive into pipelines
|
|
3064
|
+
- [Hooks API Reference](hooks-api.md) - Complete hooks documentation
|
|
3065
|
+
- [Permissions Guide](permissions.md) - Security and access control
|
|
3066
|
+
- [Performance Tuning](performance-tuning.md) - Optimization techniques
|
|
3067
|
+
|
|
3068
|
+
**Real-world examples**:
|
|
3069
|
+
- [Use Cases](use-cases/) - Practical swarm examples
|
|
3070
|
+
- [Code Review Swarm](use-cases/code-review.md)
|
|
3071
|
+
- [Documentation Generator](use-cases/documentation-generation.md)
|
|
3072
|
+
- [Data Analysis Pipeline](use-cases/data-analysis.md)
|
|
3073
|
+
|
|
3074
|
+
**API Reference**:
|
|
3075
|
+
- [SwarmSDK API](../../api/swarm-sdk.md)
|
|
3076
|
+
- [Agent Configuration](../../api/agent-configuration.md)
|
|
3077
|
+
- [Tools API](../../api/tools.md)
|
|
3078
|
+
- [Hooks API](../../api/hooks.md)
|
|
3079
|
+
|
|
3080
|
+
## Where to Get Help
|
|
3081
|
+
|
|
3082
|
+
- **Documentation**: [SwarmSDK Guides](../README.md)
|
|
3083
|
+
- **Examples**: [Example Swarms](../../../examples/v2/)
|
|
3084
|
+
- **Issues**: [GitHub Issues](https://github.com/parruda/claude-swarm/issues)
|
|
3085
|
+
|
|
3086
|
+
---
|
|
3087
|
+
|
|
3088
|
+
**You now have complete knowledge of SwarmSDK.** Build amazing AI agent teams!
|