claude_swarm 0.3.3 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df4f13365305ca607131b9976630fd7caebaa4c2f69f2fefc59e9d036aee2033
4
- data.tar.gz: b1bf9cc4b672843216ec3107654a6e17d84a69fde87fe54d9846bfb4dca0f7ec
3
+ metadata.gz: 5eb0822e3545b567132a4aa87a247304418b32dd57a460091b2809b72884c178
4
+ data.tar.gz: e01d5010ea99bdbf8dc299ff986351abe8e220b143f002d1a0e1ba7220bf64f2
5
5
  SHA512:
6
- metadata.gz: bf0623fdf1d7ff7f551c32d87ba434d0073d0ffcb5f3254ea42d6b9e6048d350823d7bad2294929d014892728866f59117c9b58ebd5a7b0b1c2f358d8942387e
7
- data.tar.gz: 7e575dd61d59a8c2c1e04790ba3024136797373ad585612aee3b365a0d47f22bd3732119ea73ae01ddd67b75900ebe090117993f58af1520deecf4bc57907ca1
6
+ metadata.gz: c401eaad0a7f80bb16edf5b49c629b17b325308fe98854a5b4e1a620f5876e89ea0683222a2935fb8ca2c1629227c7678ceafecaf66cb086c390e0e8825cc4d9
7
+ data.tar.gz: d63efd161b7af5f1143b1b4f1263d2dcbad6ebf0a597de61fd843ad97d6ece6421a8ec462a44f6d70585026d9bd8e604931d96695278e117eee12d738e2905a5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [0.3.4]
2
+
3
+ ### Changed
4
+ - Migrated from CLI to SDK-based execution**: Claude Swarm now uses the `claude-code-sdk-ruby` gem instead of executing Claude Code via CLI
5
+ - Removed CLI-based `ClaudeCodeExecutor` implementation that used `Open3.popen3`
6
+ - All Claude Code execution now uses the SDK for improved reliability and performance
7
+ - Session management and logging functionality remains unchanged
8
+ - MCP configuration parsing updated to convert JSON format to SDK hash format
9
+ - Supports all MCP server types: stdio, sse, and http
10
+ - This change is transparent to users but may affect custom integrations that relied on CLI-specific behavior
11
+
12
+ ### Added
13
+ - **SDK dependency**: Added `claude-code-sdk-ruby` (~> 0.1.0)
14
+
1
15
  ## [0.3.3]
2
16
 
3
17
  ### Fixed
data/CLAUDE.md CHANGED
@@ -93,6 +93,16 @@ instances:
93
93
  - Existing worktrees with the same name are reused
94
94
  - The `claude-swarm clean` command removes orphaned worktrees
95
95
 
96
+ ## Claude Code SDK Integration
97
+
98
+ Claude Swarm uses the Claude Code SDK (`claude-code-sdk-ruby`) for all Claude instances. This provides:
99
+ - Better performance and reliability
100
+ - Structured message handling
101
+ - Improved error recovery
102
+ - Direct MCP server configuration support (stdio, sse, http)
103
+
104
+ The SDK executor handles all three MCP server types and properly converts MCP JSON configurations to SDK format.
105
+
96
106
  ## Architecture
97
107
 
98
108
  The gem is fully implemented with the following components:
data/README.md CHANGED
@@ -978,6 +978,7 @@ Check the session directory `~/.claude-swarm/sessions/{project}/{session-id}/` f
978
978
  - `{instance}.mcp.json`: MCP configuration for each instance
979
979
  - All files for a session are kept together for easy review
980
980
 
981
+
981
982
  ## Architecture
982
983
 
983
984
  Claude Swarm consists of these core components:
@@ -986,7 +987,7 @@ Claude Swarm consists of these core components:
986
987
  - **ClaudeSwarm::Configuration** (`configuration.rb`): YAML parser and validator with path expansion
987
988
  - **ClaudeSwarm::McpGenerator** (`mcp_generator.rb`): Generates MCP JSON configs for each instance
988
989
  - **ClaudeSwarm::Orchestrator** (`orchestrator.rb`): Launches the main Claude instance with shared session management
