claude_swarm 0.3.7 → 0.3.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc0d22524516d5e0f2a76715c2a80b36d1a974a3ff7ba451c103c86cb4a36fd1
4
- data.tar.gz: 4cebdba8032fc3dfe223033ba9b2890b5849dd5516a539ffdf57231bcec66c38
3
+ metadata.gz: a256a8d09a86290b06002437b38bc9092b7d83c1e4d1e0f4866b37cd1251bd99
4
+ data.tar.gz: d5eeec5e3a350dac2a04860c64c00043a8618fd29d40b9e1acf77e86b2f3fd49
5
5
  SHA512:
6
- metadata.gz: e5ec9ed928d5e73d12eb1257571e3c2b45fc9db64dbd64e8f3186ea2df5f187927d4cc0a6e8eb9901cb8dbaf4679f442f340c85f6f6f728ca01f1d8b82db8bf8
7
- data.tar.gz: 8fce151a6a47d68736fc62b6453515f46e12d293d2eee2f3e951f99510351941faf9f0b9c5f0497de37847fac282cc997ccebdbb11f477fc71b21b8514dd753d
6
+ metadata.gz: 3bb8119400be33d056b795aaea4f7f3d045d85a29d830cc42fe8c3dba0fd406100553b68740fe884e2e769e9685c439983d3a38ee52f55730f9f1ff7b40ddbff
7
+ data.tar.gz: a2dd8483358b673698e7ca3a71d1952fa0b2c85d0daf9cd2ff06c5f62d78f7ffebacc95a0e622cfb3f62f229e81c8177c5d6b263303b88c26c592ba53e7c7607
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [0.3.8]
2
+
3
+ ### Added
4
+ - **Hooks support**: Claude Swarm now supports configuring Claude Code hooks for each instance
5
+ - Configure hooks directly in the YAML configuration file using Claude Code's format
6
+ - Each instance can have its own hooks configuration (PreToolUse, PostToolUse, UserPromptSubmit, etc.)
7
+ - Automatically generates `settings.json` files in the session directory when hooks are configured
8
+ - Main instance receives hooks via `--settings` CLI flag
9
+ - Connected instances receive hooks via SDK's `settings` attribute
10
+ - Full environment variable interpolation support in hook configurations
11
+ - See README.md "Hooks Configuration" section for usage examples
12
+
13
+ ### Fixed
14
+ - **Settings integration**: Fixed passing settings to Claude instances
15
+ - Corrected SDK attribute name from `settings_path` to `settings`
16
+ - Added missing `--settings` flag for main instance CLI command
17
+
1
18
  ## [0.3.7]
2
19
 
3
20
  ### Added
data/CLAUDE.md CHANGED
@@ -130,9 +130,10 @@ The gem is fully implemented with the following components:
130
130
  1. User creates a `claude-swarm.yml` file defining the swarm topology
131
131
  2. Running `claude-swarm` parses the configuration and validates it
132
132
  3. MCP configuration files are generated for each instance in a session directory
133
- 4. The main instance is launched with `exec`, replacing the current process
134
- 5. Connected instances are available as MCP servers to the main instance
135
- 6. When an instance has connections, those connections are automatically added to its allowed tools as `mcp__<connection_name>`
133
+ 4. Settings files (with hooks) are generated for each instance if hooks are configured
134
+ 5. The main instance is launched with `exec`, replacing the current process
135
+ 6. Connected instances are available as MCP servers to the main instance
136
+ 7. When an instance has connections, those connections are automatically added to its allowed tools as `mcp__<connection_name>`
136
137
 
137
138
  ### Configuration Example
138
139
 
@@ -159,6 +160,52 @@ swarm:
159
160
  worktree: false # Optional: disable worktree for this instance
