claude_swarm 0.3.2 → 1.0.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/.claude/commands/release.md +27 -0
- data/CHANGELOG.md +174 -0
- data/CLAUDE.md +62 -3
- data/README.md +131 -5
- data/examples/simple-session-hook-swarm.yml +37 -0
- data/lib/claude_swarm/base_executor.rb +133 -0
- data/lib/claude_swarm/claude_code_executor.rb +245 -210
- data/lib/claude_swarm/claude_mcp_server.rb +3 -2
- data/lib/claude_swarm/cli.rb +27 -20
- data/lib/claude_swarm/commands/ps.rb +29 -10
- data/lib/claude_swarm/commands/show.rb +4 -5
- data/lib/claude_swarm/configuration.rb +19 -12
- data/lib/claude_swarm/hooks/session_start_hook.rb +42 -0
- data/lib/claude_swarm/json_handler.rb +91 -0
- data/lib/claude_swarm/mcp_generator.rb +7 -5
- data/lib/claude_swarm/openai/chat_completion.rb +16 -16
- data/lib/claude_swarm/openai/executor.rb +155 -209
- data/lib/claude_swarm/openai/responses.rb +29 -29
- data/lib/claude_swarm/orchestrator.rb +452 -257
- data/lib/claude_swarm/session_cost_calculator.rb +130 -14
- data/lib/claude_swarm/session_path.rb +2 -8
- data/lib/claude_swarm/settings_generator.rb +77 -0
- data/lib/claude_swarm/system_utils.rb +6 -2
- data/lib/claude_swarm/templates/generation_prompt.md.erb +6 -6
- data/lib/claude_swarm/tools/task_tool.rb +13 -1
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm/worktree_manager.rb +2 -2
- data/lib/claude_swarm.rb +23 -2
- data/team.yml +75 -3
- data/team_v2.yml +367 -0
- metadata +54 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be01b40a18b703189532df1e653c15e406c0b798b220c20fe1f014a35331e213
|
|
4
|
+
data.tar.gz: a4eddd8c10cb1974e9693c27cb9d6660117bd781a4ed16ef52dc1408b4c414d2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8207b22b7d3514e910d9f4c72ba7c99e5f5b2f5034e532fa8708ae5d9e9219047153d54ac148c688114cc3f9bd167a4e7a16ceed9439512fe9f1c60c77f8d63
|
|
7
|
+
data.tar.gz: 53cfc85b8898b8906372e5518913de7c373e98ca2a7de1202f343f1d93f9efc566ed21acee1529f8bc9945e3e60f0cde335040dd49a9d582f723ea739c790c4e
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bump version, update changelog, and prepare for release
|
|
3
|
+
allowed-tools: [Read, Edit, Bash]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Prepare a new release for Claude Swarm by:
|
|
7
|
+
|
|
8
|
+
1. Read the current version from @lib/claude_swarm/version.rb
|
|
9
|
+
2. Determine the new version number: $ARGUMENTS (should be in format like 0.3.11 or use patch/minor/major)
|
|
10
|
+
3. Update the version in @lib/claude_swarm/version.rb
|
|
11
|
+
4. Update @CHANGELOG.md:
|
|
12
|
+
- Change "## [Unreleased]" to "## [new_version]"
|
|
13
|
+
- Add a new "## [Unreleased]" section at the top for future changes
|
|
14
|
+
5. Run these commands:
|
|
15
|
+
- `git add .`
|
|
16
|
+
- `bundle install`
|
|
17
|
+
- `git add .`
|
|
18
|
+
- `git commit -m "Release version X.X.X"`
|
|
19
|
+
- `git push`
|
|
20
|
+
|
|
21
|
+
Make sure all tests pass before releasing. The version argument should be either:
|
|
22
|
+
- A specific version number (e.g., 0.3.11)
|
|
23
|
+
- "patch" for incrementing the patch version (0.3.10 -> 0.3.11)
|
|
24
|
+
- "minor" for incrementing the minor version (0.3.10 -> 0.4.0)
|
|
25
|
+
- "major" for incrementing the major version (0.3.10 -> 1.0.0)
|
|
26
|
+
|
|
27
|
+
If no argument is provided, default to "patch".
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,177 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [1.0.0]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **HTTP MCP server configuration support**: Added support for HTTP-type MCP servers alongside existing stdio and SSE types
|
|
7
|
+
- HTTP servers can be configured with a `url` field
|
|
8
|
+
- Properly preserves server type (http/sse) in generated configurations
|
|
9
|
+
- Full compatibility with Claude Code's HTTP MCP server implementation
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Updated dependency from fast-mcp-annotations to fast-mcp gem**: Migrated to the consolidated fast-mcp gem (~> 1.6)
|
|
13
|
+
- Consolidates MCP functionality into a single, more maintainable gem
|
|
14
|
+
- Maintains all existing functionality with improved performance
|
|
15
|
+
- **Updated claude-code-sdk-ruby dependency**: Minimum version requirement increased to 0.1.6
|
|
16
|
+
- Includes latest SDK improvements and bug fixes
|
|
17
|
+
- Better error handling and stability
|
|
18
|
+
- **Swarm generation improvements**: Generator now avoids creating swarms with circular dependencies
|
|
19
|
+
- Prevents generation of invalid configurations
|
|
20
|
+
- Improves reliability of generated swarm templates
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **Empty response validation**: Added validation to prevent empty or nil responses from being passed to MCP callers
|
|
24
|
+
- ClaudeCodeExecutor now validates that Claude SDK returns non-empty result content
|
|
25
|
+
- TaskTool validates response structure and content before returning to MCP caller
|
|
26
|
+
- Clear error messages indicate when agent completes execution but provides no response
|
|
27
|
+
- Prevents silent failures when Claude SDK returns empty results
|
|
28
|
+
- **Before commands directory handling**: Fixed error when before commands need to create the main instance directory
|
|
29
|
+
- Smart directory detection: if the main instance directory exists, commands run inside it (for `npm install`, etc.)
|
|
30
|
+
- If the directory doesn't exist, commands run in the parent directory (allowing `mkdir` commands to create it)
|
|
31
|
+
- Works correctly with both regular directories and Git worktrees
|
|
32
|
+
- After commands follow the same logic for consistency
|
|
33
|
+
- Fixes "No such file or directory @ dir_chdir" errors when before commands create directories
|
|
34
|
+
|
|
35
|
+
### Internal
|
|
36
|
+
- **Centralized JSON handling**: Added JsonHandler class for consistent JSON parsing and generation
|
|
37
|
+
- Improved error handling for malformed JSON files
|
|
38
|
+
- Standardized JSON output formatting across all modules
|
|
39
|
+
- **Centralized CLAUDE_SWARM_HOME handling**: Refactored environment variable management for cleaner code
|
|
40
|
+
- **Enhanced test coverage**: Added comprehensive configuration tests and enabled branch coverage in SimpleCov
|
|
41
|
+
- Extensive validation of edge cases including circular dependencies
|
|
42
|
+
- Better coverage metrics with branch coverage enabled
|
|
43
|
+
|
|
44
|
+
## [0.3.11]
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- **Deferred directory validation for before commands**: Directories are now validated after `before` commands run, allowing them to create required directories
|
|
48
|
+
- Automatically skips initial directory validation when `before` commands are present in configuration
|
|
49
|
+
- Validates all directories after `before` commands complete successfully
|
|
50
|
+
- Enables dynamic directory creation workflows without pre-creating directory structures
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- **--root-dir parameter path resolution**: Fixed relative config file paths to be resolved relative to the --root-dir value instead of current directory
|
|
54
|
+
- Config paths are now expanded using the root directory as the base path
|
|
55
|
+
- Allows running claude-swarm from any location with consistent path resolution
|
|
56
|
+
- Absolute paths continue to work as expected regardless of --root-dir setting
|
|
57
|
+
|
|
58
|
+
### Improved
|
|
59
|
+
- **Enhanced worktree cleanup on errors**: Improved error handling to ensure worktrees are always cleaned up properly
|
|
60
|
+
- Added comprehensive error handling with cleanup at all failure points
|
|
61
|
+
- Worktrees are now cleaned up when worktree setup fails, before commands fail, or directory validation fails
|
|
62
|
+
- Prevents orphaned worktrees that could clutter the system or cause issues with future runs
|
|
63
|
+
|
|
64
|
+
## [0.3.10]
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- **Token-based cost calculation for main instance**: Main instance costs in interactive mode are now calculated from token usage using Claude model pricing
|
|
68
|
+
- Opus: $15/MTok input, $75/MTok output, $18.75/MTok cache write, $1.50/MTok cache read
|
|
69
|
+
- Sonnet: $3/MTok input, $15/MTok output, $3.75/MTok cache write, $0.30/MTok cache read
|
|
70
|
+
- Haiku: $0.80/MTok input, $4/MTok output, $1/MTok cache write, $0.08/MTok cache read
|
|
71
|
+
- Automatically extracts usage data from assistant messages in session logs
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
- **Simplified cost calculation**: Switched from cumulative `total_cost_usd` to per-request `cost_usd` for non-main instances
|
|
75
|
+
- Removed complex session reset detection logic
|
|
76
|
+
- Now uses simple summation of individual request costs
|
|
77
|
+
- More accurate and maintainable cost tracking
|
|
78
|
+
- **Improved ps command cost display**:
|
|
79
|
+
- Only shows cost warning when sessions are missing main instance data
|
|
80
|
+
- Adds asterisk (*) indicator to costs that exclude main instance
|
|
81
|
+
- Displays accurate total costs including main instance when available
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- **Main instance log format consistency**: Fixed transcript logs in interactive mode to match standard instance log format
|
|
85
|
+
- Converted transcript wrapper to request/assistant event structure
|
|
86
|
+
- Properly extracts text content from nested message arrays
|
|
87
|
+
- Ensures uniform log parsing across all instances
|
|
88
|
+
|
|
89
|
+
## [0.3.9]
|
|
90
|
+
|
|
91
|
+
### Added
|
|
92
|
+
- **Main instance transcript integration**: Main Claude instance activity is now captured in session.log.json during interactive mode
|
|
93
|
+
- Automatically configures SessionStart hook for main instance to capture transcript path
|
|
94
|
+
- Background thread continuously tails transcript file and integrates entries into session.log.json
|
|
95
|
+
- Filters out summary entries to avoid duplicate conversation titles
|
|
96
|
+
- Uses file locking for thread-safe writes to maintain consistency
|
|
97
|
+
- Provides complete session history including main instance interactions
|
|
98
|
+
|
|
99
|
+
## [0.3.8]
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
- **Hooks support**: Claude Swarm now supports configuring Claude Code hooks for each instance
|
|
103
|
+
- Configure hooks directly in the YAML configuration file using Claude Code's format
|
|
104
|
+
- Each instance can have its own hooks configuration (PreToolUse, PostToolUse, UserPromptSubmit, etc.)
|
|
105
|
+
- Automatically generates `settings.json` files in the session directory when hooks are configured
|
|
106
|
+
- Main instance receives hooks via `--settings` CLI flag
|
|
107
|
+
- Connected instances receive hooks via SDK's `settings` attribute
|
|
108
|
+
- Full environment variable interpolation support in hook configurations
|
|
109
|
+
- See README.md "Hooks Configuration" section for usage examples
|
|
110
|
+
- **Persistent HTTP connections for OpenAI**: Added `faraday-net_http_persistent` dependency and configured OpenAI client to use persistent connections
|
|
111
|
+
- Improves performance when making multiple API requests by reusing HTTP connections
|
|
112
|
+
- Automatically configured for all OpenAI instances
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
- **Improved OpenAI executor code organization**: Refactored internal methods for better maintainability
|
|
116
|
+
- Extracted configuration building and response handling into focused private methods
|
|
117
|
+
- Improved code readability with functional patterns
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
- **Settings integration**: Fixed passing settings to Claude instances
|
|
121
|
+
- Corrected SDK attribute name from `settings_path` to `settings`
|
|
122
|
+
- Added missing `--settings` flag for main instance CLI command
|
|
123
|
+
|
|
124
|
+
## [0.3.7]
|
|
125
|
+
|
|
126
|
+
### Added
|
|
127
|
+
- **Main instance logging**: Captures main Claude instance output in `session.log` with prettified JSON format
|
|
128
|
+
|
|
129
|
+
### Changed
|
|
130
|
+
- **Updated claude-code-sdk-ruby dependency**: Bumped from 0.1.4 to 0.1.6
|
|
131
|
+
- Includes latest SDK improvements and bug fixes
|
|
132
|
+
|
|
133
|
+
## [0.3.6]
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
- **SSE MCP server headers support**: SSE-type MCP servers can now include custom headers for authentication
|
|
137
|
+
- Supports headers like `Authorization: "Bearer ${TOKEN}"` in MCP configurations
|
|
138
|
+
- Environment variables in header values are automatically interpolated
|
|
139
|
+
- **Comprehensive retry middleware for OpenAI API calls**: Added robust retry logic for OpenAI provider to handle API errors gracefully
|
|
140
|
+
- Automatically retries on rate limit errors (429) with exponential backoff
|
|
141
|
+
- Retries on server errors (500, 502, 503, 504) and timeout errors
|
|
142
|
+
- Configurable retry attempts, delay, and backoff settings
|
|
143
|
+
- Detailed logging of retry attempts and errors
|
|
144
|
+
|
|
145
|
+
## [0.3.5]
|
|
146
|
+
|
|
147
|
+
### Changed
|
|
148
|
+
- Relaxed dependency version constraints for better flexibility
|
|
149
|
+
- `claude-code-sdk-ruby`: from `~> 0.1.0` to `~> 0.1`
|
|
150
|
+
- `fast-mcp-annotations`: from `~> 1.5.3` to `~> 1.5`
|
|
151
|
+
|
|
152
|
+
## [0.3.4]
|
|
153
|
+
|
|
154
|
+
### Changed
|
|
155
|
+
- Add tests for thinking_budget feature by @parruda in https://github.com/parruda/claude-swarm/pull/85
|
|
156
|
+
- Improve process group handling and signal management by @ericproulx in https://github.com/parruda/claude-swarm/pull/87
|
|
157
|
+
- Migrated from CLI to SDK-based execution**: Claude Swarm now uses the `claude-code-sdk-ruby` gem instead of executing Claude Code via CLI
|
|
158
|
+
- Removed CLI-based `ClaudeCodeExecutor` implementation that used `Open3.popen3`
|
|
159
|
+
- All Claude Code execution now uses the SDK for improved reliability and performance
|
|
160
|
+
- Session management and logging functionality remains unchanged
|
|
161
|
+
- MCP configuration parsing updated to convert JSON format to SDK hash format
|
|
162
|
+
- Supports all MCP server types: stdio, sse, and http
|
|
163
|
+
- This change is transparent to users but may affect custom integrations that relied on CLI-specific behavior
|
|
164
|
+
|
|
165
|
+
### Added
|
|
166
|
+
- **SDK dependency**: Added `claude-code-sdk-ruby` (~> 0.1.0)
|
|
167
|
+
|
|
168
|
+
## [0.3.3]
|
|
169
|
+
|
|
170
|
+
### Fixed
|
|
171
|
+
- **Bundler constant error**: Fixed `uninitialized constant ClaudeSwarm::Orchestrator::Bundler` error by adding missing `require "bundler"` statement
|
|
172
|
+
- Issue occurred when using `Bundler.with_unbundled_env` without properly requiring the bundler gem
|
|
173
|
+
- Resolves issue #83 reported by users upgrading to version 0.3.2
|
|
174
|
+
|
|
1
175
|
## [0.3.2]
|
|
2
176
|
|
|
3
177
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -6,6 +6,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
6
6
|
|
|
7
7
|
Claude Swarm is a Ruby gem that orchestrates multiple Claude Code instances as a collaborative AI development team. It enables running AI agents with specialized roles, tools, and directory contexts, communicating via MCP (Model Context Protocol).
|
|
8
8
|
|
|
9
|
+
SwarmCore is a complete reimagining of Claude Swarm that decouples from Claude Code and runs everything in a single process using RubyLLM for all LLM interactions. It is being developed in `lib/swarm_core`, and using the gemspec swarm-core.gemspec.
|
|
10
|
+
|
|
9
11
|
## Development Commands
|
|
10
12
|
|
|
11
13
|
### Testing
|
|
@@ -93,6 +95,16 @@ instances:
|
|
|
93
95
|
- Existing worktrees with the same name are reused
|
|
94
96
|
- The `claude-swarm clean` command removes orphaned worktrees
|
|
95
97
|
|
|
98
|
+
## Claude Code SDK Integration
|
|
99
|
+
|
|
100
|
+
Claude Swarm uses the Claude Code SDK (`claude-code-sdk-ruby`) for all Claude instances. This provides:
|
|
101
|
+
- Better performance and reliability
|
|
102
|
+
- Structured message handling
|
|
103
|
+
- Improved error recovery
|
|
104
|
+
- Direct MCP server configuration support (stdio, sse, http)
|
|
105
|
+
|
|
106
|
+
The SDK executor handles all three MCP server types and properly converts MCP JSON configurations to SDK format.
|
|
107
|
+
|
|
96
108
|
## Architecture
|
|
97
109
|
|
|
98
110
|
The gem is fully implemented with the following components:
|
|
@@ -120,9 +132,10 @@ The gem is fully implemented with the following components:
|
|
|
120
132
|
1. User creates a `claude-swarm.yml` file defining the swarm topology
|
|
121
133
|
2. Running `claude-swarm` parses the configuration and validates it
|
|
122
134
|
3. MCP configuration files are generated for each instance in a session directory
|
|
123
|
-
4.
|
|
124
|
-
5.
|
|
125
|
-
6.
|
|
135
|
+
4. Settings files (with hooks) are generated for each instance if hooks are configured
|
|
136
|
+
5. The main instance is launched with `exec`, replacing the current process
|
|
137
|
+
6. Connected instances are available as MCP servers to the main instance
|
|
138
|
+
7. When an instance has connections, those connections are automatically added to its allowed tools as `mcp__<connection_name>`
|
|
126
139
|
|
|
127
140
|
### Configuration Example
|
|
128
141
|
|
|
@@ -149,6 +162,52 @@ swarm:
|
|
|
149
162
|
worktree: false # Optional: disable worktree for this instance
|
|
150
163
|
```
|
|
151
164
|
|
|
165
|
+
### Hooks Support
|
|
166
|
+
|
|
167
|
+
Claude Swarm supports configuring [Claude Code hooks](https://docs.anthropic.com/en/docs/claude-code/hooks) for each instance. This allows you to run custom scripts before/after tools, on prompt submission, and more.
|
|
168
|
+
|
|
169
|
+
#### Configuration Example with Hooks
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
version: 1
|
|
173
|
+
swarm:
|
|
174
|
+
name: "Dev Team"
|
|
175
|
+
main: lead
|
|
176
|
+
instances:
|
|
177
|
+
lead:
|
|
178
|
+
description: "Lead developer"
|
|
179
|
+
directory: .
|
|
180
|
+
model: opus
|
|
181
|
+
# Hooks configuration follows Claude Code's format exactly
|
|
182
|
+
hooks:
|
|
183
|
+
PreToolUse:
|
|
184
|
+
- matcher: "Write|Edit"
|
|
185
|
+
hooks:
|
|
186
|
+
- type: "command"
|
|
187
|
+
command: "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-code.py"
|
|
188
|
+
timeout: 10
|
|
189
|
+
PostToolUse:
|
|
190
|
+
- matcher: "Bash"
|
|
191
|
+
hooks:
|
|
192
|
+
- type: "command"
|
|
193
|
+
command: "echo 'Command executed by lead' >> /tmp/lead.log"
|
|
194
|
+
UserPromptSubmit:
|
|
195
|
+
- hooks:
|
|
196
|
+
- type: "command"
|
|
197
|
+
command: "$CLAUDE_PROJECT_DIR/.claude/hooks/add-context.py"
|
|
198
|
+
frontend:
|
|
199
|
+
description: "Frontend developer"
|
|
200
|
+
directory: ./frontend
|
|
201
|
+
hooks:
|
|
202
|
+
PreToolUse:
|
|
203
|
+
- matcher: "Write"
|
|
204
|
+
hooks:
|
|
205
|
+
- type: "command"
|
|
206
|
+
command: "npm run lint"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The hooks configuration is passed directly to Claude Code via a generated settings.json file in the session directory. Each instance gets its own settings file with its specific hooks.
|
|
210
|
+
|
|
152
211
|
## Testing
|
|
153
212
|
|
|
154
213
|
The gem includes comprehensive tests covering:
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Claude Swarm
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/rb/claude_swarm)
|
|
4
4
|
[](https://github.com/parruda/claude-swarm/actions/workflows/ci.yml)
|
|
5
5
|
|
|
6
6
|
Claude Swarm orchestrates multiple Claude Code instances as a collaborative AI development team. It enables running AI agents with specialized roles, tools, and directory contexts, communicating via MCP (Model Context Protocol) in a tree-like hierarchy. Define your swarm topology in simple YAML and let Claude instances delegate tasks through connected instances. Perfect for complex projects requiring specialized AI agents for frontend, backend, testing, DevOps, or research tasks.
|
|
@@ -42,7 +42,7 @@ gem install claude_swarm
|
|
|
42
42
|
Or add it to your Gemfile:
|
|
43
43
|
|
|
44
44
|
```ruby
|
|
45
|
-
gem 'claude_swarm'
|
|
45
|
+
gem 'claude_swarm', "~> 0.3.2"
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Then run:
|
|
@@ -228,6 +228,53 @@ swarm:
|
|
|
228
228
|
# Instance definitions...
|
|
229
229
|
```
|
|
230
230
|
|
|
231
|
+
#### YAML Aliases
|
|
232
|
+
|
|
233
|
+
Claude Swarm supports [YAML aliases](https://yaml.org/spec/1.2.2/#71-alias-nodes) to reduce duplication in your configuration. This is particularly useful for sharing common values like prompts, tool lists, or MCP configurations across multiple instances:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
version: 1
|
|
237
|
+
swarm:
|
|
238
|
+
name: "Development Team"
|
|
239
|
+
main: lead
|
|
240
|
+
instances:
|
|
241
|
+
lead:
|
|
242
|
+
description: "Lead developer"
|
|
243
|
+
prompt: &shared_prompt "You are an expert developer following best practices"
|
|
244
|
+
allowed_tools: &standard_tools
|
|
245
|
+
- Read
|
|
246
|
+
- Edit
|
|
247
|
+
- Bash
|
|
248
|
+
- WebSearch
|
|
249
|
+
mcps: &common_mcps
|
|
250
|
+
- name: github
|
|
251
|
+
type: stdio
|
|
252
|
+
command: gh
|
|
253
|
+
args: ["mcp"]
|
|
254
|
+
|
|
255
|
+
frontend:
|
|
256
|
+
description: "Frontend developer"
|
|
257
|
+
prompt: *shared_prompt # Reuses the same prompt
|
|
258
|
+
allowed_tools: *standard_tools # Reuses the same tool list
|
|
259
|
+
mcps: *common_mcps # Reuses the same MCP servers
|
|
260
|
+
directory: ./frontend
|
|
261
|
+
|
|
262
|
+
backend:
|
|
263
|
+
description: "Backend developer"
|
|
264
|
+
prompt: *shared_prompt # Reuses the same prompt
|
|
265
|
+
allowed_tools: *standard_tools # Reuses the same tool list
|
|
266
|
+
mcps: *common_mcps # Reuses the same MCP servers
|
|
267
|
+
directory: ./backend
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
In this example:
|
|
271
|
+
- `&shared_prompt` defines an anchor for the prompt string
|
|
272
|
+
- `&standard_tools` defines an anchor for the tool array
|
|
273
|
+
- `&common_mcps` defines an anchor for the MCP configuration
|
|
274
|
+
- `*shared_prompt`, `*standard_tools`, and `*common_mcps` reference those anchors
|
|
275
|
+
|
|
276
|
+
This helps maintain consistency across instances and makes configuration updates easier.
|
|
277
|
+
|
|
231
278
|
#### Environment Variable Interpolation
|
|
232
279
|
|
|
233
280
|
Claude Swarm supports environment variable interpolation in all configuration values using the `${ENV_VAR_NAME}` syntax:
|
|
@@ -303,6 +350,7 @@ Each instance can have:
|
|
|
303
350
|
- **vibe**: Enable vibe mode (--dangerously-skip-permissions) for this instance (default: false)
|
|
304
351
|
- **worktree**: Configure Git worktree usage for this instance (true/false/string)
|
|
305
352
|
- **provider**: AI provider to use - "claude" (default) or "openai"
|
|
353
|
+
- **hooks**: Configure Claude Code hooks for this instance (see Hooks Configuration section below)
|
|
306
354
|
|
|
307
355
|
#### OpenAI Provider Configuration
|
|
308
356
|
|
|
@@ -389,8 +437,85 @@ mcps:
|
|
|
389
437
|
- name: remote_api
|
|
390
438
|
type: sse
|
|
391
439
|
url: "https://api.example.com/mcp"
|
|
440
|
+
headers: # Optional: custom headers for authentication
|
|
441
|
+
Authorization: "Bearer ${API_TOKEN}"
|
|
442
|
+
X-Custom-Header: "value"
|
|
392
443
|
```
|
|
393
444
|
|
|
445
|
+
#### http (HTTP-based MCP)
|
|
446
|
+
```yaml
|
|
447
|
+
mcps:
|
|
448
|
+
- name: http_service
|
|
449
|
+
type: http
|
|
450
|
+
url: "https://api.example.com/mcp-endpoint"
|
|
451
|
+
headers: # Optional: custom headers for authentication
|
|
452
|
+
Authorization: "Bearer ${API_TOKEN}"
|
|
453
|
+
X-API-Key: "${API_KEY}"
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Hooks Configuration
|
|
457
|
+
|
|
458
|
+
Claude Swarm supports configuring [Claude Code hooks](https://docs.anthropic.com/en/docs/claude-code/hooks) for each instance. Hooks allow you to run custom scripts before/after tools, on prompt submission, and more. Each instance can have its own hooks configuration.
|
|
459
|
+
|
|
460
|
+
#### Supported Hook Events
|
|
461
|
+
|
|
462
|
+
- **PreToolUse**: Run before a tool is executed
|
|
463
|
+
- **PostToolUse**: Run after a tool completes
|
|
464
|
+
- **UserPromptSubmit**: Run when a user prompt is submitted
|
|
465
|
+
- **Stop**: Run when the Claude instance stops
|
|
466
|
+
- **SessionStart**: Run when a session starts
|
|
467
|
+
- **And more...** (see Claude Code hooks documentation)
|
|
468
|
+
|
|
469
|
+
#### Configuration Example
|
|
470
|
+
|
|
471
|
+
```yaml
|
|
472
|
+
instances:
|
|
473
|
+
lead:
|
|
474
|
+
description: "Lead developer"
|
|
475
|
+
directory: .
|
|
476
|
+
# Hooks configuration follows Claude Code's format exactly
|
|
477
|
+
hooks:
|
|
478
|
+
PreToolUse:
|
|
479
|
+
- matcher: "Write|Edit"
|
|
480
|
+
hooks:
|
|
481
|
+
- type: "command"
|
|
482
|
+
command: "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-code.py"
|
|
483
|
+
timeout: 10
|
|
484
|
+
PostToolUse:
|
|
485
|
+
- matcher: "Bash"
|
|
486
|
+
hooks:
|
|
487
|
+
- type: "command"
|
|
488
|
+
command: "echo 'Bash executed by ${INSTANCE_NAME}' >> ${LOG_DIR}/commands.log"
|
|
489
|
+
UserPromptSubmit:
|
|
490
|
+
- hooks:
|
|
491
|
+
- type: "command"
|
|
492
|
+
command: "${HOOKS_DIR:=$CLAUDE_PROJECT_DIR/.claude/hooks}/add-context.py"
|
|
493
|
+
frontend:
|
|
494
|
+
description: "Frontend developer"
|
|
495
|
+
directory: ./frontend
|
|
496
|
+
hooks:
|
|
497
|
+
PreToolUse:
|
|
498
|
+
- matcher: "Write"
|
|
499
|
+
hooks:
|
|
500
|
+
- type: "command"
|
|
501
|
+
command: "npm run lint"
|
|
502
|
+
timeout: 5
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
#### How It Works
|
|
506
|
+
|
|
507
|
+
1. Define hooks in your instance configuration using the exact format expected by Claude Code
|
|
508
|
+
2. Claude Swarm generates a `settings.json` file for each instance with hooks
|
|
509
|
+
3. The settings file is passed to Claude Code SDK via the `--settings` parameter
|
|
510
|
+
4. Each instance runs with its own hooks configuration
|
|
511
|
+
|
|
512
|
+
#### Environment Variables in Hooks
|
|
513
|
+
|
|
514
|
+
Hooks have access to standard Claude Code environment variables plus:
|
|
515
|
+
- `$CLAUDE_PROJECT_DIR` - The project directory
|
|
516
|
+
- `$CLAUDE_SWARM_SESSION_DIR` - The swarm session directory
|
|
517
|
+
- `$CLAUDE_SWARM_INSTANCE_NAME` - The name of the current instance
|
|
518
|
+
|
|
394
519
|
### Tools
|
|
395
520
|
|
|
396
521
|
Specify which tools each instance can use:
|
|
@@ -757,8 +882,8 @@ swarm:
|
|
|
757
882
|
claude-swarm
|
|
758
883
|
|
|
759
884
|
# Specify a different configuration file
|
|
760
|
-
claude-swarm my-swarm.yml
|
|
761
|
-
claude-swarm team-config.yml
|
|
885
|
+
claude-swarm start my-swarm.yml
|
|
886
|
+
claude-swarm start team-config.yml
|
|
762
887
|
|
|
763
888
|
# Run with --dangerously-skip-permissions for all instances
|
|
764
889
|
claude-swarm --vibe
|
|
@@ -978,6 +1103,7 @@ Check the session directory `~/.claude-swarm/sessions/{project}/{session-id}/` f
|
|
|
978
1103
|
- `{instance}.mcp.json`: MCP configuration for each instance
|
|
979
1104
|
- All files for a session are kept together for easy review
|
|
980
1105
|
|
|
1106
|
+
|
|
981
1107
|
## Architecture
|
|
982
1108
|
|
|
983
1109
|
Claude Swarm consists of these core components:
|
|
@@ -986,7 +1112,7 @@ Claude Swarm consists of these core components:
|
|
|
986
1112
|
- **ClaudeSwarm::Configuration** (`configuration.rb`): YAML parser and validator with path expansion
|
|
987
1113
|
- **ClaudeSwarm::McpGenerator** (`mcp_generator.rb`): Generates MCP JSON configs for each instance
|
|
988
1114
|
- **ClaudeSwarm::Orchestrator** (`orchestrator.rb`): Launches the main Claude instance with shared session management
|
|
989
|
-
- **ClaudeSwarm::ClaudeCodeExecutor** (`claude_code_executor.rb`):
|
|
1115
|
+
- **ClaudeSwarm::ClaudeCodeExecutor** (`claude_code_executor.rb`): Executor for Claude Code with session persistence
|
|
990
1116
|
- **ClaudeSwarm::ClaudeMcpServer** (`claude_mcp_server.rb`): FastMCP-based server providing task execution, session info, and reset capabilities
|
|
991
1117
|
|
|
992
1118
|
## Development
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
swarm:
|
|
3
|
+
name: "Simple Session Hook Swarm"
|
|
4
|
+
main: developer
|
|
5
|
+
instances:
|
|
6
|
+
developer:
|
|
7
|
+
description: "Main developer instance"
|
|
8
|
+
directory: .
|
|
9
|
+
model: sonnet
|
|
10
|
+
allowed_tools:
|
|
11
|
+
- Read
|
|
12
|
+
- Edit
|
|
13
|
+
- Write
|
|
14
|
+
- Bash
|
|
15
|
+
connections: [session_tracker]
|
|
16
|
+
prompt: |
|
|
17
|
+
You are the main developer. You can delegate session tracking tasks to the session_tracker instance.
|
|
18
|
+
|
|
19
|
+
For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
|
|
20
|
+
|
|
21
|
+
session_tracker:
|
|
22
|
+
description: "Session tracking specialist that monitors and logs session information"
|
|
23
|
+
directory: .
|
|
24
|
+
model: sonnet
|
|
25
|
+
allowed_tools:
|
|
26
|
+
- Write
|
|
27
|
+
- Bash
|
|
28
|
+
hooks:
|
|
29
|
+
SessionStart:
|
|
30
|
+
- hooks:
|
|
31
|
+
- type: "command"
|
|
32
|
+
command: "cat > session_id.txt"
|
|
33
|
+
timeout: 5
|
|
34
|
+
prompt: |
|
|
35
|
+
You specialize in session tracking and monitoring. You automatically create session tracking files when you start.
|
|
36
|
+
|
|
37
|
+
For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClaudeSwarm
|
|
4
|
+
class BaseExecutor
|
|
5
|
+
attr_reader :session_id, :last_response, :working_directory, :logger, :session_path, :session_json_path, :instance_info
|
|
6
|
+
|
|
7
|
+
def initialize(working_directory: Dir.pwd, model: nil, mcp_config: nil, vibe: false,
|
|
8
|
+
instance_name: nil, instance_id: nil, calling_instance: nil, calling_instance_id: nil,
|
|
9
|
+
claude_session_id: nil, additional_directories: [], debug: false)
|
|
10
|
+
@working_directory = working_directory
|
|
11
|
+
@additional_directories = additional_directories
|
|
12
|
+
@model = model
|
|
13
|
+
@mcp_config = mcp_config
|
|
14
|
+
@vibe = vibe
|
|
15
|
+
@session_id = claude_session_id
|
|
16
|
+
@last_response = nil
|
|
17
|
+
@instance_name = instance_name
|
|
18
|
+
@instance_id = instance_id
|
|
19
|
+
@calling_instance = calling_instance
|
|
20
|
+
@calling_instance_id = calling_instance_id
|
|
21
|
+
@debug = debug
|
|
22
|
+
|
|
23
|
+
# Setup static info strings for logging
|
|
24
|
+
@instance_info = build_info(@instance_name, @instance_id)
|
|
25
|
+
@caller_info = build_info(@calling_instance, @calling_instance_id)
|
|
26
|
+
@caller_to_instance = "#{@caller_info} -> #{instance_info}:"
|
|
27
|
+
@instance_to_caller = "#{instance_info} -> #{@caller_info}:"
|
|
28
|
+
|
|
29
|
+
# Setup logging
|
|
30
|
+
setup_logging
|
|
31
|
+
|
|
32
|
+
# Setup static event templates
|
|
33
|
+
setup_event_templates
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def execute(_prompt, _options = {})
|
|
37
|
+
raise NotImplementedError, "Subclasses must implement the execute method"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset_session
|
|
41
|
+
@session_id = nil
|
|
42
|
+
@last_response = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def has_session?
|
|
46
|
+
!@session_id.nil?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def build_info(name, id)
|
|
52
|
+
return name unless id
|
|
53
|
+
|
|
54
|
+
"#{name} (#{id})"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def setup_logging
|
|
58
|
+
# Use session path from environment (required)
|
|
59
|
+
@session_path = SessionPath.from_env
|
|
60
|
+
SessionPath.ensure_directory(@session_path)
|
|
61
|
+
|
|
62
|
+
# Initialize session JSON path
|
|
63
|
+
@session_json_path = File.join(@session_path, "session.log.json")
|
|
64
|
+
|
|
65
|
+
# Create logger with session.log filename
|
|
66
|
+
log_filename = "session.log"
|
|
67
|
+
log_path = File.join(@session_path, log_filename)
|
|
68
|
+
log_level = @debug ? :debug : :info
|
|
69
|
+
@logger = Logger.new(log_path, level: log_level, progname: @instance_name)
|
|
70
|
+
|
|
71
|
+
logger.info { "Started #{self.class.name} for instance: #{instance_info}" }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def setup_event_templates
|
|
75
|
+
@log_request_event_template = {
|
|
76
|
+
type: "request",
|
|
77
|
+
from_instance: @calling_instance,
|
|
78
|
+
from_instance_id: @calling_instance_id,
|
|
79
|
+
to_instance: @instance_name,
|
|
80
|
+
to_instance_id: @instance_id,
|
|
81
|
+
}.freeze
|
|
82
|
+
|
|
83
|
+
@session_json_entry_template = {
|
|
84
|
+
instance: @instance_name,
|
|
85
|
+
instance_id: @instance_id,
|
|
86
|
+
calling_instance: @calling_instance,
|
|
87
|
+
calling_instance_id: @calling_instance_id,
|
|
88
|
+
}.freeze
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def log_request(prompt)
|
|
92
|
+
logger.info { "#{@caller_to_instance} \n---\n#{prompt}\n---" }
|
|
93
|
+
|
|
94
|
+
# Merge dynamic data with static template
|
|
95
|
+
event = @log_request_event_template.merge(
|
|
96
|
+
prompt: prompt,
|
|
97
|
+
timestamp: Time.now.iso8601,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
append_to_session_json(event)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def log_response(response)
|
|
104
|
+
logger.info do
|
|
105
|
+
"($#{response["total_cost"]} - #{response["duration_ms"]}ms) #{@instance_to_caller} \n---\n#{response["result"]}\n---"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def append_to_session_json(event)
|
|
110
|
+
# Use file locking to ensure thread-safe writes
|
|
111
|
+
File.open(@session_json_path, File::WRONLY | File::APPEND | File::CREAT) do |file|
|
|
112
|
+
file.flock(File::LOCK_EX)
|
|
113
|
+
|
|
114
|
+
# Merge dynamic data with static template
|
|
115
|
+
entry = @session_json_entry_template.merge(
|
|
116
|
+
timestamp: Time.now.iso8601,
|
|
117
|
+
event: event,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Write as single line JSON (JSONL format)
|
|
121
|
+
file.puts(entry.to_json)
|
|
122
|
+
|
|
123
|
+
file.flock(File::LOCK_UN)
|
|
124
|
+
end
|
|
125
|
+
rescue StandardError => e
|
|
126
|
+
logger.error { "Failed to append to session JSON: #{e.message}" }
|
|
127
|
+
raise
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class ExecutionError < StandardError; end
|
|
131
|
+
class ParseError < StandardError; end
|
|
132
|
+
end
|
|
133
|
+
end
|