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.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/release.md +1 -1
  3. data/.claude/hooks/lint-code-files.rb +65 -0
  4. data/.rubocop.yml +22 -2
  5. data/CHANGELOG.md +14 -1
  6. data/CLAUDE.md +1 -1
  7. data/CONTRIBUTING.md +69 -0
  8. data/README.md +27 -2
  9. data/Rakefile +71 -3
  10. data/analyze_coverage.rb +94 -0
  11. data/docs/v2/CHANGELOG.swarm_cli.md +43 -0
  12. data/docs/v2/CHANGELOG.swarm_memory.md +379 -0
  13. data/docs/v2/CHANGELOG.swarm_sdk.md +362 -0
  14. data/docs/v2/README.md +308 -0
  15. data/docs/v2/guides/claude-code-agents.md +262 -0
  16. data/docs/v2/guides/complete-tutorial.md +3088 -0
  17. data/docs/v2/guides/getting-started.md +1456 -0
  18. data/docs/v2/guides/memory-adapters.md +998 -0
  19. data/docs/v2/guides/plugins.md +816 -0
  20. data/docs/v2/guides/quick-start-cli.md +1745 -0
  21. data/docs/v2/guides/rails-integration.md +1902 -0
  22. data/docs/v2/guides/swarm-memory.md +599 -0
  23. data/docs/v2/reference/cli.md +729 -0
  24. data/docs/v2/reference/ruby-dsl.md +2154 -0
  25. data/docs/v2/reference/yaml.md +1835 -0
  26. data/docs-team-swarm.yml +2222 -0
  27. data/examples/learning-assistant/assistant.md +7 -0
  28. data/examples/learning-assistant/example-memories/concept-example.md +90 -0
  29. data/examples/learning-assistant/example-memories/experience-example.md +66 -0
  30. data/examples/learning-assistant/example-memories/fact-example.md +76 -0
  31. data/examples/learning-assistant/example-memories/memory-index.md +78 -0
  32. data/examples/learning-assistant/example-memories/skill-example.md +168 -0
  33. data/examples/learning-assistant/learning_assistant.rb +34 -0
  34. data/examples/learning-assistant/learning_assistant.yml +20 -0
  35. data/examples/v2/dsl/01_basic.rb +44 -0
  36. data/examples/v2/dsl/02_core_parameters.rb +59 -0
  37. data/examples/v2/dsl/03_capabilities.rb +71 -0
  38. data/examples/v2/dsl/04_llm_parameters.rb +56 -0
  39. data/examples/v2/dsl/05_advanced_flags.rb +73 -0
  40. data/examples/v2/dsl/06_permissions.rb +80 -0
  41. data/examples/v2/dsl/07_mcp_server.rb +62 -0
  42. data/examples/v2/dsl/08_swarm_hooks.rb +53 -0
  43. data/examples/v2/dsl/09_agent_hooks.rb +67 -0
  44. data/examples/v2/dsl/10_all_agents_hooks.rb +67 -0
  45. data/examples/v2/dsl/11_delegation.rb +60 -0
  46. data/examples/v2/dsl/12_complete_integration.rb +137 -0
  47. data/examples/v2/file_tools_swarm.yml +102 -0
  48. data/examples/v2/hooks/01_basic_hooks.rb +133 -0
  49. data/examples/v2/hooks/02_usage_tracking.rb +201 -0
  50. data/examples/v2/hooks/03_production_monitoring.rb +429 -0
  51. data/examples/v2/hooks/agent_stop_exit_0.yml +21 -0
  52. data/examples/v2/hooks/agent_stop_exit_1.yml +21 -0
  53. data/examples/v2/hooks/agent_stop_exit_2.yml +26 -0
  54. data/examples/v2/hooks/multiple_hooks_all_pass.yml +37 -0
  55. data/examples/v2/hooks/multiple_hooks_first_fails.yml +37 -0
  56. data/examples/v2/hooks/multiple_hooks_second_fails.yml +37 -0
  57. data/examples/v2/hooks/multiple_hooks_warnings.yml +37 -0
  58. data/examples/v2/hooks/post_tool_use_exit_0.yml +24 -0
  59. data/examples/v2/hooks/post_tool_use_exit_1.yml +24 -0
  60. data/examples/v2/hooks/post_tool_use_exit_2.yml +24 -0
  61. data/examples/v2/hooks/post_tool_use_multi_matcher_exit_0.yml +26 -0
  62. data/examples/v2/hooks/post_tool_use_multi_matcher_exit_1.yml +26 -0
  63. data/examples/v2/hooks/post_tool_use_multi_matcher_exit_2.yml +26 -0
  64. data/examples/v2/hooks/pre_tool_use_exit_0.yml +24 -0
  65. data/examples/v2/hooks/pre_tool_use_exit_1.yml +24 -0
  66. data/examples/v2/hooks/pre_tool_use_exit_2.yml +24 -0
  67. data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_0.yml +26 -0
  68. data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_1.yml +26 -0
  69. data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_2.yml +27 -0
  70. data/examples/v2/hooks/swarm_summary.sh +44 -0
  71. data/examples/v2/hooks/user_prompt_exit_0.yml +21 -0
  72. data/examples/v2/hooks/user_prompt_exit_1.yml +21 -0
  73. data/examples/v2/hooks/user_prompt_exit_2.yml +21 -0
  74. data/examples/v2/hooks/validate_bash.rb +59 -0
  75. data/examples/v2/multi_directory_permissions.yml +221 -0
  76. data/examples/v2/node_context_demo.rb +127 -0
  77. data/examples/v2/node_workflow.rb +173 -0
  78. data/examples/v2/path_resolution_demo.rb +216 -0
  79. data/examples/v2/simple-swarm-v2.rb +90 -0
  80. data/examples/v2/simple-swarm-v2.yml +62 -0
  81. data/examples/v2/swarm.yml +71 -0
  82. data/examples/v2/swarm_with_hooks.yml +61 -0
  83. data/examples/v2/swarm_with_hooks_simple.yml +25 -0
  84. data/examples/v2/think_tool_demo.rb +62 -0
  85. data/exe/swarm +6 -0
  86. data/lib/claude_swarm/claude_mcp_server.rb +0 -6
  87. data/lib/claude_swarm/cli.rb +10 -3
  88. data/lib/claude_swarm/commands/ps.rb +19 -20
  89. data/lib/claude_swarm/commands/show.rb +1 -1
  90. data/lib/claude_swarm/configuration.rb +10 -12
  91. data/lib/claude_swarm/mcp_generator.rb +10 -1
  92. data/lib/claude_swarm/orchestrator.rb +73 -49
  93. data/lib/claude_swarm/system_utils.rb +37 -11
  94. data/lib/claude_swarm/version.rb +1 -1
  95. data/lib/claude_swarm/worktree_manager.rb +1 -0
  96. data/lib/claude_swarm/yaml_loader.rb +22 -0
  97. data/lib/claude_swarm.rb +7 -2
  98. data/lib/swarm_cli/cli.rb +201 -0
  99. data/lib/swarm_cli/command_registry.rb +61 -0
  100. data/lib/swarm_cli/commands/mcp_serve.rb +130 -0
  101. data/lib/swarm_cli/commands/mcp_tools.rb +148 -0
  102. data/lib/swarm_cli/commands/migrate.rb +55 -0
  103. data/lib/swarm_cli/commands/run.rb +173 -0
  104. data/lib/swarm_cli/config_loader.rb +97 -0
  105. data/lib/swarm_cli/formatters/human_formatter.rb +711 -0
  106. data/lib/swarm_cli/formatters/json_formatter.rb +51 -0
  107. data/lib/swarm_cli/interactive_repl.rb +918 -0
  108. data/lib/swarm_cli/mcp_serve_options.rb +44 -0
  109. data/lib/swarm_cli/mcp_tools_options.rb +59 -0
  110. data/lib/swarm_cli/migrate_options.rb +54 -0
  111. data/lib/swarm_cli/migrator.rb +132 -0
  112. data/lib/swarm_cli/options.rb +151 -0
  113. data/lib/swarm_cli/ui/components/agent_badge.rb +33 -0
  114. data/lib/swarm_cli/ui/components/content_block.rb +120 -0
  115. data/lib/swarm_cli/ui/components/divider.rb +57 -0
  116. data/lib/swarm_cli/ui/components/panel.rb +62 -0
  117. data/lib/swarm_cli/ui/components/usage_stats.rb +70 -0
  118. data/lib/swarm_cli/ui/formatters/cost.rb +49 -0
  119. data/lib/swarm_cli/ui/formatters/number.rb +58 -0
  120. data/lib/swarm_cli/ui/formatters/text.rb +77 -0
  121. data/lib/swarm_cli/ui/formatters/time.rb +73 -0
  122. data/lib/swarm_cli/ui/icons.rb +59 -0
  123. data/lib/swarm_cli/ui/renderers/event_renderer.rb +188 -0
  124. data/lib/swarm_cli/ui/state/agent_color_cache.rb +45 -0
  125. data/lib/swarm_cli/ui/state/depth_tracker.rb +40 -0
  126. data/lib/swarm_cli/ui/state/spinner_manager.rb +170 -0
  127. data/lib/swarm_cli/ui/state/usage_tracker.rb +62 -0
  128. data/lib/swarm_cli/version.rb +5 -0
  129. data/lib/swarm_cli.rb +44 -0
  130. data/lib/swarm_memory/adapters/base.rb +141 -0
  131. data/lib/swarm_memory/adapters/filesystem_adapter.rb +845 -0
  132. data/lib/swarm_memory/chat_extension.rb +34 -0
  133. data/lib/swarm_memory/cli/commands.rb +306 -0
  134. data/lib/swarm_memory/core/entry.rb +37 -0
  135. data/lib/swarm_memory/core/frontmatter_parser.rb +108 -0
  136. data/lib/swarm_memory/core/metadata_extractor.rb +68 -0
  137. data/lib/swarm_memory/core/path_normalizer.rb +75 -0
  138. data/lib/swarm_memory/core/semantic_index.rb +244 -0
  139. data/lib/swarm_memory/core/storage.rb +288 -0
  140. data/lib/swarm_memory/core/storage_read_tracker.rb +63 -0
  141. data/lib/swarm_memory/dsl/builder_extension.rb +40 -0
  142. data/lib/swarm_memory/dsl/memory_config.rb +113 -0
  143. data/lib/swarm_memory/embeddings/embedder.rb +36 -0
  144. data/lib/swarm_memory/embeddings/informers_embedder.rb +152 -0
  145. data/lib/swarm_memory/errors.rb +21 -0
  146. data/lib/swarm_memory/integration/cli_registration.rb +30 -0
  147. data/lib/swarm_memory/integration/configuration.rb +43 -0
  148. data/lib/swarm_memory/integration/registration.rb +31 -0
  149. data/lib/swarm_memory/integration/sdk_plugin.rb +531 -0
  150. data/lib/swarm_memory/optimization/analyzer.rb +244 -0
  151. data/lib/swarm_memory/optimization/defragmenter.rb +863 -0
  152. data/lib/swarm_memory/prompts/memory.md.erb +109 -0
  153. data/lib/swarm_memory/prompts/memory_assistant.md.erb +181 -0
  154. data/lib/swarm_memory/prompts/memory_researcher.md.erb +281 -0
  155. data/lib/swarm_memory/prompts/memory_retrieval.md.erb +78 -0
  156. data/lib/swarm_memory/search/semantic_search.rb +112 -0
  157. data/lib/swarm_memory/search/text_search.rb +42 -0
  158. data/lib/swarm_memory/search/text_similarity.rb +80 -0
  159. data/lib/swarm_memory/skills/meta/deep-learning.md +101 -0
  160. data/lib/swarm_memory/skills/meta/deep-learning.yml +14 -0
  161. data/lib/swarm_memory/tools/load_skill.rb +313 -0
  162. data/lib/swarm_memory/tools/memory_defrag.rb +382 -0
  163. data/lib/swarm_memory/tools/memory_delete.rb +99 -0
  164. data/lib/swarm_memory/tools/memory_edit.rb +185 -0
  165. data/lib/swarm_memory/tools/memory_glob.rb +160 -0
  166. data/lib/swarm_memory/tools/memory_grep.rb +247 -0
  167. data/lib/swarm_memory/tools/memory_multi_edit.rb +281 -0
  168. data/lib/swarm_memory/tools/memory_read.rb +123 -0
  169. data/lib/swarm_memory/tools/memory_write.rb +231 -0
  170. data/lib/swarm_memory/utils.rb +50 -0
  171. data/lib/swarm_memory/version.rb +5 -0
  172. data/lib/swarm_memory.rb +166 -0
  173. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +127 -0
  174. data/lib/swarm_sdk/agent/builder.rb +461 -0
  175. data/lib/swarm_sdk/agent/chat/context_tracker.rb +314 -0
  176. data/lib/swarm_sdk/agent/chat/hook_integration.rb +372 -0
  177. data/lib/swarm_sdk/agent/chat/logging_helpers.rb +116 -0
  178. data/lib/swarm_sdk/agent/chat/system_reminder_injector.rb +152 -0
  179. data/lib/swarm_sdk/agent/chat.rb +1159 -0
  180. data/lib/swarm_sdk/agent/context.rb +112 -0
  181. data/lib/swarm_sdk/agent/context_manager.rb +309 -0
  182. data/lib/swarm_sdk/agent/definition.rb +556 -0
  183. data/lib/swarm_sdk/claude_code_agent_adapter.rb +205 -0
  184. data/lib/swarm_sdk/configuration.rb +296 -0
  185. data/lib/swarm_sdk/context_compactor/metrics.rb +147 -0
  186. data/lib/swarm_sdk/context_compactor/token_counter.rb +106 -0
  187. data/lib/swarm_sdk/context_compactor.rb +340 -0
  188. data/lib/swarm_sdk/hooks/adapter.rb +359 -0
  189. data/lib/swarm_sdk/hooks/context.rb +197 -0
  190. data/lib/swarm_sdk/hooks/definition.rb +80 -0
  191. data/lib/swarm_sdk/hooks/error.rb +29 -0
  192. data/lib/swarm_sdk/hooks/executor.rb +146 -0
  193. data/lib/swarm_sdk/hooks/registry.rb +147 -0
  194. data/lib/swarm_sdk/hooks/result.rb +150 -0
  195. data/lib/swarm_sdk/hooks/shell_executor.rb +254 -0
  196. data/lib/swarm_sdk/hooks/tool_call.rb +35 -0
  197. data/lib/swarm_sdk/hooks/tool_result.rb +62 -0
  198. data/lib/swarm_sdk/log_collector.rb +51 -0
  199. data/lib/swarm_sdk/log_stream.rb +69 -0
  200. data/lib/swarm_sdk/markdown_parser.rb +75 -0
  201. data/lib/swarm_sdk/model_aliases.json +5 -0
  202. data/lib/swarm_sdk/models.json +1 -0
  203. data/lib/swarm_sdk/models.rb +120 -0
  204. data/lib/swarm_sdk/node/agent_config.rb +49 -0
  205. data/lib/swarm_sdk/node/builder.rb +439 -0
  206. data/lib/swarm_sdk/node/transformer_executor.rb +248 -0
  207. data/lib/swarm_sdk/node_context.rb +170 -0
  208. data/lib/swarm_sdk/node_orchestrator.rb +384 -0
  209. data/lib/swarm_sdk/permissions/config.rb +239 -0
  210. data/lib/swarm_sdk/permissions/error_formatter.rb +121 -0
  211. data/lib/swarm_sdk/permissions/path_matcher.rb +35 -0
  212. data/lib/swarm_sdk/permissions/validator.rb +173 -0
  213. data/lib/swarm_sdk/permissions_builder.rb +122 -0
  214. data/lib/swarm_sdk/plugin.rb +147 -0
  215. data/lib/swarm_sdk/plugin_registry.rb +101 -0
  216. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +243 -0
  217. data/lib/swarm_sdk/providers/openai_with_responses.rb +582 -0
  218. data/lib/swarm_sdk/result.rb +97 -0
  219. data/lib/swarm_sdk/swarm/agent_initializer.rb +334 -0
  220. data/lib/swarm_sdk/swarm/all_agents_builder.rb +140 -0
  221. data/lib/swarm_sdk/swarm/builder.rb +586 -0
  222. data/lib/swarm_sdk/swarm/mcp_configurator.rb +151 -0
  223. data/lib/swarm_sdk/swarm/tool_configurator.rb +419 -0
  224. data/lib/swarm_sdk/swarm.rb +982 -0
  225. data/lib/swarm_sdk/tools/bash.rb +274 -0
  226. data/lib/swarm_sdk/tools/clock.rb +44 -0
  227. data/lib/swarm_sdk/tools/delegate.rb +164 -0
  228. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +83 -0
  229. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +99 -0
  230. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +101 -0
  231. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +78 -0
  232. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +194 -0
  233. data/lib/swarm_sdk/tools/edit.rb +150 -0
  234. data/lib/swarm_sdk/tools/glob.rb +158 -0
  235. data/lib/swarm_sdk/tools/grep.rb +228 -0
  236. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +43 -0
  237. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +163 -0
  238. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +65 -0
  239. data/lib/swarm_sdk/tools/multi_edit.rb +232 -0
  240. data/lib/swarm_sdk/tools/path_resolver.rb +43 -0
  241. data/lib/swarm_sdk/tools/read.rb +251 -0
  242. data/lib/swarm_sdk/tools/registry.rb +93 -0
  243. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +96 -0
  244. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +76 -0
  245. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +91 -0
  246. data/lib/swarm_sdk/tools/stores/read_tracker.rb +61 -0
  247. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +224 -0
  248. data/lib/swarm_sdk/tools/stores/storage.rb +148 -0
  249. data/lib/swarm_sdk/tools/stores/todo_manager.rb +65 -0
  250. data/lib/swarm_sdk/tools/think.rb +95 -0
  251. data/lib/swarm_sdk/tools/todo_write.rb +216 -0
  252. data/lib/swarm_sdk/tools/web_fetch.rb +261 -0
  253. data/lib/swarm_sdk/tools/write.rb +117 -0
  254. data/lib/swarm_sdk/utils.rb +50 -0
  255. data/lib/swarm_sdk/version.rb +5 -0
  256. data/lib/swarm_sdk.rb +157 -0
  257. data/llm.v2.txt +13407 -0
  258. data/rubocop/cop/security/no_reflection_methods.rb +47 -0
  259. data/rubocop/cop/security/no_ruby_llm_logger.rb +32 -0
  260. data/swarm_cli.gemspec +57 -0
  261. data/swarm_memory.gemspec +28 -0
  262. data/swarm_sdk.gemspec +41 -0
  263. data/team.yml +1 -1
  264. data/team_full.yml +1875 -0
  265. data/{team_v2.yml → team_sdk.yml} +121 -52
  266. metadata +249 -6
  267. data/EXAMPLES.md +0 -164