989
- - **ClaudeSwarm::ClaudeCodeExecutor** (`claude_code_executor.rb`): Wrapper for executing Claude commands with session persistence
990
+ - **ClaudeSwarm::ClaudeCodeExecutor** (`claude_code_executor.rb`): Executor for Claude Code with session persistence
990
991
  - **ClaudeSwarm::ClaudeMcpServer** (`claude_mcp_server.rb`): FastMCP-based server providing task execution, session info, and reset capabilities
991
992
 
992
993
  ## Development
@@ -27,59 +27,66 @@ module ClaudeSwarm
27
27
  # Log the request
28
28
  log_request(prompt)
29
29
 
30
- cmd_array = build_command_array(prompt, options)
30
+ # Build SDK options
31
+ sdk_options = build_sdk_options(prompt, options)
31
32
 
32
33
  # Variables to collect output
33
- stderr_output = []
34
+ all_messages = []
34
35
  result_response = nil
35
36
 
36
- # Execute command with unbundled environment to avoid bundler conflicts
37
- # This ensures claude runs in a clean environment without inheriting
38
- # Claude Swarm's BUNDLE_* environment variables
39
- Bundler.with_unbundled_env do
40
- # Execute command with streaming
41
- Open3.popen3(*cmd_array, chdir: @working_directory) do |stdin, stdout, stderr, wait_thread|
42
- stdin.close
43
-
44
- # Read stderr in a separate thread
45
- stderr_thread = Thread.new do
46
- stderr.each_line { |line| stderr_output << line }
47
- end
48
-
49
- # Process stdout line by line
50
- stdout.each_line do |line|
51
- json_data = JSON.parse(line.strip)
37
+ # Execute with streaming
38
+ begin
39
+ ClaudeSDK.query(prompt, options: sdk_options) do |message|
40
+ # Convert message to hash for logging
41
+ message_hash = message_to_hash(message)
42
+ all_messages << message_hash
52
43
 
53
- # Log each JSON event
54
- log_streaming_event(json_data)
44
+ # Log streaming event BEFORE we modify anything
45
+ log_streaming_event(message_hash)
55
46
 
47
+ # Process specific message types
48
+ case message
49
+ when ClaudeSDK::Messages::System
56
50
  # Capture session_id from system init
57
- if json_data["type"] == "system" && json_data["subtype"] == "init"
58
- @session_id = json_data["session_id"]
59
- write_instance_state
51
+ if message.subtype == "init" && message.data.is_a?(Hash)
52
+ # For init messages, session_id is in the data hash
53
+ session_id = message.data[:session_id] || message.data["session_id"]
54
+
55
+ if session_id
56
+ @session_id = session_id
57
+ write_instance_state
58
+ end
60
59
  end
61
-
62
- # Capture the final result
63
- result_response = json_data if json_data["type"] == "result"
64
- rescue JSON::ParserError => e
65
- @logger.warn("Failed to parse JSON line: #{line.strip} - #{e.message}")
66
- end
67
-
68
- # Wait for stderr thread to finish
69
- stderr_thread.join
70
-
71
- # Check exit status
72
- exit_status = wait_thread.value
73
- unless exit_status.success?
74
- error_msg = stderr_output.join
75
- @logger.error("Execution error for #{@instance_name}: #{error_msg}")
76
- raise ExecutionError, "Claude Code execution failed: #{error_msg}"
60
+ when ClaudeSDK::Messages::Assistant
61
+ # Assistant messages only contain content blocks
62
+ # No need to track for result extraction - result comes from Result message
63
+ when ClaudeSDK::Messages::Result
64
+ # Build result response in expected format
65
+ result_response = {
66
+ "type" => "result",
67
+ "subtype" => message.subtype || "success",
68
+ "cost_usd" => message.total_cost_usd,
69
+ "is_error" => message.is_error || false,
70
+ "duration_ms" => message.duration_ms,
71
+ "result" => message.result, # Result text is directly in message.result
72
+ "total_cost" => message.total_cost_usd,
73
+ "session_id" => message.session_id,
74
+ }
77
75
  end
78
76
  end