160
161
  ```
161
162
 
163
+ ### Hooks Support
164
+
165
+ 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.
166
+
167
+ #### Configuration Example with Hooks
168
+
169
+ ```yaml
170
+ version: 1
171
+ swarm:
172
+ name: "Dev Team"
173
+ main: lead
174
+ instances:
175
+ lead:
176
+ description: "Lead developer"
177
+ directory: .
178
+ model: opus
179
+ # Hooks configuration follows Claude Code's format exactly
180
+ hooks:
181
+ PreToolUse:
182
+ - matcher: "Write|Edit"
183
+ hooks:
184
+ - type: "command"
185
+ command: "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-code.py"
186
+ timeout: 10
187
+ PostToolUse:
188
+ - matcher: "Bash"
189
+ hooks:
190
+ - type: "command"
191
+ command: "echo 'Command executed by lead' >> /tmp/lead.log"
192
+ UserPromptSubmit:
193
+ - hooks:
194
+ - type: "command"
195
+ command: "$CLAUDE_PROJECT_DIR/.claude/hooks/add-context.py"
196
+ frontend:
197
+ description: "Frontend developer"
198
+ directory: ./frontend
199
+ hooks:
200
+ PreToolUse:
201
+ - matcher: "Write"
202
+ hooks:
203
+ - type: "command"
204
+ command: "npm run lint"
205
+ ```
206
+
207
+ 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.
208
+
162
209
  ## Testing
163
210
 
164
211
  The gem includes comprehensive tests covering:
data/README.md CHANGED
@@ -303,6 +303,7 @@ Each instance can have:
303
303
  - **vibe**: Enable vibe mode (--dangerously-skip-permissions) for this instance (default: false)
304
304
  - **worktree**: Configure Git worktree usage for this instance (true/false/string)
305
305
  - **provider**: AI provider to use - "claude" (default) or "openai"
306
+ - **hooks**: Configure Claude Code hooks for this instance (see Hooks Configuration section below)
306
307
 
307
308
  #### OpenAI Provider Configuration
308
309
 
@@ -394,6 +395,69 @@ mcps:
394
395
  X-Custom-Header: "value"
395
396
  ```
396
397
 
398
+ ### Hooks Configuration
399
+
400
+ 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.
401
+
402
+ #### Supported Hook Events
403
+
404
+ - **PreToolUse**: Run before a tool is executed
405
+ - **PostToolUse**: Run after a tool completes
406
+ - **UserPromptSubmit**: Run when a user prompt is submitted
407
+ - **Stop**: Run when the Claude instance stops
408
+ - **SessionStart**: Run when a session starts
409
+ - **And more...** (see Claude Code hooks documentation)
410
+
411
+ #### Configuration Example
412
+
413
+ ```yaml
414
+ instances:
415
+ lead:
416
+ description: "Lead developer"
417
+ directory: .
418
+ # Hooks configuration follows Claude Code's format exactly
419
+ hooks:
420
+ PreToolUse:
421
+ - matcher: "Write|Edit"
422
+ hooks:
423
+ - type: "command"
424
+ command: "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-code.py"
425
+ timeout: 10
426
+ PostToolUse:
427
+ - matcher: "Bash"
428
+ hooks:
429
+ - type: "command"
430
+ command: "echo 'Bash executed by ${INSTANCE_NAME}' >> ${LOG_DIR}/commands.log"
431
+ UserPromptSubmit:
432
+ - hooks:
433
+ - type: "command"
434
+ command: "${HOOKS_DIR:=$CLAUDE_PROJECT_DIR/.claude/hooks}/add-context.py"
435
+ frontend:
436
+ description: "Frontend developer"
437
+ directory: ./frontend
438
+ hooks:
439
+ PreToolUse:
440
+ - matcher: "Write"
441
+ hooks:
442
+ - type: "command"
443
+ command: "npm run lint"
444
+ timeout: 5
445
+ ```
446
+
447
+ #### How It Works
448
+
449
+ 1. Define hooks in your instance configuration using the exact format expected by Claude Code
450
+ 2. Claude Swarm generates a `settings.json` file for each instance with hooks
451
+ 3. The settings file is passed to Claude Code SDK via the `--settings` parameter
452
+ 4. Each instance runs with its own hooks configuration
453
+
454
+ #### Environment Variables in Hooks
455
+
456
+ Hooks have access to standard Claude Code environment variables plus:
457
+ - `$CLAUDE_PROJECT_DIR` - The project directory
458
+ - `$CLAUDE_SWARM_SESSION_DIR` - The swarm session directory
459
+ - `$CLAUDE_SWARM_INSTANCE_NAME` - The name of the current instance
460
+
397
461
  ### Tools
398
462
 
399
463
  Specify which tools each instance can use:
@@ -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.
@@ -184,6 +184,10 @@ module ClaudeSwarm
184
184
  setup_additional_directories_mcp(sdk_options)
185
185
  end
186
186
 
187
+ # Add settings file path if it exists
188
+ settings_file = File.join(@session_path, "#{@instance_name}_settings.json")
189
+ sdk_options.settings = settings_file if File.exist?(settings_file)
190
+
187
191
  sdk_options
188
192
  end
189
193
 
@@ -200,6 +200,7 @@ module ClaudeSwarm
200
200
  vibe: config["vibe"],
201
201
  worktree: parse_worktree_value(config["worktree"]),
202
202
  provider: provider, # nil means Claude (default)