@@ -0,0 +1,816 @@
1
+ # Plugin System Guide
2
+
3
+ Complete guide to SwarmSDK's plugin architecture - how it works, how to write plugins, and what's possible.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ The **plugin system** allows gems to extend SwarmSDK without creating tight coupling. Plugins can provide:
10
+
11
+ - Custom tools
12
+ - Persistent storage
13
+ - Configuration options
14
+ - System prompt contributions
15
+ - Lifecycle hooks (agent init, swarm start/stop, user messages)
16
+
17
+ **Key Design Principles:**
18
+ - 🔌 **Zero Coupling** - SwarmSDK has no knowledge of plugin classes
19
+ - 🤖 **Auto-Registration** - Plugins register themselves when loaded
20
+ - 🎯 **Lifecycle Hooks** - Plugins participate in agent/swarm lifecycle
21
+ - 🛠️ **Tool Provider** - Plugins create and manage their own tools
22
+ - 📦 **Storage Provider** - Plugins handle their own data persistence
23
+
24
+ ---
25
+
26
+ ## Architecture
27
+
28
+ ```
29
+ ┌─────────────────────────────────────────┐
30
+ │ SwarmSDK (Core) │
31
+ │ - Plugin base class │
32
+ │ - PluginRegistry │
33
+ │ - Lifecycle hooks │
34
+ │ - No plugin dependencies │
35
+ └─────────────┬───────────────────────────┘
36
+
37
+ │ (auto-registers)
38
+
39
+ ┌─────────────▼───────────────────────────┐
40
+ │ Plugin Gem (e.g., SwarmMemory) │
41
+ │ - Inherits from SwarmSDK::Plugin │
42
+ │ - Implements required methods │
43
+ │ - Registers on load │
44
+ │ - Provides tools & storage │
45
+ └──────────────────────────────────────────┘
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Writing a Plugin
51
+
52
+ ### Step 1: Create Plugin Class
53
+
54
+ ```ruby
55
+ # lib/my_plugin/integration/sdk_plugin.rb
56
+
57
+ module MyPlugin
58
+ module Integration
59
+ class SDKPlugin < SwarmSDK::Plugin
60
+ def initialize
61
+ super
62
+ @storages = {} # Track per-agent storage
63
+ end
64
+
65
+ # Plugin identifier (must be unique)
66
+ def name
67
+ :my_plugin
68
+ end
69
+
70
+ # Tools provided by this plugin
71
+ def tools
72
+ [:MyTool1, :MyTool2]
73
+ end
74
+
75
+ # Create a tool instance
76
+ def create_tool(tool_name, context)
77
+ storage = context[:storage]
78
+ agent_name = context[:agent_name]
79
+
80
+ case tool_name
81
+ when :MyTool1
82
+ Tools::MyTool1.new(storage: storage, agent_name: agent_name)
83
+ when :MyTool2
84
+ Tools::MyTool2.new(storage: storage)
85
+ end
86
+ end
87
+
88
+ # Check if storage should be created for an agent
89
+ def storage_enabled?(agent_definition)
90
+ agent_definition.respond_to?(:my_plugin) && agent_definition.my_plugin
91
+ end
92
+
93
+ # Create storage for an agent
94
+ def create_storage(agent_name:, config:)
95
+ directory = config.respond_to?(:directory) ? config.directory : config[:directory]
96
+
97
+ MyPlugin::Storage.new(directory: directory)
98
+ end
99
+
100
+ # Contribute to system prompt
101
+ def system_prompt_contribution(agent_definition:, storage:)
102
+ # Load your prompt template
103
+ File.read(File.expand_path("../prompts/my_plugin.md", __dir__))
104
+ end
105
+
106
+ # Tools that should be immutable (can't be removed)
107
+ def immutable_tools
108
+ [:MyTool1]
109
+ end
110
+
111
+ # Called when agent is initialized
112
+ def on_agent_initialized(agent_name:, agent:, context:)
113
+ storage = context[:storage]
114
+ return unless storage
115
+
116
+ # Store for later use
117
+ @storages[agent_name] = storage
118
+
119
+ # Mark tools as immutable
120
+ agent.mark_tools_immutable(immutable_tools.map(&:to_s))
121
+ end
122
+
123
+ # Called on every user message
124
+ def on_user_message(agent_name:, prompt:, is_first_message:)
125
+ storage = @storages[agent_name]
126
+ return [] unless storage
127
+
128
+ # Perform some analysis and return system reminders
129
+ if should_suggest_something?(prompt)
130
+ ["<system-reminder>Helpful suggestion here</system-reminder>"]
131
+ else
132
+ []
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ ```
139
+
140
+ ### Step 2: Auto-Register Plugin
141
+
142
+ ```ruby
143
+ # lib/my_plugin.rb
144
+
145
+ require 'swarm_sdk'
146
+ require_relative 'my_plugin/integration/sdk_plugin'
147
+
148
+ module MyPlugin
149
+ # ... your gem code ...
150
+ end
151
+
152
+ # Auto-register with SwarmSDK when loaded
153
+ if defined?(SwarmSDK) && defined?(SwarmSDK::PluginRegistry)
154
+ SwarmSDK::PluginRegistry.register(MyPlugin::Integration::SDKPlugin.new)
155
+ end
156
+ ```
157
+
158
+ ### Step 3: Add DSL Support (Optional)
159
+
160
+ ```ruby
161
+ # Add configuration method to Agent::Builder
162
+ module SwarmSDK
163
+ module Agent
164
+ class Builder
165
+ def my_plugin(&block)
166
+ @my_plugin_config = MyPluginConfig.new
167
+ @my_plugin_config.instance_eval(&block) if block_given?
168
+ @my_plugin_config
169
+ end
170
+ end
171
+ end
172
+ end
173
+ ```
174
+
175
+ **Usage:**
176
+ ```ruby
177
+ agent :assistant do
178
+ my_plugin do
179
+ directory ".swarm/my-plugin-data"
180
+ option "value"
181
+ end
182
+ end
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Plugin Interface Reference
188
+
189
+ ### Required Methods
190
+
191
+ ```ruby
192
+ class MyPlugin < SwarmSDK::Plugin
193
+ # Plugin identifier (Symbol) - REQUIRED
194
+ def name
195
+ :my_plugin
196
+ end
197
+ end
198
+ ```
199
+
200
+ ### Optional Methods
201
+
202
+ ```ruby
203
+ # List of tools provided
204
+ def tools
205
+ [:Tool1, :Tool2]
206
+ end
207
+
208
+ # Create a tool instance
209
+ # context = {agent_name:, storage:, agent_definition:, chat:, tool_configurator:}
210
+ def create_tool(tool_name, context)
211
+ MyTool.new(...)
212
+ end
213
+
214
+ # Create plugin storage for an agent
215
+ def create_storage(agent_name:, config:)
216
+ MyStorage.new(...)
217
+ end
218
+
219
+ # Check if storage should be created
220
+ def storage_enabled?(agent_definition)
221
+ agent_definition.respond_to?(:my_plugin)
222
+ end
223
+
224
+ # Parse configuration from agent definition
225
+ def parse_config(raw_config)
226
+ raw_config # Or transform as needed
227
+ end
228
+
229
+ # Contribute to agent system prompt
230
+ def system_prompt_contribution(agent_definition:, storage:)
231
+ "# My Plugin Guidance\n..."
232
+ end
233
+
234
+ # Tools that can't be removed
235
+ def immutable_tools
236
+ [:MyTool1]
237
+ end
238
+
239
+ # Lifecycle: Agent initialized
240
+ def on_agent_initialized(agent_name:, agent:, context:)
241
+ # Setup, register tools, mark immutable, etc.
242
+ end
243
+
244
+ # Lifecycle: Swarm started
245
+ def on_swarm_started(swarm:)
246
+ # Global initialization
247
+ end
248
+
249
+ # Lifecycle: Swarm stopped
250
+ def on_swarm_stopped(swarm:)
251
+ # Cleanup, save state, etc.
252
+ end
253
+
254
+ # Lifecycle: User message (EVERY message)
255
+ def on_user_message(agent_name:, prompt:, is_first_message:)
256
+ # Analyze prompt, return system reminders
257
+ [] # Array of reminder strings
258
+ end
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Lifecycle Hooks
264
+
265
+ ### Hook Execution Order
266
+
267
+ ```
268
+ 1. Swarm created
269
+
270
+ 2. Agents initialized
271
+ → Plugin.create_storage()
272
+ → Plugin.on_agent_initialized()
273
+
274
+ 3. Swarm.execute() called
275
+ → Plugin.on_swarm_started()
276
+
277
+ 4. User message
278
+ → Plugin.on_user_message() [Returns reminders]
279
+ → Agent sees reminders
280
+ → Agent responds
281
+
282
+ 5. Swarm stops
283
+ → Plugin.on_swarm_stopped()
284
+ ```
285
+
286
+ ### on_agent_initialized
287
+
288
+ **Purpose:** Setup plugin-specific agent configuration
289
+
290
+ **Use cases:**
291
+ - Register additional tools (like LoadSkill that needs chat reference)
292
+ - Mark tools as immutable
293
+ - Store agent storage reference for later use
294
+ - Configure agent-specific settings
295
+
296
+ **Example:**
297
+ ```ruby
298
+ def on_agent_initialized(agent_name:, agent:, context:)
299
+ @storages[agent_name] = context[:storage]
300
+
301
+ # Register special tool
302
+ special_tool = create_special_tool(context)
303
+ agent.with_tool(special_tool)
304
+
305
+ # Mark tools as immutable
306
+ agent.mark_tools_immutable(["MyTool1", "MyTool2"])
307
+ end
308
+ ```
309
+
310
+ ### on_user_message
311
+
312
+ **Purpose:** Inject context-aware system reminders
313
+
314
+ **Use cases:**
315
+ - Semantic skill discovery
316
+ - Context injection based on prompt
317
+ - Suggested actions
318
+ - Warning/guidance
319
+
320
+ **Example:**
321
+ ```ruby
322
+ def on_user_message(agent_name:, prompt:, is_first_message:)
323
+ storage = @storages[agent_name]
324
+ return [] unless storage
325
+
326
+ # Search for relevant knowledge
327
+ results = storage.search(prompt, threshold: 0.65)
328
+ return [] if results.empty?
329
+
330
+ # Return system reminder
331
+ ["<system-reminder>Found #{results.size} relevant entries...</system-reminder>"]
332
+ end
333
+ ```
334
+
335
+ **Important:** Reminders are **ephemeral** - sent to LLM but not persisted in conversation.
336
+
337
+ ---
338
+
339
+ ## Real-World Example: SwarmMemory
340
+
341
+ See how SwarmMemory implements the plugin interface:
342
+
343
+ **File:** `lib/swarm_memory/integration/sdk_plugin.rb`
344
+
345
+ **Provides:**
346
+ - 9 tools (MemoryWrite, MemoryRead, ..., LoadSkill)
347
+ - Filesystem storage with embeddings
348
+ - Memory system prompt
349
+ - Dual semantic search (skills + memories)
350
+ - Relationship discovery
351
+
352
+ **Key Implementation Details:**
353
+
354
+ ```ruby
355
+ class SDKPlugin < SwarmSDK::Plugin
356
+ def initialize
357
+ super
358
+ @storages = {} # Track storages per agent
359
+ end
360
+
361
+ def tools
362
+ # LoadSkill NOT here - registered in on_agent_initialized
363
+ [:MemoryWrite, :MemoryRead, :MemoryEdit, ...]
364
+ end
365
+
366
+ def create_storage(agent_name:, config:)
367
+ directory = extract_directory(config)
368
+ embedder = Embeddings::InformersEmbedder.new
369
+ adapter = Adapters::FilesystemAdapter.new(directory: directory)
370
+
371
+ Storage.new(adapter: adapter, embedder: embedder)
372
+ end
373
+
374
+ def on_agent_initialized(agent_name:, agent:, context:)
375
+ # Store for later
376
+ @storages[agent_name] = context[:storage]
377
+
378
+ # Register LoadSkill (needs chat + tool_configurator)
379
+ load_skill = create_load_skill_tool(context)
380
+ agent.with_tool(load_skill)
381
+
382
+ # Mark all memory tools immutable
383
+ agent.mark_tools_immutable(immutable_tools)
384
+ end
385
+
386
+ def on_user_message(agent_name:, prompt:, is_first_message:)
387
+ storage = @storages[agent_name]
388
+ return [] unless storage&.semantic_index
389
+
390
+ # Parallel search for skills AND memories
391
+ Async do |task|
392
+ skills = task.async { search_skills(prompt) }
393
+ memories = task.async { search_memories(prompt) }
394
+
395
+ # Build reminders for both
396
+ reminders = []
397
+ reminders << build_skill_reminder(skills.wait) if skills.wait.any?
398
+ reminders << build_memory_reminder(memories.wait) if memories.wait.any?
399
+ reminders
400
+ end.wait
401
+ end
402
+ end
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Testing Plugins
408
+
409
+ ### Unit Tests
410
+
411
+ ```ruby
412
+ class MyPluginTest < Minitest::Test
413
+ def test_plugin_registration
414
+ assert SwarmSDK::PluginRegistry.registered?(:my_plugin)
415
+
416
+ plugin = SwarmSDK::PluginRegistry.get(:my_plugin)
417
+ assert_instance_of MyPlugin::Integration::SDKPlugin, plugin
418
+ end
419
+
420
+ def test_plugin_provides_tools
421
+ plugin = SwarmSDK::PluginRegistry.get(:my_plugin)
422
+
423
+ assert_includes plugin.tools, :MyTool1
424
+ assert_includes plugin.tools, :MyTool2
425
+ end
426
+
427
+ def test_tool_creation
428
+ plugin = SwarmSDK::PluginRegistry.get(:my_plugin)
429
+ storage = MyPlugin::Storage.new(directory: "/tmp/test")
430
+
431
+ context = { agent_name: :test, storage: storage }
432
+ tool = plugin.create_tool(:MyTool1, context)
433
+
434
+ assert_instance_of MyPlugin::Tools::MyTool1, tool
435
+ end
436
+ end
437
+ ```
438
+
439
+ ### Integration Tests
440
+
441
+ ```ruby
442
+ def test_plugin_tools_available_to_agent
443
+ swarm = SwarmSDK.build do
444
+ agent :test do
445
+ my_plugin { directory "/tmp/test" }
446
+ end
447
+ end
448
+
449
+ agent = swarm.agent(:test)
450
+
451
+ # Plugin tools should be registered
452
+ assert agent.tools.key?(:MyTool1)
453
+ assert agent.tools.key?(:MyTool2)
454
+ end
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Plugin Registry API
460
+
461
+ ### Registration
462
+
463
+ ```ruby
464
+ # Auto-registration (recommended)
465
+ SwarmSDK::PluginRegistry.register(MyPlugin.new)
466
+
467
+ # Check registration
468
+ SwarmSDK::PluginRegistry.registered?(:my_plugin) # => true
469
+ ```
470
+
471
+ ### Lookup
472
+
473
+ ```ruby
474
+ # Get plugin by name
475
+ plugin = SwarmSDK::PluginRegistry.get(:my_plugin)
476
+
477
+ # Check if tool is provided by plugin
478
+ SwarmSDK::PluginRegistry.plugin_tool?(:MyTool1) # => true
479
+
480
+ # Get plugin for a tool
481
+ plugin = SwarmSDK::PluginRegistry.plugin_for_tool(:MyTool1)
482
+ plugin.name # => :my_plugin
483
+ ```
484
+
485
+ ### All Plugins
486
+
487
+ ```ruby
488
+ # Get all registered plugins
489
+ plugins = SwarmSDK::PluginRegistry.all # => [plugin1, plugin2]
490
+
491
+ # Get all plugin tools
492
+ tools = SwarmSDK::PluginRegistry.tools # => {MyTool1: plugin1, MyTool2: plugin1}
493
+ ```
494
+
495
+ ---
496
+
497
+ ## Best Practices
498
+
499
+ ### 1. Single Responsibility
500
+
501
+ Each plugin should have a **focused purpose**:
502
+
503
+ ✅ **Good:** Memory storage plugin, Database plugin, Analytics plugin
504
+ ❌ **Bad:** "Utilities" plugin with unrelated tools
505
+
506
+ ### 2. Minimal Dependencies
507
+
508
+ Plugins should have **minimal external dependencies**:
509
+
510
+ ```ruby
511
+ # Check if dependency available
512
+ def create_storage(...)
513
+ unless defined?(SomeDependency)
514
+ raise PluginError, "my_plugin requires 'some_gem'. Install: gem install some_gem"
515
+ end
516
+
517
+ SomeDependency.new(...)
518
+ end
519
+ ```
520
+
521
+ ### 3. Graceful Degradation
522
+
523
+ Plugins should **degrade gracefully** if features unavailable:
524
+
525
+ ```ruby
526
+ def on_user_message(agent_name:, prompt:, is_first_message:)
527
+ storage = @storages[agent_name]
528
+
529
+ # No storage? Return empty (no crash)
530
+ return [] unless storage
531
+
532
+ # Feature unavailable? Silent degradation
533
+ return [] unless storage.respond_to?(:search)
534
+
535
+ # Feature available - use it
536
+ results = storage.search(prompt)
537
+ results.any? ? [build_reminder(results)] : []
538
+ end
539
+ ```
540
+
541
+ ### 4. Namespace Your Tools
542
+
543
+ Use descriptive, namespaced tool names:
544
+
545
+ ✅ **Good:** `MemoryWrite`, `DatabaseQuery`, `AnalyticsTrack`
546
+ ❌ **Bad:** `Write`, `Query`, `Track` (conflicts with built-ins)
547
+
548
+ ### 5. Document Everything
549
+
550
+ Plugins should have:
551
+ - Comprehensive README
552
+ - Tool descriptions (in tool classes)
553
+ - Configuration examples
554
+ - Troubleshooting guide
555
+
556
+ ---
557
+
558
+ ## Advanced Patterns
559
+
560
+ ### Conditional Tool Registration
561
+
562
+ Register different tools based on configuration:
563
+
564
+ ```ruby
565
+ def on_agent_initialized(agent_name:, agent:, context:)
566
+ config = context[:agent_definition].my_plugin
567
+
568
+ # Conditionally register tools
569
+ if config.experimental_features
570
+ experimental_tool = create_experimental_tool(context)
571
+ agent.with_tool(experimental_tool)
572
+ end
573
+ end
574
+ ```
575
+
576
+ ### Tool Swapping
577
+
578
+ Dynamically change available tools:
579
+
580
+ ```ruby
581
+ def on_user_message(agent_name:, prompt:, is_first_message:)
582
+ # Detect if user wants specialized mode
583
+ if prompt.include?("debug mode")
584
+ # Agent can swap tools based on this hint
585
+ ["<system-reminder>Debug mode detected. Load debug skill for specialized tools.</system-reminder>"]
586
+ else
587
+ []
588
+ end
589
+ end
590
+ ```
591
+
592
+ ### Multi-Agent Coordination
593
+
594
+ Plugins can coordinate across agents:
595
+
596
+ ```ruby
597
+ class CoordinationPlugin < SwarmSDK::Plugin
598
+ def initialize
599
+ super
600
+ @shared_state = {}
601
+ end
602
+
603
+ def on_agent_initialized(agent_name:, agent:, context:)
604
+ @shared_state[agent_name] = { initialized_at: Time.now }
605
+ end
606
+
607
+ def on_user_message(agent_name:, prompt:, is_first_message:)
608
+ # Check what other agents are doing
609
+ other_agents = @shared_state.keys - [agent_name]
610
+
611
+ if other_agents.any?
612
+ ["<system-reminder>Other active agents: #{other_agents.join(", ")}</system-reminder>"]
613
+ else
614
+ []
615
+ end
616
+ end
617
+ end
618
+ ```
619
+
620
+ ---
621
+
622
+ ## Plugin Development Checklist
623
+
624
+ ### Before Publishing
625
+
626
+ - [ ] Plugin class inherits from `SwarmSDK::Plugin`
627
+ - [ ] `name` method returns unique symbol
628
+ - [ ] Auto-registration code in main gem file
629
+ - [ ] All tools have comprehensive descriptions
630
+ - [ ] Storage adapter (if any) handles errors gracefully
631
+ - [ ] Lifecycle hooks implemented as needed
632
+ - [ ] Unit tests for plugin class
633
+ - [ ] Integration tests with SwarmSDK
634
+ - [ ] README with installation and usage
635
+ - [ ] Example swarm configuration
636
+ - [ ] Troubleshooting section
637
+
638
+ ### Quality Checklist
639
+
640
+ - [ ] Plugin works when SwarmSDK is standalone (no crashes)
641
+ - [ ] Graceful error messages if dependencies missing
642
+ - [ ] No global state pollution
643
+ - [ ] Thread-safe (if using shared state)
644
+ - [ ] Fiber-safe (if using Async operations)
645
+ - [ ] Tools have `name` method returning simple strings
646
+ - [ ] Configuration validated with helpful errors
647
+ - [ ] Works with both Ruby DSL and YAML
648
+
649
+ ---
650
+
651
+ ## Common Pitfalls
652
+
653
+ ### ❌ Pitfall 1: Circular Dependencies
654
+
655
+ ```ruby
656
+ # BAD - SwarmSDK would depend on MyPlugin
657
+ require 'swarm_sdk'
658
+ require 'my_plugin' # SwarmSDK has: require 'my_plugin'
659
+
660
+ # GOOD - No circular dependency
661
+ require 'swarm_sdk' # No my_plugin references
662
+ require 'my_plugin' # Requires swarm_sdk, registers plugin
663
+ ```
664
+
665
+ ### ❌ Pitfall 2: Hardcoding in SDK
666
+
667
+ ```ruby
668
+ # BAD - SDK knows about plugin
669
+ if defined?(MyPlugin)
670
+ do_something_with_my_plugin
671
+ end
672
+
673
+ # GOOD - SDK uses plugin interface
674
+ SwarmSDK::PluginRegistry.all.each do |plugin|
675
+ plugin.on_agent_initialized(...)
676
+ end
677
+ ```
678
+
679
+ ### ❌ Pitfall 3: Not Handling Missing Storage
680
+
681
+ ```ruby
682
+ # BAD - Crashes if storage nil
683
+ def on_user_message(agent_name:, prompt:, is_first_message:)
684
+ storage = @storages[agent_name]
685
+ results = storage.search(prompt) # BOOM if storage is nil
686
+ end
687
+
688
+ # GOOD - Graceful handling
689
+ def on_user_message(agent_name:, prompt:, is_first_message:)
690
+ storage = @storages[agent_name]
691
+ return [] unless storage # Early return
692
+
693
+ results = storage.search(prompt)
694
+ # ...
695
+ end
696
+ ```
697
+
698
+ ### ❌ Pitfall 4: Forgetting to Track Storage
699
+
700
+ ```ruby
701
+ # BAD - Storage created but not tracked
702
+ def create_storage(...)
703
+ MyStorage.new(...)
704
+ # Forgot to store it!
705
+ end
706
+
707
+ # In on_user_message:
708
+ storage = @storages[agent_name] # nil!
709
+
710
+ # GOOD - Track in on_agent_initialized
711
+ def on_agent_initialized(agent_name:, agent:, context:)
712
+ @storages[agent_name] = context[:storage]
713
+ end
714
+ ```
715
+
716
+ ---
717
+
718
+ ## Examples
719
+
720
+ ### Minimal Plugin
721
+
722
+ ```ruby
723
+ class MinimalPlugin < SwarmSDK::Plugin
724
+ def name
725
+ :minimal
726
+ end
727
+
728
+ def tools
729
+ [:Echo]
730
+ end
731
+
732
+ def create_tool(tool_name, context)
733
+ Tools::Echo.new
734
+ end
735
+ end
736
+
737
+ SwarmSDK::PluginRegistry.register(MinimalPlugin.new)
738
+ ```
739
+
740
+ ### Storage Plugin
741
+
742
+ ```ruby
743
+ class StoragePlugin < SwarmSDK::Plugin
744
+ def initialize
745
+ super
746
+ @databases = {}
747
+ end
748
+
749
+ def name
750
+ :database
751
+ end
752
+
753
+ def storage_enabled?(agent_definition)
754
+ agent_definition.respond_to?(:database)
755
+ end
756
+
757
+ def create_storage(agent_name:, config:)
758
+ Database.connect(config.url)
759
+ end
760
+
761
+ def on_agent_initialized(agent_name:, agent:, context:)
762
+ @databases[agent_name] = context[:storage]
763
+ end
764
+
765
+ def tools
766
+ [:DbQuery, :DbInsert]
767
+ end
768
+
769
+ def create_tool(tool_name, context)
770
+ db = context[:storage]
771
+
772
+ case tool_name
773
+ when :DbQuery
774
+ Tools::DbQuery.new(db: db)
775
+ when :DbInsert
776
+ Tools::DbInsert.new(db: db)
777
+ end
778
+ end
779
+ end
780
+ ```
781
+
782
+ ### Analytics Plugin
783
+
784
+ ```ruby
785
+ class AnalyticsPlugin < SwarmSDK::Plugin
786
+ def name
787
+ :analytics
788
+ end
789
+
790
+ def on_user_message(agent_name:, prompt:, is_first_message:)
791
+ # Track every user message
792
+ Analytics.track(
793
+ event: "user_message",
794
+ agent: agent_name,
795
+ prompt_length: prompt.length,
796
+ is_first: is_first_message
797
+ )
798
+
799
+ [] # No reminders
800
+ end
801
+
802
+ def on_swarm_stopped(swarm:)
803
+ # Flush analytics on shutdown
804
+ Analytics.flush
805
+ end
806
+ end
807
+ ```
808
+
809
+ ---
810
+
811
+ ## See Also
812
+
813
+ - **SwarmMemory Plugin:** `lib/swarm_memory/integration/sdk_plugin.rb` - Real-world example
814
+ - **Plugin Base Class:** `lib/swarm_sdk/plugin.rb` - Interface definition
815
+ - **PluginRegistry:** `lib/swarm_sdk/plugin_registry.rb` - Registry implementation
816
+ - **Writing Adapters:** `docs/v2/guides/memory-adapters.md` - Storage adapters