77
+ rescue StandardError => e
78
+ @logger.error("Execution error for #{@instance_name}: #{e.class} - #{e.message}")
79
+ @logger.error("Backtrace: #{e.backtrace.join("\n")}")
80
+ raise ExecutionError, "Claude Code execution failed: #{e.message}"
79
81
  end
80
82
 
81
83
  # Ensure we got a result
82
- raise ParseError, "No result found in stream output" unless result_response
84
+ raise ParseError, "No result found in SDK response" unless result_response
85
+
86
+ # Write session JSON log
87
+ all_messages.each do |msg|
88
+ append_to_session_json(msg)
89
+ end
83
90
 
84
91
  result_response
85
92
  rescue StandardError => e
@@ -195,11 +202,12 @@ module ClaudeSwarm
195
202
  end
196
203
 
197
204
  def log_assistant_message(msg)
198
- return if msg["stop_reason"] == "end_turn" # that means it is not a thought but the final answer
199
-
205
+ # Assistant messages don't have stop_reason in SDK - they only have content
200
206
  content = msg["content"]
201
- @logger.debug("ASSISTANT: #{JSON.pretty_generate(content)}")
202
- tool_calls = content.select { |c| c["type"] == "tool_use" }
207
+ @logger.debug("ASSISTANT: #{JSON.pretty_generate(content)}") if content
208
+
209
+ # Log tool calls
210
+ tool_calls = content&.select { |c| c["type"] == "tool_use" } || []
203
211
  tool_calls.each do |tool_call|
204
212
  arguments = tool_call["input"].to_json
205
213
  arguments = "#{arguments[0..300]} ...}" if arguments.length > 300
@@ -211,7 +219,8 @@ module ClaudeSwarm
211
219
  )
212
220
  end
213
221
 
214
- text = content.select { |c| c["type"] == "text" }
222
+ # Log thinking text
223
+ text = content&.select { |c| c["type"] == "text" } || []
215
224
  text.each do |t|
216
225
  instance_info = @instance_name
217
226
  instance_info += " (#{@instance_id})" if @instance_id
@@ -251,38 +260,18 @@ module ClaudeSwarm
251
260
  raise
252
261
  end
253
262
 
254
- def build_command_array(prompt, options)
255
- cmd_array = ["claude"]
256
-
257
- # Add model if specified
258
- cmd_array += ["--model", @model]
259
-
260
- cmd_array << "--verbose"
263
+ def build_sdk_options(prompt, options)
264
+ # Map CLI options to SDK options
265
+ sdk_options = ClaudeSDK::ClaudeCodeOptions.new
261
266
 
262
- # Add additional directories with --add-dir
263
- cmd_array << "--add-dir" if @additional_directories.any?
264
- @additional_directories.each do |additional_dir|
265
- cmd_array << additional_dir
266
- end
267
-
268
- # Add MCP config if specified
269
- cmd_array += ["--mcp-config", @mcp_config] if @mcp_config
270
-
271
- # Resume session if we have a session ID
272
- cmd_array += ["--resume", @session_id] if @session_id && !options[:new_session]
273
-
274
- # Always use JSON output format for structured responses
275
- cmd_array += ["--output-format", "stream-json"]
276
-
277
- # Add non-interactive mode with prompt
278
- cmd_array += ["--print", "-p", prompt]
279
-
280
- # Add any custom system prompt
281
- cmd_array += ["--append-system-prompt", options[:system_prompt]] if options[:system_prompt]
267
+ # Basic options
268
+ sdk_options.model = @model if @model
269
+ sdk_options.cwd = @working_directory
270
+ sdk_options.resume = @session_id if @session_id && !options[:new_session]
282
271
 
283
- # Add any allowed tools or vibe flag
272
+ # Permission mode
284
273
  if @vibe
285
- cmd_array << "--dangerously-skip-permissions"
274
+ sdk_options.permission_mode = ClaudeSDK::PermissionMode::BYPASS_PERMISSIONS
286
275
  else
287
276
  # Build allowed tools list including MCP connections
288
277
  allowed_tools = options[:allowed_tools] ? Array(options[:allowed_tools]).dup : []
@@ -292,20 +281,175 @@ module ClaudeSwarm
292
281
  allowed_tools << "mcp__#{connection_name}"
293
282
  end