203
+ hooks: config["hooks"], # Pass hooks configuration as-is
203
204
  }
204
205
 
205
206
  # Add OpenAI-specific fields only when provider is "openai"
@@ -17,6 +17,7 @@ module ClaudeSwarm
17
17
  restore_session_path: nil, worktree: nil, session_id: nil)
18
18
  @config = configuration
19
19
  @generator = mcp_generator
20
+ @settings_generator = SettingsGenerator.new(configuration)
20
21
  @vibe = vibe
21
22
  @non_interactive_prompt = prompt
22
23
  @interactive_prompt = interactive_prompt
@@ -74,6 +75,12 @@ module ClaudeSwarm
74
75
  non_interactive_output do
75
76
  puts "✓ Regenerated MCP configurations with session IDs"
76
77
  end
78
+
79
+ # Generate settings files
80
+ @settings_generator.generate_all
81
+ non_interactive_output do
82
+ puts "✓ Generated settings files with hooks"
83
+ end
77
84
  else
78
85
  non_interactive_output do
79
86
  puts "🐝 Starting Claude Swarm: #{@config.swarm_name}"
@@ -127,6 +134,12 @@ module ClaudeSwarm
127
134
  puts "✓ Generated MCP configurations in session directory"
128
135
  end
129
136
 
137
+ # Generate settings files
138
+ @settings_generator.generate_all
139
+ non_interactive_output do
140
+ puts "✓ Generated settings files with hooks"
141
+ end
142
+
130
143
  # Save swarm config path for restoration
131
144
  save_swarm_config_path(session_path)
132
145
  end
@@ -488,6 +501,13 @@ module ClaudeSwarm
488
501
  parts << "--mcp-config"
489
502
  parts << mcp_config_path
490
503
 
504
+ # Add settings file if it exists for the main instance
505
+ settings_file = @settings_generator.settings_path(@config.main_instance)
506
+ if File.exist?(settings_file)
507
+ parts << "--settings"
508
+ parts << settings_file
509
+ end
510
+
491
511
  # Handle different modes
492
512
  if @non_interactive_prompt
493
513
  # Non-interactive mode with -p
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClaudeSwarm
4
+ class SettingsGenerator
5
+ def initialize(configuration)
6
+ @config = configuration
7
+ end
8
+
9
+ def generate_all
10
+ ensure_session_directory
11
+
12
+ @config.instances.each do |name, instance|
13
+ generate_settings(name, instance)
14
+ end
15
+ end
16
+
17
+ def settings_path(instance_name)
18
+ File.join(session_path, "#{instance_name}_settings.json")
19
+ end
20
+
21
+ private
22
+
23
+ def session_path
24
+ # In tests, use the session path from env if available, otherwise use a temp path
25
+ @session_path ||= if ENV["CLAUDE_SWARM_SESSION_PATH"]
26
+ SessionPath.from_env
27
+ else
28
+ # This should only happen in unit tests
29
+ Dir.pwd
30
+ end
31
+ end
32
+
33
+ def ensure_session_directory
34
+ # Session directory is already created by orchestrator
35
+ # Just ensure it exists
36
+ SessionPath.ensure_directory(session_path)
37
+ end
38
+
39
+ def generate_settings(name, instance)
40
+ settings = {}
41
+
42
+ # Add hooks if configured
43
+ if instance[:hooks] && !instance[:hooks].empty?
44
+ settings["hooks"] = instance[:hooks]
45
+ end
46
+
47
+ # Only write settings file if there are settings to write
48
+ return if settings.empty?
49
+
50
+ # Write settings file
51
+ File.write(settings_path(name), JSON.pretty_generate(settings))
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeSwarm
4
- VERSION = "0.3.7"
4
+ VERSION = "0.3.8"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude_swarm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -143,6 +143,7 @@ files:
143
143
  - examples/monitoring-demo.yml
144
144
  - examples/multi-directory.yml
145
145
  - examples/session-restoration-demo.yml
146
+ - examples/simple-session-hook-swarm.yml
146
147
  - examples/test-generation.yml
147
148
  - examples/with-before-commands.yml
148
149
  - exe/claude-swarm
@@ -162,6 +163,7 @@ files:
162
163
  - lib/claude_swarm/process_tracker.rb
163
164
  - lib/claude_swarm/session_cost_calculator.rb
164
165
  - lib/claude_swarm/session_path.rb
166
+ - lib/claude_swarm/settings_generator.rb
165
167
  - lib/claude_swarm/system_utils.rb
166
168
  - lib/claude_swarm/templates/generation_prompt.md.erb
167
169
  - lib/claude_swarm/tools/reset_session_tool.rb