claude_swarm 0.1.20 → 0.2.0
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/.rubocop.yml +9 -66
- data/.rubocop_todo.yml +11 -0
- data/CHANGELOG.md +93 -0
- data/CLAUDE.md +61 -0
- data/README.md +172 -15
- data/Rakefile +1 -1
- data/examples/mixed-provider-swarm.yml +23 -0
- data/lib/claude_swarm/claude_code_executor.rb +7 -12
- data/lib/claude_swarm/claude_mcp_server.rb +26 -12
- data/lib/claude_swarm/cli.rb +293 -165
- data/lib/claude_swarm/commands/ps.rb +22 -24
- data/lib/claude_swarm/commands/show.rb +45 -63
- data/lib/claude_swarm/configuration.rb +137 -8
- data/lib/claude_swarm/mcp_generator.rb +39 -14
- data/lib/claude_swarm/openai/chat_completion.rb +264 -0
- data/lib/claude_swarm/openai/executor.rb +301 -0
- data/lib/claude_swarm/openai/responses.rb +338 -0
- data/lib/claude_swarm/orchestrator.rb +205 -39
- data/lib/claude_swarm/process_tracker.rb +7 -7
- data/lib/claude_swarm/session_cost_calculator.rb +93 -0
- data/lib/claude_swarm/session_path.rb +3 -5
- data/lib/claude_swarm/system_utils.rb +1 -3
- data/lib/claude_swarm/tools/reset_session_tool.rb +24 -0
- data/lib/claude_swarm/tools/session_info_tool.rb +24 -0
- data/lib/claude_swarm/tools/task_tool.rb +43 -0
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm/worktree_manager.rb +13 -20
- data/lib/claude_swarm.rb +23 -10
- data/single.yml +482 -6
- metadata +50 -16
- data/claude-swarm.yml +0 -64
- data/lib/claude_swarm/reset_session_tool.rb +0 -22
- data/lib/claude_swarm/session_info_tool.rb +0 -22
- data/lib/claude_swarm/task_tool.rb +0 -39
- /data/{example → examples}/claude-swarm.yml +0 -0
- /data/{example → examples}/microservices-team.yml +0 -0
- /data/{example → examples}/session-restoration-demo.yml +0 -0
- /data/{example → examples}/test-generation.yml +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4085d9345464dcd7fc7be4c78155aa03f2467f7f089b056f2be0589f5de260f2
|
4
|
+
data.tar.gz: fda22e57619c30b1d9e1efcabb5a8a0b2b74f9f6df2d969944e07d27753adbd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 216ff3a7bfda3f2763195eec1e32821596d7047c155d0757d33da0718ad1dbb3c51f04fe50591c2a99d98da37d53255a9bda11c9bf9b6bf79dff788ac27fc0c9
|
7
|
+
data.tar.gz: 39784e3be63360c32ec3388983a10068f9d8193bde6cebef190aae856a2da9caa47cb63c772e268203a85eb8a8fad2e0717a901401fffbd0ce8e716979cd3f20
|
data/.rubocop.yml
CHANGED
@@ -1,71 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
inherit_gem:
|
4
|
+
rubocop-shopify: rubocop.yml
|
4
5
|
|
5
6
|
plugins:
|
6
7
|
- rubocop-minitest
|
7
8
|
- rubocop-rake
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
EnforcedStyle: double_quotes
|
15
|
-
|
16
|
-
# Disable documentation for internal classes
|
17
|
-
Style/Documentation:
|
18
|
-
Enabled: false
|
19
|
-
|
20
|
-
# Allow slightly longer methods
|
21
|
-
Metrics/MethodLength:
|
22
|
-
Enabled: false
|
23
|
-
|
24
|
-
# Disable gemspec specific cops
|
25
|
-
Gemspec/RequireMFA:
|
26
|
-
Enabled: false
|
27
|
-
|
28
|
-
Gemspec/RequiredRubyVersion:
|
29
|
-
Enabled: false
|
30
|
-
|
31
|
-
Gemspec/DevelopmentDependencies:
|
32
|
-
Enabled: false
|
33
|
-
|
34
|
-
Naming/AccessorMethodName:
|
35
|
-
Enabled: false
|
36
|
-
|
37
|
-
Metrics/BlockLength:
|
38
|
-
Enabled: false
|
39
|
-
|
40
|
-
Metrics/BlockNesting:
|
41
|
-
Enabled: false
|
42
|
-
|
43
|
-
Metrics/ClassLength:
|
44
|
-
Enabled: false
|
45
|
-
|
46
|
-
Metrics/PerceivedComplexity:
|
47
|
-
Enabled: false
|
48
|
-
|
49
|
-
Metrics/CyclomaticComplexity:
|
50
|
-
Enabled: false
|
51
|
-
|
52
|
-
Metrics/AbcSize:
|
53
|
-
Enabled: false
|
54
|
-
|
55
|
-
Naming/PredicateName:
|
56
|
-
Enabled: false
|
57
|
-
|
58
|
-
Layout/LineLength:
|
59
|
-
Max: 150
|
60
|
-
|
61
|
-
Metrics/ModuleLength:
|
62
|
-
Enabled: false
|
63
|
-
|
64
|
-
Minitest/MultipleAssertions:
|
65
|
-
Enabled: false
|
66
|
-
|
67
|
-
Metrics/ParameterLists:
|
68
|
-
Enabled: false
|
69
|
-
|
70
|
-
Style/PerlBackrefs:
|
71
|
-
Enabled: false
|
10
|
+
AllCops:
|
11
|
+
TargetRubyVersion: 3.4
|
12
|
+
NewCops: enable
|
13
|
+
Exclude:
|
14
|
+
- '.ruby-lsp/**/*'
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2025-07-02 11:28:10 UTC using RuboCop version 1.77.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 34
|
10
|
+
Minitest/MultipleAssertions:
|
11
|
+
Max: 23
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,96 @@
|
|
1
|
+
## [0.2.0]
|
2
|
+
|
3
|
+
### Added
|
4
|
+
- **After commands support**: Added `after` field to swarm configuration for executing cleanup commands
|
5
|
+
- Commands run after Claude exits but before cleanup processes
|
6
|
+
- Execute in the main instance's directory (including worktree if enabled)
|
7
|
+
- Run even when interrupted by signals (Ctrl+C)
|
8
|
+
- Failures in after commands do not prevent cleanup from proceeding
|
9
|
+
- Not executed during session restoration
|
10
|
+
- Example: `after: ["docker-compose down", "rm -rf temp/*"]`
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
- **Session restoration command**: Session restoration now uses a dedicated `restore` command instead of the `--session-id` flag
|
14
|
+
- Previous: `claude-swarm start --session-id SESSION_ID`
|
15
|
+
- New: `claude-swarm restore SESSION_ID`
|
16
|
+
- More intuitive command structure following standard CLI patterns
|
17
|
+
- **Removed redundant -c flag**: The `-c/--config` option has been removed from the `start` command
|
18
|
+
- Config file can still be specified as a positional argument: `claude-swarm start my-config.yml`
|
19
|
+
- Default remains `claude-swarm.yml` when no file is specified
|
20
|
+
- **Session ID format**: Session IDs now use UUIDs instead of timestamp format
|
21
|
+
- Previous format: `YYYYMMDD_HHMMSS` (e.g., `20250707_181341`)
|
22
|
+
- New format: UUID v4 (e.g., `550e8400-e29b-41d4-a716-446655440000`)
|
23
|
+
- Provides globally unique identifiers suitable for external application integration
|
24
|
+
- Sessions remain sorted by file creation time, not by ID
|
25
|
+
- **BREAKING CHANGE: Before commands now execute in main instance directory**: The `before` commands specified in swarm configuration now run after changing to the main instance's directory (including worktrees when enabled), rather than in the original working directory
|
26
|
+
- This ensures commands like `npm install` or `bundle install` affect only the isolated worktree
|
27
|
+
- Makes behavior more intuitive and consistent with user expectations
|
28
|
+
- Existing swarms relying on before commands running in the original directory will need to be updated
|
29
|
+
- **Custom session ID support**: Added `--session-id` option to the `start` command to allow users to specify their own session ID
|
30
|
+
- Use `claude-swarm start --session-id my-custom-id` to use a custom session ID
|
31
|
+
- If not provided, a UUID is generated automatically
|
32
|
+
- Useful for integrating with external systems that need predictable session identifiers
|
33
|
+
- **Environment variable interpolation in configuration**: Claude Swarm now supports environment variable interpolation in all YAML configuration values
|
34
|
+
- Use `${ENV_VAR_NAME}` syntax to reference environment variables
|
35
|
+
- Variables are interpolated recursively in strings, arrays, and nested structures
|
36
|
+
- Fails with clear error message if referenced environment variable is not set
|
37
|
+
- Supports multiple variables in the same string and partial string interpolation
|
38
|
+
- **Environment variable defaults**: Environment variables in configuration now support default values
|
39
|
+
- Use `${ENV_VAR_NAME:=default_value}` syntax to provide defaults
|
40
|
+
- Default values are used when the environment variable is not set
|
41
|
+
- Supports any string as default value, including spaces and special characters
|
42
|
+
- Examples: `${DB_PORT:=5432}`, `${API_URL:=https://api.example.com}`
|
43
|
+
- **Session path display in show command**: The `claude-swarm show SESSION_ID` command now displays the session path for easier access to session files
|
44
|
+
- **Main process PID tracking**: The orchestrator now writes its process ID to `SESSION_PATH/main_pid` for external monitoring and management
|
45
|
+
- **Swarm execution summary**: Display runtime duration and total cost at the end of each swarm run [@claudenm]
|
46
|
+
- Shows total execution time in hours, minutes, and seconds format
|
47
|
+
- Calculates and displays aggregate cost across all instances
|
48
|
+
- Indicates when main instance cost is excluded (e.g., for interactive sessions)
|
49
|
+
- Session metadata now includes end time and duration in seconds
|
50
|
+
|
51
|
+
- **Session cost calculator**: New `SessionCostCalculator` class for aggregating costs from session logs [@claudenm]
|
52
|
+
- Processes session.log.json files to calculate total usage costs
|
53
|
+
- Tracks which instances have cost data available
|
54
|
+
|
55
|
+
- **Session cost calculator**: New `SessionCostCalculator` class for aggregating costs from session logs
|
56
|
+
- Processes session.log.json files to calculate total usage costs
|
57
|
+
- Tracks which instances have cost data available
|
58
|
+
|
59
|
+
- **OpenAI provider support**: Claude Swarm now supports OpenAI models as an alternative provider
|
60
|
+
- Instances can specify `provider: openai` in configuration (default remains "claude")
|
61
|
+
- Full MCP tool support for OpenAI instances via automatic conversion
|
62
|
+
- Mixed provider swarms allow Claude and OpenAI instances to collaborate
|
63
|
+
- OpenAI instances only work with `vibe: true` at the moment. There's no way to set allowed/disallowed tools.
|
64
|
+
|
65
|
+
- **Dual OpenAI API support**: Two API versions available for different use cases
|
66
|
+
- Chat Completion API (`api_version: "chat_completion"`) - Traditional format with tool calling
|
67
|
+
- Responses API (`api_version: "responses"`) - New structured format with function calls
|
68
|
+
- Both APIs support recursive tool execution with proper conversation tracking
|
69
|
+
|
70
|
+
- **OpenAI-specific configuration options**:
|
71
|
+
- `temperature`: Control response randomness (default: 0.3)
|
72
|
+
- `api_version`: Choose between "chat_completion" or "responses"
|
73
|
+
- `openai_token_env`: Custom environment variable for API key (default: "OPENAI_API_KEY")
|
74
|
+
- `base_url`: Support for OpenAI-compatible endpoints and proxies
|
75
|
+
|
76
|
+
- **Enhanced debugging and logging**:
|
77
|
+
- Detailed error response logging for OpenAI API calls
|
78
|
+
- Conversation flow tracking with IDs for debugging
|
79
|
+
- Full request/response logging in session JSONL files
|
80
|
+
|
81
|
+
### Changed
|
82
|
+
- Configuration validation now enforces provider-specific fields
|
83
|
+
- Example configurations moved from `example/` to `examples/` directory
|
84
|
+
- Added `mixed-provider-swarm.yml` example demonstrating Claude-OpenAI collaboration
|
85
|
+
- Session metadata now includes `start_time`, `end_time`, and `duration_seconds` fields [@claudenm]
|
86
|
+
- Updated `ps` and `show` commands to use the new cost calculation functionality [@claudenm]
|
87
|
+
|
88
|
+
|
89
|
+
### Internal
|
90
|
+
- New classes: `OpenAIExecutor`, `OpenAIChatCompletion`, `OpenAIResponses`
|
91
|
+
- Comprehensive test coverage for OpenAI provider functionality
|
92
|
+
- MCP generator enhanced to support provider-specific configurations
|
93
|
+
|
1
94
|
## [0.1.20]
|
2
95
|
|
3
96
|
### Added
|
data/CLAUDE.md
CHANGED
@@ -18,6 +18,23 @@ bin/setup # Install dependencies
|
|
18
18
|
rake test # Run the Minitest test suite
|
19
19
|
```
|
20
20
|
|
21
|
+
**Important**: Tests should not generate any output to stdout or stderr. When writing tests:
|
22
|
+
- Capture or suppress all stdout/stderr output from tested methods
|
23
|
+
- Use `capture_io` or `capture_subprocess_io` for Minitest
|
24
|
+
- Redirect output streams to `StringIO` or `/dev/null` when necessary
|
25
|
+
- Mock or stub methods that produce console output
|
26
|
+
- Ensure clean test output for better CI/CD integration
|
27
|
+
|
28
|
+
Example:
|
29
|
+
```ruby
|
30
|
+
def test_command_with_output
|
31
|
+
output, err = capture_io do
|
32
|
+
# Code that produces output
|
33
|
+
end
|
34
|
+
# Test assertions here
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
21
38
|
### Linting
|
22
39
|
```bash
|
23
40
|
rake rubocop -A # Run RuboCop linter to auto fix problems
|
@@ -152,3 +169,47 @@ The gem includes comprehensive tests covering:
|
|
152
169
|
|
153
170
|
- **thor** (~> 1.3): Command-line interface framework
|
154
171
|
- **yaml**: Built-in Ruby YAML parser (no explicit dependency needed)
|
172
|
+
|
173
|
+
## Zeitwerk Autoloading
|
174
|
+
|
175
|
+
This project uses Zeitwerk for automatic class loading. Important guidelines:
|
176
|
+
|
177
|
+
### Require Statement Rules
|
178
|
+
|
179
|
+
1. **DO NOT include any require statements for lib files**: Zeitwerk automatically loads all classes under `lib/claude_swarm/`. Never use `require`, `require_relative`, or `require "claude_swarm/..."` for internal project files.
|
180
|
+
|
181
|
+
2. **All dependencies must be consolidated in lib/claude_swarm.rb**: Both standard library and external gem dependencies are required at the top of `lib/claude_swarm.rb`. This includes:
|
182
|
+
- Standard library dependencies (json, yaml, fileutils, etc.)
|
183
|
+
- External gem dependencies (thor, openai, mcp_client, fast_mcp_annotations)
|
184
|
+
|
185
|
+
3. **No requires in other lib files**: Individual files in `lib/claude_swarm/` should not have any require statements. They rely on:
|
186
|
+
- Dependencies loaded in `lib/claude_swarm.rb`
|
187
|
+
- Other classes autoloaded by Zeitwerk
|
188
|
+
|
189
|
+
### Example
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
# ✅ CORRECT - lib/claude_swarm.rb
|
193
|
+
# Standard library dependencies
|
194
|
+
require "json"
|
195
|
+
require "yaml"
|
196
|
+
require "fileutils"
|
197
|
+
# ... other standard libraries
|
198
|
+
|
199
|
+
# External dependencies
|
200
|
+
require "thor"
|
201
|
+
require "openai"
|
202
|
+
# ... other gems
|
203
|
+
|
204
|
+
# Zeitwerk setup
|
205
|
+
require "zeitwerk"
|
206
|
+
loader = Zeitwerk::Loader.for_gem
|
207
|
+
loader.setup
|
208
|
+
|
209
|
+
# ❌ INCORRECT - lib/claude_swarm/some_class.rb
|
210
|
+
require "json" # Don't do this!
|
211
|
+
require_relative "other_class" # Don't do this!
|
212
|
+
require "claude_swarm/configuration" # Don't do this!
|
213
|
+
```
|
214
|
+
|
215
|
+
This approach ensures clean dependency management and leverages Ruby's modern autoloading capabilities.
|
data/README.md
CHANGED
@@ -221,10 +221,70 @@ swarm:
|
|
221
221
|
- "echo 'Setting up environment...'"
|
222
222
|
- "npm install"
|
223
223
|
- "docker-compose up -d"
|
224
|
+
after: # Optional: commands to run after exiting the swarm
|
225
|
+
- "echo 'Cleaning up environment...'"
|
226
|
+
- "docker-compose down"
|
224
227
|
instances:
|
225
228
|
# Instance definitions...
|
226
229
|
```
|
227
230
|
|
231
|
+
#### Environment Variable Interpolation
|
232
|
+
|
233
|
+
Claude Swarm supports environment variable interpolation in all configuration values using the `${ENV_VAR_NAME}` syntax:
|
234
|
+
|
235
|
+
```yaml
|
236
|
+
version: 1
|
237
|
+
swarm:
|
238
|
+
name: "${APP_NAME} Development Team"
|
239
|
+
main: lead
|
240
|
+
instances:
|
241
|
+
lead:
|
242
|
+
description: "Lead developer for ${APP_NAME}"
|
243
|
+
directory: "${PROJECT_ROOT}"
|
244
|
+
model: "${CLAUDE_MODEL}"
|
245
|
+
prompt: "You are developing ${APP_NAME} version ${APP_VERSION}"
|
246
|
+
allowed_tools: ["${TOOL_1}", "${TOOL_2}", "Bash"]
|
247
|
+
mcps:
|
248
|
+
- name: github
|
249
|
+
type: stdio
|
250
|
+
command: "${MCP_GITHUB_PATH}"
|
251
|
+
env:
|
252
|
+
GITHUB_TOKEN: "${GITHUB_TOKEN}"
|
253
|
+
```
|
254
|
+
|
255
|
+
Features:
|
256
|
+
- Variables are interpolated recursively in strings, arrays, and nested structures
|
257
|
+
- Multiple variables can be used in the same string
|
258
|
+
- Partial string interpolation is supported (e.g., `"prefix-${VAR}-suffix"`)
|
259
|
+
- If a referenced environment variable is not set, Claude Swarm will exit with a clear error message
|
260
|
+
- Non-matching patterns like `$VAR` or `{VAR}` are preserved as-is
|
261
|
+
|
262
|
+
##### Default Values
|
263
|
+
|
264
|
+
Environment variables can have default values using the `${VAR_NAME:=default_value}` syntax:
|
265
|
+
|
266
|
+
```yaml
|
267
|
+
version: 1
|
268
|
+
swarm:
|
269
|
+
name: "Dev Team"
|
270
|
+
main: lead
|
271
|
+
instances:
|
272
|
+
lead:
|
273
|
+
description: "Lead developer"
|
274
|
+
directory: "${PROJECT_DIR:=.}"
|
275
|
+
model: "${CLAUDE_MODEL:=sonnet}"
|
276
|
+
mcps:
|
277
|
+
- name: api-server
|
278
|
+
type: sse
|
279
|
+
url: "${API_URL:=http://localhost:8080}"
|
280
|
+
worktree: "${BRANCH_NAME:=feature-branch}"
|
281
|
+
```
|
282
|
+
|
283
|
+
- Default values are used when the environment variable is not set
|
284
|
+
- Any string can be used as a default value, including spaces and special characters
|
285
|
+
- Empty defaults are supported: `${VAR:=}` results in an empty string if VAR is not set
|
286
|
+
- Works in all configuration values: strings, arrays, and nested structures
|
287
|
+
|
228
288
|
#### Instance Configuration
|
229
289
|
|
230
290
|
Each instance must have:
|
@@ -242,6 +302,24 @@ Each instance can have:
|
|
242
302
|
- **prompt**: Custom system prompt to append to the instance
|
243
303
|
- **vibe**: Enable vibe mode (--dangerously-skip-permissions) for this instance (default: false)
|
244
304
|
- **worktree**: Configure Git worktree usage for this instance (true/false/string)
|
305
|
+
- **provider**: AI provider to use - "claude" (default) or "openai"
|
306
|
+
|
307
|
+
#### OpenAI Provider Configuration
|
308
|
+
|
309
|
+
When using `provider: openai`, the following additional fields are available:
|
310
|
+
|
311
|
+
- **temperature**: Temperature for GPT models only (0.0-2.0). Not supported for O-series reasoning models (o1, o1-preview, o1-mini, o3, etc.)
|
312
|
+
- **api_version**: API version to use - "chat_completion" (default) or "responses"
|
313
|
+
- **openai_token_env**: Environment variable name for OpenAI API key (default: "OPENAI_API_KEY")
|
314
|
+
- **base_url**: Custom base URL for OpenAI API (optional)
|
315
|
+
- **reasoning_effort**: Reasoning effort for O-series models only - "low", "medium", or "high"
|
316
|
+
|
317
|
+
**Important Notes:**
|
318
|
+
- O-series models (o1, o1-preview, o1-mini, o3, etc.) use deterministic reasoning and do not support the `temperature` parameter
|
319
|
+
- The `reasoning_effort` parameter is only supported by O-series models
|
320
|
+
- GPT models support `temperature` but not `reasoning_effort`
|
321
|
+
- OpenAI instances default to and ONLY operate as `vibe: true` and use MCP for tool access
|
322
|
+
- By default it comes with Claude Code tools, connected with MCP to `claude mcp serve`
|
245
323
|
|
246
324
|
```yaml
|
247
325
|
instance_name:
|
@@ -268,6 +346,27 @@ instance_name:
|
|
268
346
|
args: ["arg1", "arg2"]
|
269
347
|
env:
|
270
348
|
VAR1: value1
|
349
|
+
|
350
|
+
# OpenAI instance examples
|
351
|
+
|
352
|
+
# GPT model with temperature
|
353
|
+
gpt_instance:
|
354
|
+
description: "OpenAI GPT-powered creative assistant"
|
355
|
+
provider: openai
|
356
|
+
model: gpt-4o
|
357
|
+
temperature: 0.7 # Supported for GPT models
|
358
|
+
api_version: chat_completion
|
359
|
+
openai_token_env: OPENAI_API_KEY
|
360
|
+
prompt: "You are a creative assistant specializing in content generation"
|
361
|
+
|
362
|
+
# O-series reasoning model with reasoning_effort
|
363
|
+
reasoning_instance:
|
364
|
+
description: "OpenAI O-series reasoning assistant"
|
365
|
+
provider: openai
|
366
|
+
model: o1-mini
|
367
|
+
reasoning_effort: medium # Only for O-series models
|
368
|
+
api_version: responses # Can use either API version
|
369
|
+
prompt: "You are a reasoning assistant for complex problem solving"
|
271
370
|
```
|
272
371
|
|
273
372
|
### MCP Server Types
|
@@ -459,9 +558,54 @@ When using multiple directories:
|
|
459
558
|
- Additional directories are accessible via the `--add-dir` flag in Claude
|
460
559
|
- All directories must exist or the configuration will fail validation
|
461
560
|
|
462
|
-
####
|
561
|
+
#### Mixed AI Provider Team
|
562
|
+
|
563
|
+
Combine Claude and OpenAI instances in a single swarm:
|
564
|
+
|
565
|
+
```yaml
|
566
|
+
version: 1
|
567
|
+
swarm:
|
568
|
+
name: "Mixed AI Development Team"
|
569
|
+
main: lead_developer
|
570
|
+
instances:
|
571
|
+
lead_developer:
|
572
|
+
description: "Claude lead developer coordinating the team"
|
573
|
+
directory: .
|
574
|
+
model: opus
|
575
|
+
connections: [creative_assistant, reasoning_expert, backend_dev]
|
576
|
+
prompt: "You are the lead developer coordinating a mixed AI team"
|
577
|
+
allowed_tools: [Read, Edit, Bash, Write]
|
578
|
+
|
579
|
+
creative_assistant:
|
580
|
+
description: "OpenAI-powered assistant for creative and UI/UX tasks"
|
581
|
+
provider: openai
|
582
|
+
model: gpt-4o
|
583
|
+
temperature: 0.7 # Supported for GPT models
|
584
|
+
directory: ./frontend
|
585
|
+
prompt: "You are a creative frontend developer specializing in UI/UX design"
|
586
|
+
# OpenAI instances default to vibe: true
|
587
|
+
|
588
|
+
reasoning_expert:
|
589
|
+
description: "OpenAI O-series model for complex problem solving"
|
590
|
+
provider: openai
|
591
|
+
model: o1-mini
|
592
|
+
reasoning_effort: high # For O-series models only
|
593
|
+
directory: ./architecture
|
594
|
+
prompt: "You solve complex architectural and algorithmic problems"
|
595
|
+
|
596
|
+
backend_dev:
|
597
|
+
description: "Claude backend developer for system architecture"
|
598
|
+
directory: ./backend
|
599
|
+
model: sonnet
|
600
|
+
prompt: "You specialize in backend development and system architecture"
|
601
|
+
allowed_tools: [Read, Edit, Write, Bash]
|
602
|
+
```
|
603
|
+
|
604
|
+
Note: OpenAI instances require the API key to be set in the environment variable (default: `OPENAI_API_KEY`).
|
463
605
|
|
464
|
-
|
606
|
+
#### Before and After Commands
|
607
|
+
|
608
|
+
You can specify commands to run before launching and after exiting the swarm using the `before` and `after` fields:
|
465
609
|
|
466
610
|
```yaml
|
467
611
|
version: 1
|
@@ -473,6 +617,10 @@ swarm:
|
|
473
617
|
- "npm install"
|
474
618
|
- "docker-compose up -d"
|
475
619
|
- "bundle install"
|
620
|
+
after:
|
621
|
+
- "echo '🛑 Cleaning up development environment...'"
|
622
|
+
- "docker-compose down"
|
623
|
+
- "rm -rf temp/*"
|
476
624
|
instances:
|
477
625
|
lead_developer:
|
478
626
|
description: "Lead developer coordinating the team"
|
@@ -483,16 +631,26 @@ swarm:
|
|
483
631
|
|
484
632
|
The `before` commands:
|
485
633
|
- Are executed in sequence before launching any Claude instances
|
634
|
+
- Execute in the main instance's directory (including worktree if enabled)
|
486
635
|
- Must all succeed for the swarm to launch (exit code 0)
|
487
636
|
- Are only executed on initial swarm launch, not when restoring sessions
|
488
637
|
- Have their output logged to the session log file
|
489
638
|
- Will abort the swarm launch if any command fails
|
490
639
|
|
640
|
+
The `after` commands:
|
641
|
+
- Are executed after Claude exits but before cleanup processes
|
642
|
+
- Execute in the main instance's directory (including worktree if enabled)
|
643
|
+
- Run even when the swarm is interrupted by signals (Ctrl+C)
|
644
|
+
- Failures do not prevent cleanup from proceeding
|
645
|
+
- Are only executed on initial swarm runs, not when restoring sessions
|
646
|
+
- Have their output logged to the session log file
|
647
|
+
|
491
648
|
This is useful for:
|
492
|
-
- Installing dependencies
|
649
|
+
- Installing dependencies in the isolated worktree environment
|
493
650
|
- Starting required services (databases, Docker containers, etc.)
|
494
651
|
- Setting up the development environment
|
495
652
|
- Running any prerequisite setup scripts
|
653
|
+
- Ensuring setup commands affect only the working directory, not the original repository
|
496
654
|
|
497
655
|
|
498
656
|
#### Mixed Permission Modes
|
@@ -598,8 +756,8 @@ swarm:
|
|
598
756
|
claude-swarm
|
599
757
|
|
600
758
|
# Specify a different configuration file
|
601
|
-
claude-swarm
|
602
|
-
claude-swarm
|
759
|
+
claude-swarm my-swarm.yml
|
760
|
+
claude-swarm team-config.yml
|
603
761
|
|
604
762
|
# Run with --dangerously-skip-permissions for all instances
|
605
763
|
claude-swarm --vibe
|
@@ -608,9 +766,11 @@ claude-swarm --vibe
|
|
608
766
|
claude-swarm -p "Implement the new user authentication feature"
|
609
767
|
claude-swarm --prompt "Fix the bug in the payment module"
|
610
768
|
|
611
|
-
#
|
612
|
-
claude-swarm --session-id
|
613
|
-
|
769
|
+
# Use a custom session ID instead of auto-generated UUID
|
770
|
+
claude-swarm --session-id my-custom-session-123
|
771
|
+
|
772
|
+
# Stream logs to stdout in prompt mode
|
773
|
+
claude-swarm -p "Fix the tests" --stream-logs
|
614
774
|
|
615
775
|
# Run all instances in Git worktrees
|
616
776
|
claude-swarm --worktree # Auto-generated name (worktree-SESSION_ID)
|
@@ -671,7 +831,7 @@ Example output from `claude-swarm ps`:
|
|
671
831
|
SESSION_ID SWARM_NAME TOTAL_COST UPTIME DIRECTORY
|
672
832
|
-------------------------------------------------------------------------------
|
673
833
|
20250617_235233 Feature Development $0.3847 15m .
|
674
|
-
20250617_143022 Bug Investigation $1.2156 1h
|
834
|
+
20250617_143022 Bug Investigation $1.2156 1h .
|
675
835
|
20250617_091547 Multi-Module Dev $0.8932 30m ./frontend, ./backend, ./shared
|
676
836
|
```
|
677
837
|
|
@@ -734,11 +894,8 @@ Output shows:
|
|
734
894
|
Resume a previous session with all instances restored to their Claude session states:
|
735
895
|
|
736
896
|
```bash
|
737
|
-
#
|
738
|
-
claude-swarm
|
739
|
-
|
740
|
-
# Resume by full path
|
741
|
-
claude-swarm --session-id ~/.claude-swarm/sessions/my-project/20250617_143022
|
897
|
+
# Restore using the session's UUID
|
898
|
+
claude-swarm restore 550e8400-e29b-41d4-a716-446655440000
|
742
899
|
```
|
743
900
|
|
744
901
|
This will:
|
@@ -810,7 +967,7 @@ The swarm will display:
|
|
810
967
|
|
811
968
|
### Session Files
|
812
969
|
|
813
|
-
Check the session directory `~/.claude-swarm/sessions/{project}/{
|
970
|
+
Check the session directory `~/.claude-swarm/sessions/{project}/{session-id}/` for:
|
814
971
|
- `session.log`: Human-readable logs with request/response tracking
|
815
972
|
- `session.log.json`: All events in JSONL format (one JSON object per line)
|
816
973
|
- `{instance}.mcp.json`: MCP configuration for each instance
|
data/Rakefile
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
version: 1
|
2
|
+
swarm:
|
3
|
+
name: "Mixed AI Team"
|
4
|
+
main: lead_developer
|
5
|
+
instances:
|
6
|
+
lead_developer:
|
7
|
+
description: "Claude lead developer coordinating the team"
|
8
|
+
directory: .
|
9
|
+
model: opus
|
10
|
+
prompt: "You are the lead developer coordinating a mixed AI team"
|
11
|
+
allowed_tools: [Read, Edit, Bash, Write]
|
12
|
+
connections: [openai_assistant]
|
13
|
+
|
14
|
+
openai_assistant:
|
15
|
+
description: "OpenAI-powered assistant for creative tasks"
|
16
|
+
directory: .
|
17
|
+
provider: openai
|
18
|
+
model: o3
|
19
|
+
api_version: responses
|
20
|
+
reasoning_effort: high # Optional: low, medium, or high
|
21
|
+
prompt: "You are a creative frontend developer using React and modern web technologies"
|
22
|
+
# OpenAI instances default to vibe: true
|
23
|
+
|
@@ -1,17 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "json"
|
4
|
-
require "open3"
|
5
|
-
require "logger"
|
6
|
-
require "fileutils"
|
7
|
-
|
8
3
|
module ClaudeSwarm
|
9
4
|
class ClaudeCodeExecutor
|
10
5
|
attr_reader :session_id, :last_response, :working_directory, :logger, :session_path
|
11
6
|
|
12
7
|
def initialize(working_directory: Dir.pwd, model: nil, mcp_config: nil, vibe: false,
|
13
|
-
|
14
|
-
|
8
|
+
instance_name: nil, instance_id: nil, calling_instance: nil, calling_instance_id: nil,
|
9
|
+
claude_session_id: nil, additional_directories: [])
|
15
10
|
@working_directory = working_directory
|
16
11
|
@additional_directories = additional_directories
|
17
12
|
@model = model
|
@@ -111,7 +106,7 @@ module ClaudeSwarm
|
|
111
106
|
instance_id: @instance_id,
|
112
107
|
claude_session_id: @session_id,
|
113
108
|
status: "active",
|
114
|
-
updated_at: Time.now.iso8601
|
109
|
+
updated_at: Time.now.iso8601,
|
115
110
|
}
|
116
111
|
|
117
112
|
File.write(state_file, JSON.pretty_generate(state_data))
|
@@ -158,7 +153,7 @@ module ClaudeSwarm
|
|
158
153
|
to_instance: @instance_name,
|
159
154
|
to_instance_id: @instance_id,
|
160
155
|
prompt: prompt,
|
161
|
-
timestamp: Time.now.iso8601
|
156
|
+
timestamp: Time.now.iso8601,
|
162
157
|
}
|
163
158
|
|
164
159
|
append_to_session_json(event)
|
@@ -170,7 +165,7 @@ module ClaudeSwarm
|
|
170
165
|
instance_info = @instance_name
|
171
166
|
instance_info += " (#{@instance_id})" if @instance_id
|
172
167
|
@logger.info(
|
173
|
-
"($#{response["total_cost"]} - #{response["duration_ms"]}ms) #{instance_info} -> #{caller_info}: \n---\n#{response["result"]}\n---"
|
168
|
+
"($#{response["total_cost"]} - #{response["duration_ms"]}ms) #{instance_info} -> #{caller_info}: \n---\n#{response["result"]}\n---",
|
174
169
|
)
|
175
170
|
end
|
176
171
|
|
@@ -207,7 +202,7 @@ module ClaudeSwarm
|
|
207
202
|
instance_info = @instance_name
|
208
203
|
instance_info += " (#{@instance_id})" if @instance_id
|
209
204
|
@logger.info(
|
210
|
-
"Tool call from #{instance_info} -> Tool: #{tool_call["name"]}, ID: #{tool_call["id"]}, Arguments: #{arguments}"
|
205
|
+
"Tool call from #{instance_info} -> Tool: #{tool_call["name"]}, ID: #{tool_call["id"]}, Arguments: #{arguments}",
|
211
206
|
)
|
212
207
|
end
|
213
208
|
|
@@ -238,7 +233,7 @@ module ClaudeSwarm
|
|
238
233
|
calling_instance: @calling_instance,
|
239
234
|
calling_instance_id: @calling_instance_id,
|
240
235
|
timestamp: Time.now.iso8601,
|
241
|
-
event: event
|
236
|
+
event: event,
|
242
237
|
}
|
243
238
|
|
244
239
|
# Write as single line JSON (JSONL format)
|