294
283
 
295
- # Add allowed tools if any
296
- if allowed_tools.any?
297
- tools_str = allowed_tools.join(",")
298
- cmd_array += ["--allowedTools", tools_str]
284
+ # Set allowed and disallowed tools
285
+ sdk_options.allowed_tools = allowed_tools if allowed_tools.any?
286
+ sdk_options.disallowed_tools = Array(options[:disallowed_tools]) if options[:disallowed_tools]
287
+ end
288
+
289
+ # System prompt
290
+ sdk_options.append_system_prompt = options[:system_prompt] if options[:system_prompt]
291
+
292
+ # MCP configuration
293
+ if @mcp_config
294
+ sdk_options.mcp_servers = parse_mcp_config(@mcp_config)
295
+ end
296
+
297
+ # Handle additional directories by adding them to MCP servers
298
+ if @additional_directories.any?
299
+ setup_additional_directories_mcp(sdk_options)
300
+ end
301
+
302
+ sdk_options
303
+ end
304
+
305
+ def parse_mcp_config(config_path)
306
+ # Parse MCP JSON config file and convert to SDK format
307
+ config = JSON.parse(File.read(config_path))
308
+ mcp_servers = {}
309
+
310
+ config["mcpServers"]&.each do |name, server_config|
311
+ server_type = server_config["type"] || "stdio"
312
+
313
+ mcp_servers[name] = case server_type
314
+ when "stdio"
315
+ ClaudeSDK::McpServerConfig::StdioServer.new(
316
+ command: server_config["command"],
317
+ args: server_config["args"] || [],
318
+ env: server_config["env"] || {},
319
+ )
320
+ when "sse"
321
+ ClaudeSDK::McpServerConfig::SSEServer.new(
322
+ url: server_config["url"],
323
+ headers: server_config["headers"] || {},
324
+ )
325
+ when "http"
326
+ ClaudeSDK::McpServerConfig::HttpServer.new(
327
+ url: server_config["url"],
328
+ headers: server_config["headers"] || {},
329
+ )
330
+ else
331
+ @logger.warn("Unsupported MCP server type: #{server_type} for server: #{name}")
332
+ nil
299
333
  end
334
+ end
335
+
336
+ mcp_servers.compact
337
+ rescue StandardError => e
338
+ @logger.error("Failed to parse MCP config: #{e.message}")
339
+ {}
340
+ end
341
+
342
+ def setup_additional_directories_mcp(sdk_options)
343
+ # Workaround for --add-dir: add file system MCP servers for additional directories
344
+ sdk_options.mcp_servers ||= {}
345
+
346
+ @additional_directories.each do |dir|
347
+ # This is a placeholder - the SDK doesn't directly support file system servers
348
+ # You would need to implement a proper MCP server that provides file access
349
+ @logger.warn("Additional directories not fully supported: #{dir}")
350
+ end
351
+ end
300
352
 
301
- # Add disallowed tools if any
302
- if options[:disallowed_tools]
303
- disallowed_tools = Array(options[:disallowed_tools]).join(",")
304
- cmd_array += ["--disallowedTools", disallowed_tools]
353
+ def message_to_hash(message)
354
+ # Convert SDK message objects to hash format matching CLI JSON output
355
+ case message
356
+ when ClaudeSDK::Messages::System
357
+ # System messages have subtype and data attributes
358
+ # The data hash contains the actual information from the CLI
359
+ hash = {
360
+ "type" => "system",
361
+ "subtype" => message.subtype,
362
+ }
363
+
364
+ # Include the data hash if it exists - this is where CLI puts info like session_id, tools, etc.
365
+ if message.data.is_a?(Hash)
366
+ # For "init" subtype, extract session_id and tools from data
367
+ if message.subtype == "init"
368
+ hash["session_id"] = message.data[:session_id] || message.data["session_id"]
369
+ hash["tools"] = message.data[:tools] || message.data["tools"]
370
+ end
371
+ # You can add other relevant data fields as needed
372
+ end
373
+
374
+ hash.compact
375
+ when ClaudeSDK::Messages::Assistant
376
+ # Assistant messages only have content attribute
377
+ {
378
+ "type" => "assistant",
379
+ "message" => {
380
+ "type" => "message",
381
+ "role" => "assistant",
382
+ "content" => content_blocks_to_hash(message.content),
383
+ },
384
+ "session_id" => @session_id,
385
+ }
386
+ when ClaudeSDK::Messages::User
387
+ # User messages only have content attribute (a string)
388
+ {
389
+ "type" => "user",
390
+ "message" => {
391
+ "type" => "message",
392
+ "role" => "user",
393
+ "content" => message.content,
394
+ },
395
+ "session_id" => @session_id,
396
+ }
397
+ when ClaudeSDK::Messages::Result
398
+ # Result messages have multiple attributes
399
+ {
400
+ "type" => "result",
401
+ "subtype" => message.subtype || "success",
402
+ "cost_usd" => message.total_cost_usd,
403
+ "is_error" => message.is_error || false,
404
+ "duration_ms" => message.duration_ms,
405
+ "duration_api_ms" => message.duration_api_ms,
406
+ "num_turns" => message.num_turns,
407
+ "result" => message.result, # Result text is in message.result, not from content
408
+ "total_cost" => message.total_cost_usd,
409
+ "total_cost_usd" => message.total_cost_usd,
410
+ "session_id" => message.session_id,
411
+ "usage" => message.usage,
412
+ }.compact
413
+ else
414
+ # Fallback for unknown message types
415
+ begin
416
+ message.to_h
417
+ rescue
418
+ { "type" => "unknown", "data" => message.to_s }
305
419
  end
306
420
  end
421
+ end
307
422
 
308
- cmd_array
423
+ def content_blocks_to_hash(content)
424
+ return [] unless content
425
+
426
+ content.map do |block|
427
+ case block
428
+ when ClaudeSDK::ContentBlock::Text
429
+ { "type" => "text", "text" => block.text }
430
+ when ClaudeSDK::ContentBlock::ToolUse
431
+ {
432
+ "type" => "tool_use",
433
+ "id" => block.id,
434
+ "name" => block.name,
435
+ "input" => block.input,
436
+ }
437
+ when ClaudeSDK::ContentBlock::ToolResult
438
+ {
439
+ "type" => "tool_result",
440
+ "tool_use_id" => block.tool_use_id,
441
+ "content" => block.content,
442
+ "is_error" => block.is_error,
443
+ }
444
+ else
445
+ # Fallback
446
+ begin
447
+ block.to_h
448
+ rescue
449
+ { "type" => "unknown", "data" => block.to_s }
450
+ end
451
+ end
452
+ end
309
453
  end
310
454
 
311
455
  class ExecutionError < StandardError; end
@@ -37,7 +37,7 @@ module ClaudeSwarm
37
37
  reasoning_effort: instance_config[:reasoning_effort],
38
38
  )
39
39
  else
40
- # Default Claude behavior (existing code)
40
+ # Default Claude behavior - always use SDK
41
41
  ClaudeCodeExecutor.new(**common_params)
42
42
  end
43
43
 
@@ -4,6 +4,11 @@ module ClaudeSwarm
4
4
  class Orchestrator
5
5
  include SystemUtils
6
6
  RUN_DIR = File.expand_path("~/.claude-swarm/run")
7
+ ["INT", "TERM", "QUIT"].each do |signal|
8
+ Signal.trap(signal) do
9
+ puts "\n🛑 Received #{signal} signal."
10
+ end
11
+ end
7
12
 
8
13
  def initialize(configuration, mcp_generator, vibe: false, prompt: nil, interactive_prompt: nil, stream_logs: false, debug: false,
9
14
  restore_session_path: nil, worktree: nil, session_id: nil)
@@ -58,9 +63,6 @@ module ClaudeSwarm
58
63
  # Initialize process tracker
59
64
  @process_tracker = ProcessTracker.new(session_path)
60
65
 
61
- # Set up signal handlers to clean up child processes
62
- setup_signal_handlers
63
-
64
66
  # Check if the original session used worktrees
65
67
  restore_worktrees_if_needed(session_path)
66
68
 
@@ -103,9 +105,6 @@ module ClaudeSwarm
103
105
  # Initialize process tracker
104
106
  @process_tracker = ProcessTracker.new(session_path)
105
107
 
106
- # Set up signal handlers to clean up child processes
107
- setup_signal_handlers
108
-
109
108
  # Create WorktreeManager if needed with session ID
110
109
  if @needs_worktree_manager
111
110
  cli_option = @worktree_option.is_a?(String) && !@worktree_option.empty? ? @worktree_option : nil
@@ -371,32 +370,6 @@ module ClaudeSwarm
371
370
  File.write(metadata_file, JSON.pretty_generate(metadata))
372
371
  end
373
372
 
374
- def setup_signal_handlers
375
- ["INT", "TERM", "QUIT"].each do |signal|
376
- Signal.trap(signal) do
377
- puts "\n🛑 Received #{signal} signal, cleaning up..."
378
- display_summary
379
-
380
- # Execute after commands if configured
381
- main_instance = @config.main_instance_config
382
- after_commands = @config.after_commands
383
- if after_commands.any? && !@restore_session_path && !@non_interactive_prompt
384
- Dir.chdir(main_instance[:directory]) do
385
- puts
386
- puts "⚙️ Executing after commands..."
387
- puts
388
- execute_after_commands?(after_commands)
389
- end
390
- end
391
-
392
- cleanup_processes
393
- cleanup_run_symlink
394
- cleanup_worktrees
395
- exit
396
- end
397
- end
398
- end
399
-
400
373
  def cleanup_processes
401
374
  @process_tracker.cleanup_all
402
375
  puts "✓ Cleanup complete"
@@ -7,8 +7,12 @@ module ClaudeSwarm
7
7
  unless success
8
8
  exit_status = $CHILD_STATUS&.exitstatus || 1
9
9
  command_str = args.size == 1 ? args.first : args.join(" ")
10
- warn("❌ Command failed with exit status: #{exit_status}")
11
- raise Error, "Command failed with exit status #{exit_status}: #{command_str}"
10
+ if exit_status == 143 # timeout command exit status = 128 + 15 (SIGTERM)
11
+ warn("⏱️ Command timeout: #{command_str}")
12
+ else
13
+ warn("❌ Command failed with exit status: #{exit_status}")
14
+ raise Error, "Command failed with exit status #{exit_status}: #{command_str}"
15
+ end
12
16
  end
13
17
  success
14
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeSwarm
4
- VERSION = "0.3.3"
4
+ VERSION = "0.3.4"
5
5
  end
data/lib/claude_swarm.rb CHANGED
@@ -21,6 +21,7 @@ require "tmpdir"
21
21
  require "yaml"
22
22
 
23
23
  # External dependencies
24
+ require "claude_sdk"
24
25
  require "fast_mcp_annotations"
25
26
  require "mcp_client"
26
27
  require "openai"
data/team.yml CHANGED
@@ -8,10 +8,20 @@ swarm:
8
8
  directory: .
9
9
  model: opus
10
10
  vibe: true
11
- connections: [github_expert, fast_mcp_expert, ruby_mcp_client_expert, openai_api_expert]
11
+ connections: [github_expert, fast_mcp_expert, ruby_mcp_client_expert, openai_api_expert, claude_code_sdk_expert]
12
12
  prompt: |
13
13
  You are the lead developer of Claude Swarm, a Ruby gem that orchestrates multiple Claude Code instances as a collaborative AI development team. The gem enables running AI agents with specialized roles, tools, and directory contexts, communicating via MCP (Model Context Protocol) in a tree-like hierarchy.
14
- Use the github_expert to help you with git and github related tasks.
14
+
15
+ IMPORTANT: Use your specialized team members for their areas of expertise. Each team member has deep knowledge in their domain:
16
+
17
+ Team Member Usage Guide:
18
+ - **github_expert**: Use for all Git and GitHub operations including creating issues, PRs, managing releases, checking CI/CD workflows, and repository management
19
+ - **fast_mcp_expert**: Use for MCP server development, tool creation, resource management, and any FastMCP-related architecture decisions
20
+ - **ruby_mcp_client_expert**: Use for MCP client integration, multi-transport connectivity, authentication flows, and ruby-mcp-client library guidance
21
+ - **openai_api_expert**: Use for OpenAI API integration, ruby-openai gem usage, model configuration, and OpenAI provider support in Claude Swarm
22
+ - **claude_code_sdk_expert**: Use for Claude Code SDK integration, programmatic Claude Code usage, client configuration, and SDK development patterns
23
+
24
+ Always delegate specialized tasks to the appropriate team member rather than handling everything yourself. This ensures the highest quality solutions and leverages each expert's deep domain knowledge.
15
25
 
16
26
  Your responsibilities include:
17
27
  - Developing new features and improvements for the Claude Swarm gem
@@ -254,4 +264,66 @@ swarm:
254
264
  - Set up CI to run code_quality checks
255
265
  - Document Raix integration in wiki/docs
256
266
 
257
- For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
267
+ For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
268
+
269
+ claude_code_sdk_expert:
270
+ description: "Expert in Claude Code SDK for Ruby, specializing in client integration and API usage patterns"
271
+ directory: ~/src/github.com/parruda/claude-code-sdk-ruby
272
+ model: opus
273
+ vibe: true
274
+ prompt: |
275
+ You are an expert in the Claude Code SDK for Ruby, specializing in client integration, API usage patterns, and SDK development best practices.
276
+
277
+ Your expertise covers:
278
+ - Claude Code SDK architecture and client configuration
279
+ - API authentication and session management
280
+ - Request/response handling and error management
281
+ - Code generation and analysis capabilities
282
+ - SDK integration patterns and best practices
283
+ - Tool usage and permission management
284
+ - Streaming responses and real-time interactions
285
+ - Multi-modal capabilities (text, code, images)
286
+ - Rate limiting and cost optimization
287
+ - Testing and debugging SDK integrations
288
+
289
+ Key responsibilities:
290
+ - Analyze Claude Code SDK codebase for implementation patterns
291
+ - Provide guidance on proper SDK usage and integration
292
+ - Design robust client configurations and authentication flows
293
+ - Implement efficient request handling and error recovery
294
+ - Optimize SDK performance and resource usage
295
+ - Create comprehensive examples and documentation
296
+ - Troubleshoot integration issues and API errors
297
+ - Ensure proper handling of streaming and async operations
298
+
299
+ Technical focus areas:
300
+ - Client initialization and configuration options
301
+ - Authentication flows and token management
302
+ - Request builders and parameter validation
303
+ - Response parsing and error handling
304
+ - Streaming implementations and chunk processing
305
+ - Tool integration and permission management
306
+ - Session management and state persistence
307
+ - Performance optimization and caching strategies
308
+ - Testing patterns and mock configurations
309
+
310
+ When providing guidance:
311
+ - Reference specific SDK methods and classes
312
+ - Include practical code examples and usage patterns
313
+ - Explain both SDK abstractions and underlying API details
314
+ - Highlight important configuration options and their implications
315
+ - Warn about common pitfalls and API limitations
316
+ - Suggest performance optimizations and cost-saving strategies
317
+ - Provide context on when to use different SDK features
318
+ - Demonstrate proper error handling and retry strategies
319
+
320
+ Integration with Claude Swarm development:
321
+ - Understand how Claude Code SDK can enhance swarm capabilities
322
+ - Provide insights on programmatic Claude Code integration
323
+ - Design patterns for automated swarm management
324
+ - Optimize SDK usage within swarm orchestration
325
+ - Ensure compatibility with swarm session management
326
+
327
+ For maximum efficiency, whenever you need to perform multiple independent operations, invoke all relevant tools simultaneously rather than sequentially.
328
+
329
+ Help developers integrate Claude Code SDK effectively with confidence, best practices, and optimal performance.
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.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.6'
40
+ - !ruby/object:Gem::Dependency
41
+ name: claude-code-sdk-ruby
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.0
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: fast-mcp-annotations
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
178
  - !ruby/object:Gem::Version
165
179
  version: '0'
166
180
  requirements: []
167
- rubygems_version: 3.6.7
181
+ rubygems_version: 3.6.9
168
182
  specification_version: 4
169
183
  summary: Orchestrate multiple Claude Code instances as a collaborative AI development
170
184
  team