claude_swarm 0.1.4 → 0.1.6
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 +3 -0
- data/CHANGELOG.md +16 -0
- data/README.md +15 -15
- data/claude-swarm.yml +2 -2
- data/lib/claude_swarm/claude_code_executor.rb +141 -21
- data/lib/claude_swarm/claude_mcp_server.rb +8 -152
- data/lib/claude_swarm/orchestrator.rb +22 -11
- data/lib/claude_swarm/reset_session_tool.rb +22 -0
- data/lib/claude_swarm/session_info_tool.rb +22 -0
- data/lib/claude_swarm/task_tool.rb +32 -0
- data/lib/claude_swarm/version.rb +1 -1
- data/sdk-docs.md +426 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32206b2e4ec4228e8d9c2450447f0508a2c58378d37c80ce24d327a54653ee05
|
4
|
+
data.tar.gz: c11bf2d8042b73de10ee2f40c01e977d8bae0a8bd74e23b74fc29216735396c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e639606be661128f4c23411f6e9c4164cf9b212ce37e6f99178ba33e4d67a5eb0995b25c1dbe885fff0c20230ea12e347c7b04c7b3bef8b4313353bce6cb948
|
7
|
+
data.tar.gz: 8d51962bb83f7268510b44a1aff1b13c5f5260c008b8bb26b41d971d0fbdd816c76a9221c275c028851c7ccc825c2aeee7b0d7d0e311f50485119693b3b5791a
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## [0.1.6]
|
2
|
+
- Refactor: move tools out of the ClaudeMcpServer class
|
3
|
+
- Move logging into code executor and save instance interaction streams to session.log
|
4
|
+
- Human readable logs with thoughts and tool calls
|
5
|
+
|
6
|
+
## [0.1.5]
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- **Improved command execution**: Switched from `exec` to `Dir.chdir` + `system` for better process handling and proper directory context
|
10
|
+
- Command arguments are now passed as an array instead of a shell string, eliminating the need for manual shell escaping
|
11
|
+
- Added default prompt behavior: when no `-p` flag is provided, a default prompt is added to help Claude understand it should start working
|
12
|
+
|
13
|
+
### Internal
|
14
|
+
- Updated test suite to match new command execution implementation
|
15
|
+
- Removed shellwords escaping tests as they're no longer needed with array-based command execution
|
16
|
+
|
1
17
|
## [0.1.4]
|
2
18
|
|
3
19
|
### Added
|
data/README.md
CHANGED
@@ -52,7 +52,7 @@ swarm:
|
|
52
52
|
frontend:
|
53
53
|
description: "Frontend specialist handling UI and user experience"
|
54
54
|
directory: ./frontend
|
55
|
-
model:
|
55
|
+
model: opus
|
56
56
|
tools:
|
57
57
|
- Edit
|
58
58
|
- Write
|
@@ -60,7 +60,7 @@ swarm:
|
|
60
60
|
backend:
|
61
61
|
description: "Backend developer managing APIs and data layer"
|
62
62
|
directory: ./backend
|
63
|
-
model:
|
63
|
+
model: opus
|
64
64
|
tools:
|
65
65
|
- Edit
|
66
66
|
- Write
|
@@ -111,14 +111,14 @@ swarm:
|
|
111
111
|
react_dev:
|
112
112
|
description: "React developer specializing in components and state management"
|
113
113
|
directory: ./web-frontend/src
|
114
|
-
model:
|
114
|
+
model: opus
|
115
115
|
prompt: "You specialize in React components and state management"
|
116
116
|
tools: [Edit, Write, "Bash(npm:*)"]
|
117
117
|
|
118
118
|
css_expert:
|
119
119
|
description: "CSS specialist handling styling and responsive design"
|
120
120
|
directory: ./web-frontend/styles
|
121
|
-
model:
|
121
|
+
model: opus
|
122
122
|
prompt: "You handle all CSS and styling concerns"
|
123
123
|
tools: [Edit, Write, Read]
|
124
124
|
|
@@ -133,21 +133,21 @@ swarm:
|
|
133
133
|
api_dev:
|
134
134
|
description: "API developer building REST endpoints"
|
135
135
|
directory: ./api-server/src
|
136
|
-
model:
|
136
|
+
model: opus
|
137
137
|
prompt: "You develop REST API endpoints"
|
138
138
|
tools: [Edit, Write, Bash]
|
139
139
|
|
140
140
|
database_expert:
|
141
141
|
description: "Database specialist managing schemas and migrations"
|
142
142
|
directory: ./api-server/db
|
143
|
-
model:
|
143
|
+
model: opus
|
144
144
|
prompt: "You handle database schema and migrations"
|
145
145
|
tools: [Edit, Write, "Bash(psql:*, migrate:*)"]
|
146
146
|
|
147
147
|
mobile_lead:
|
148
148
|
description: "Mobile team lead coordinating cross-platform development"
|
149
149
|
directory: ./mobile-app
|
150
|
-
model:
|
150
|
+
model: opus
|
151
151
|
connections: [ios_dev, android_dev]
|
152
152
|
prompt: "You coordinate mobile development across platforms"
|
153
153
|
tools: [Read, Edit]
|
@@ -155,21 +155,21 @@ swarm:
|
|
155
155
|
ios_dev:
|
156
156
|
description: "iOS developer building native Apple applications"
|
157
157
|
directory: ./mobile-app/ios
|
158
|
-
model:
|
158
|
+
model: opus
|
159
159
|
prompt: "You develop the iOS application"
|
160
160
|
tools: [Edit, Write, "Bash(xcodebuild:*, pod:*)"]
|
161
161
|
|
162
162
|
android_dev:
|
163
163
|
description: "Android developer creating native Android apps"
|
164
164
|
directory: ./mobile-app/android
|
165
|
-
model:
|
165
|
+
model: opus
|
166
166
|
prompt: "You develop the Android application"
|
167
167
|
tools: [Edit, Write, "Bash(gradle:*, adb:*)"]
|
168
168
|
|
169
169
|
devops:
|
170
170
|
description: "DevOps engineer managing CI/CD and infrastructure"
|
171
171
|
directory: ./infrastructure
|
172
|
-
model:
|
172
|
+
model: opus
|
173
173
|
prompt: "You handle CI/CD and infrastructure"
|
174
174
|
tools: [Read, Edit, "Bash(docker:*, kubectl:*)"]
|
175
175
|
```
|
@@ -305,7 +305,7 @@ swarm:
|
|
305
305
|
frontend:
|
306
306
|
description: "Frontend developer specializing in React and TypeScript"
|
307
307
|
directory: ./frontend
|
308
|
-
model:
|
308
|
+
model: opus
|
309
309
|
connections: [architect]
|
310
310
|
prompt: "You specialize in React, TypeScript, and modern frontend development"
|
311
311
|
tools:
|
@@ -316,7 +316,7 @@ swarm:
|
|
316
316
|
backend:
|
317
317
|
description: "Backend developer building APIs and services"
|
318
318
|
directory: ./backend
|
319
|
-
model:
|
319
|
+
model: opus
|
320
320
|
connections: [architect, database]
|
321
321
|
tools:
|
322
322
|
- Edit
|
@@ -334,7 +334,7 @@ swarm:
|
|
334
334
|
devops:
|
335
335
|
description: "DevOps engineer handling deployment and infrastructure"
|
336
336
|
directory: .
|
337
|
-
model:
|
337
|
+
model: opus
|
338
338
|
connections: [architect]
|
339
339
|
tools:
|
340
340
|
- Read
|
@@ -367,7 +367,7 @@ swarm:
|
|
367
367
|
data_analyst:
|
368
368
|
description: "Data analyst processing research data and statistics"
|
369
369
|
directory: ~/research/data
|
370
|
-
model:
|
370
|
+
model: opus
|
371
371
|
tools:
|
372
372
|
- Read
|
373
373
|
- Write
|
@@ -381,7 +381,7 @@ swarm:
|
|
381
381
|
writer:
|
382
382
|
description: "Technical writer preparing research documentation"
|
383
383
|
directory: ~/research/papers
|
384
|
-
model:
|
384
|
+
model: opus
|
385
385
|
tools:
|
386
386
|
- Edit
|
387
387
|
- Write
|
data/claude-swarm.yml
CHANGED
@@ -6,7 +6,7 @@ swarm:
|
|
6
6
|
lead_developer:
|
7
7
|
description: "Lead developer coordinating the team and making architectural decisions"
|
8
8
|
directory: .
|
9
|
-
model:
|
9
|
+
model: opus
|
10
10
|
prompt: "You are the lead developer coordinating the team"
|
11
11
|
tools: [Read, Edit, Bash, Write]
|
12
12
|
connections: [frontend_dev]
|
@@ -16,6 +16,6 @@ swarm:
|
|
16
16
|
frontend_dev:
|
17
17
|
description: "Frontend developer specializing in React and modern web technologies"
|
18
18
|
directory: .
|
19
|
-
model:
|
19
|
+
model: opus
|
20
20
|
prompt: "You specialize in frontend development with React, TypeScript, and modern web technologies"
|
21
21
|
tools: [Read, Edit, Write, "Bash(npm:*)", "Bash(yarn:*)", "Bash(pnpm:*)"]
|
@@ -2,43 +2,85 @@
|
|
2
2
|
|
3
3
|
require "json"
|
4
4
|
require "open3"
|
5
|
+
require "logger"
|
6
|
+
require "fileutils"
|
5
7
|
|
6
8
|
module ClaudeSwarm
|
7
9
|
class ClaudeCodeExecutor
|
8
|
-
|
10
|
+
SWARM_DIR = ".claude-swarm"
|
11
|
+
SESSIONS_DIR = "sessions"
|
9
12
|
|
10
|
-
|
13
|
+
attr_reader :session_id, :last_response, :working_directory, :logger, :session_timestamp
|
14
|
+
|
15
|
+
def initialize(working_directory: Dir.pwd, model: nil, mcp_config: nil, vibe: false, instance_name: nil, calling_instance: nil)
|
11
16
|
@working_directory = working_directory
|
12
17
|
@model = model
|
13
18
|
@mcp_config = mcp_config
|
14
19
|
@vibe = vibe
|
15
20
|
@session_id = nil
|
16
21
|
@last_response = nil
|
22
|
+
@instance_name = instance_name
|
23
|
+
@calling_instance = calling_instance
|
24
|
+
|
25
|
+
# Setup logging
|
26
|
+
setup_logging
|
17
27
|
end
|
18
28
|
|
19
29
|
def execute(prompt, options = {})
|
20
|
-
|
21
|
-
|
22
|
-
stdout, stderr, status = Open3.capture3(*cmd_array, chdir: @working_directory)
|
23
|
-
|
24
|
-
raise ExecutionError, "Claude Code execution failed: #{stderr}" unless status.success?
|
30
|
+
# Log the request
|
31
|
+
log_request(prompt)
|
25
32
|
|
26
|
-
|
27
|
-
response = JSON.parse(stdout)
|
28
|
-
@last_response = response
|
29
|
-
|
30
|
-
# Extract and store session ID from the response
|
31
|
-
@session_id = response["session_id"]
|
33
|
+
cmd_array = build_command_array(prompt, options)
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
# Variables to collect output
|
36
|
+
stderr_output = []
|
37
|
+
result_response = nil
|
38
|
+
|
39
|
+
# Execute command with streaming
|
40
|
+
Open3.popen3(*cmd_array, chdir: @working_directory) do |stdin, stdout, stderr, wait_thread|
|
41
|
+
stdin.close
|
42
|
+
|
43
|
+
# Read stderr in a separate thread
|
44
|
+
stderr_thread = Thread.new do
|
45
|
+
stderr.each_line { |line| stderr_output << line }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Process stdout line by line
|
49
|
+
stdout.each_line do |line|
|
50
|
+
json_data = JSON.parse(line.strip)
|
51
|
+
|
52
|
+
# Log each JSON event
|
53
|
+
log_streaming_event(json_data)
|
54
|
+
|
55
|
+
# Capture session_id from system init
|
56
|
+
@session_id = json_data["session_id"] if json_data["type"] == "system" && json_data["subtype"] == "init"
|
57
|
+
|
58
|
+
# Capture the final result
|
59
|
+
result_response = json_data if json_data["type"] == "result"
|
60
|
+
rescue JSON::ParserError => e
|
61
|
+
@logger.warn("Failed to parse JSON line: #{line.strip} - #{e.message}")
|
62
|
+
end
|
63
|
+
|
64
|
+
# Wait for stderr thread to finish
|
65
|
+
stderr_thread.join
|
66
|
+
|
67
|
+
# Check exit status
|
68
|
+
exit_status = wait_thread.value
|
69
|
+
unless exit_status.success?
|
70
|
+
error_msg = stderr_output.join
|
71
|
+
@logger.error("Execution error for #{@instance_name}: #{error_msg}")
|
72
|
+
raise ExecutionError, "Claude Code execution failed: #{error_msg}"
|
73
|
+
end
|
36
74
|
end
|
37
|
-
end
|
38
75
|
|
39
|
-
|
40
|
-
|
41
|
-
|
76
|
+
# Ensure we got a result
|
77
|
+
raise ParseError, "No result found in stream output" unless result_response
|
78
|
+
|
79
|
+
result_response
|
80
|
+
rescue StandardError => e
|
81
|
+
@logger.error("Unexpected error for #{@instance_name}: #{e.class} - #{e.message}")
|
82
|
+
@logger.error("Backtrace: #{e.backtrace.join("\n")}")
|
83
|
+
raise
|
42
84
|
end
|
43
85
|
|
44
86
|
def reset_session
|
@@ -52,12 +94,90 @@ module ClaudeSwarm
|
|
52
94
|
|
53
95
|
private
|
54
96
|
|
97
|
+
def setup_logging
|
98
|
+
# Use environment variable for session timestamp if available (set by orchestrator)
|
99
|
+
# Otherwise create a new timestamp
|
100
|
+
@session_timestamp = ENV["CLAUDE_SWARM_SESSION_TIMESTAMP"] || Time.now.strftime("%Y%m%d_%H%M%S")
|
101
|
+
|
102
|
+
# Ensure the session directory exists
|
103
|
+
session_dir = File.join(Dir.pwd, SWARM_DIR, SESSIONS_DIR, @session_timestamp)
|
104
|
+
FileUtils.mkdir_p(session_dir)
|
105
|
+
|
106
|
+
# Create logger with session.log filename
|
107
|
+
log_filename = "session.log"
|
108
|
+
log_path = File.join(session_dir, log_filename)
|
109
|
+
@logger = Logger.new(log_path)
|
110
|
+
@logger.level = Logger::INFO
|
111
|
+
|
112
|
+
# Custom formatter for better readability
|
113
|
+
@logger.formatter = proc do |severity, datetime, _progname, msg|
|
114
|
+
"[#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")}] [#{severity}] #{msg}\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
@logger.info("Started Claude Code executor for instance: #{@instance_name}") if @instance_name
|
118
|
+
end
|
119
|
+
|
120
|
+
def log_request(prompt)
|
121
|
+
@logger.info("#{@calling_instance} -> #{@instance_name}: \n---\n#{prompt}\n---")
|
122
|
+
end
|
123
|
+
|
124
|
+
def log_response(response)
|
125
|
+
@logger.info(
|
126
|
+
"($#{response["total_cost"]} - #{response["duration_ms"]}ms) #{@instance_name} -> #{@calling_instance}: \n---\n#{response["result"]}\n---"
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
def log_streaming_event(event)
|
131
|
+
return log_system_message(event) if event["type"] == "system"
|
132
|
+
|
133
|
+
# Add specific details based on event type
|
134
|
+
case event["type"]
|
135
|
+
when "assistant"
|
136
|
+
log_assistant_message(event["message"])
|
137
|
+
when "user"
|
138
|
+
log_user_message(event["message"]["content"])
|
139
|
+
when "result"
|
140
|
+
log_response(event)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def log_system_message(event)
|
145
|
+
@logger.debug("SYSTEM: #{JSON.pretty_generate(event)}")
|
146
|
+
end
|
147
|
+
|
148
|
+
def log_assistant_message(msg)
|
149
|
+
return if msg["stop_reason"] == "end_turn" # that means it is not a thought but the final answer
|
150
|
+
|
151
|
+
content = msg["content"]
|
152
|
+
@logger.debug("ASSISTANT: #{JSON.pretty_generate(content)}")
|
153
|
+
tool_calls = content.select { |c| c["type"] == "tool_use" }
|
154
|
+
tool_calls.each do |tool_call|
|
155
|
+
arguments = tool_call["input"].to_json
|
156
|
+
arguments = "#{arguments[0..300]} ...}" if arguments.length > 300
|
157
|
+
|
158
|
+
@logger.info(
|
159
|
+
"Tool call from #{@instance_name} -> Tool: #{tool_call["name"]}, ID: #{tool_call["id"]}, Arguments: #{arguments}"
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
text = content.select { |c| c["type"] == "text" }
|
164
|
+
text.each do |t|
|
165
|
+
@logger.info("#{@instance_name} is thinking:\n---\n#{t["text"]}\n---")
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def log_user_message(content)
|
170
|
+
@logger.debug("USER: #{JSON.pretty_generate(content)}")
|
171
|
+
end
|
172
|
+
|
55
173
|
def build_command_array(prompt, options)
|
56
174
|
cmd_array = ["claude"]
|
57
175
|
|
58
176
|
# Add model if specified
|
59
177
|
cmd_array += ["--model", @model]
|
60
178
|
|
179
|
+
cmd_array << "--verbose"
|
180
|
+
|
61
181
|
# Add MCP config if specified
|
62
182
|
cmd_array += ["--mcp-config", @mcp_config] if @mcp_config
|
63
183
|
|
@@ -65,7 +185,7 @@ module ClaudeSwarm
|
|
65
185
|
cmd_array += ["--resume", @session_id] if @session_id && !options[:new_session]
|
66
186
|
|
67
187
|
# Always use JSON output format for structured responses
|
68
|
-
cmd_array += ["--output-format", "json"]
|
188
|
+
cmd_array += ["--output-format", "stream-json"]
|
69
189
|
|
70
190
|
# Add non-interactive mode with prompt
|
71
191
|
cmd_array += ["--print", "-p", prompt]
|
@@ -2,15 +2,13 @@
|
|
2
2
|
|
3
3
|
require "fast_mcp"
|
4
4
|
require "json"
|
5
|
-
require "fileutils"
|
6
|
-
require "logger"
|
7
5
|
require_relative "claude_code_executor"
|
6
|
+
require_relative "task_tool"
|
7
|
+
require_relative "session_info_tool"
|
8
|
+
require_relative "reset_session_tool"
|
8
9
|
|
9
10
|
module ClaudeSwarm
|
10
11
|
class ClaudeMcpServer
|
11
|
-
SWARM_DIR = ".claude-swarm"
|
12
|
-
SESSIONS_DIR = "sessions"
|
13
|
-
|
14
12
|
# Class variables to share state with tool classes
|
15
13
|
class << self
|
16
14
|
attr_accessor :executor, :instance_config, :logger, :session_timestamp, :calling_instance
|
@@ -23,46 +21,19 @@ module ClaudeSwarm
|
|
23
21
|
working_directory: instance_config[:directory],
|
24
22
|
model: instance_config[:model],
|
25
23
|
mcp_config: instance_config[:mcp_config_path],
|
26
|
-
vibe: instance_config[:vibe]
|
24
|
+
vibe: instance_config[:vibe],
|
25
|
+
instance_name: instance_config[:name],
|
26
|
+
calling_instance: calling_instance
|
27
27
|
)
|
28
28
|
|
29
|
-
# Setup logging
|
30
|
-
setup_logging
|
31
|
-
|
32
29
|
# Set class variables so tools can access them
|
33
30
|
self.class.executor = @executor
|
34
31
|
self.class.instance_config = @instance_config
|
35
|
-
self.class.logger = @logger
|
32
|
+
self.class.logger = @executor.logger
|
33
|
+
self.class.session_timestamp = @executor.session_timestamp
|
36
34
|
self.class.calling_instance = @calling_instance
|
37
35
|
end
|
38
36
|
|
39
|
-
private
|
40
|
-
|
41
|
-
def setup_logging
|
42
|
-
# Use environment variable for session timestamp if available (set by orchestrator)
|
43
|
-
# Otherwise create a new timestamp
|
44
|
-
self.class.session_timestamp ||= ENV["CLAUDE_SWARM_SESSION_TIMESTAMP"] || Time.now.strftime("%Y%m%d_%H%M%S")
|
45
|
-
|
46
|
-
# Ensure the session directory exists
|
47
|
-
session_dir = File.join(Dir.pwd, SWARM_DIR, SESSIONS_DIR, self.class.session_timestamp)
|
48
|
-
FileUtils.mkdir_p(session_dir)
|
49
|
-
|
50
|
-
# Create logger with session.log filename
|
51
|
-
log_filename = "session.log"
|
52
|
-
log_path = File.join(session_dir, log_filename)
|
53
|
-
@logger = Logger.new(log_path)
|
54
|
-
@logger.level = Logger::INFO
|
55
|
-
|
56
|
-
# Custom formatter for better readability
|
57
|
-
@logger.formatter = proc do |severity, datetime, _progname, msg|
|
58
|
-
"[#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")}] [#{severity}] #{msg}\n"
|
59
|
-
end
|
60
|
-
|
61
|
-
@logger.info("Started MCP server for instance: #{@instance_config[:name]}")
|
62
|
-
end
|
63
|
-
|
64
|
-
public
|
65
|
-
|
66
37
|
def start
|
67
38
|
server = FastMcp::Server.new(
|
68
39
|
name: @instance_config[:name],
|
@@ -84,120 +55,5 @@ module ClaudeSwarm
|
|
84
55
|
# Start the stdio server
|
85
56
|
server.start
|
86
57
|
end
|
87
|
-
|
88
|
-
class TaskTool < FastMcp::Tool
|
89
|
-
tool_name "task"
|
90
|
-
description "Execute a task using Claude Code"
|
91
|
-
|
92
|
-
arguments do
|
93
|
-
required(:prompt).filled(:string).description("The task or question for the agent")
|
94
|
-
optional(:new_session).filled(:bool).description("Start a new session (default: false)")
|
95
|
-
optional(:system_prompt).filled(:string).description("Override the system prompt for this request")
|
96
|
-
end
|
97
|
-
|
98
|
-
def call(prompt:, new_session: false, system_prompt: nil)
|
99
|
-
executor = ClaudeMcpServer.executor
|
100
|
-
instance_config = ClaudeMcpServer.instance_config
|
101
|
-
logger = ClaudeMcpServer.logger
|
102
|
-
|
103
|
-
options = {
|
104
|
-
new_session: new_session,
|
105
|
-
system_prompt: system_prompt || instance_config[:prompt]
|
106
|
-
}
|
107
|
-
|
108
|
-
# Add allowed tools from instance config
|
109
|
-
options[:allowed_tools] = instance_config[:tools] if instance_config[:tools]&.any?
|
110
|
-
|
111
|
-
begin
|
112
|
-
# Log the request
|
113
|
-
log_entry = {
|
114
|
-
timestamp: Time.now.utc.iso8601,
|
115
|
-
from_instance: ClaudeMcpServer.calling_instance, # The instance making the request
|
116
|
-
to_instance: instance_config[:name], # This instance is receiving the request
|
117
|
-
model: instance_config[:model],
|
118
|
-
working_directory: instance_config[:directory],
|
119
|
-
session_id: executor.session_id,
|
120
|
-
request: {
|
121
|
-
prompt: prompt,
|
122
|
-
new_session: new_session,
|
123
|
-
system_prompt: options[:system_prompt],
|
124
|
-
allowed_tools: options[:allowed_tools]
|
125
|
-
}
|
126
|
-
}
|
127
|
-
|
128
|
-
logger.info("REQUEST: #{JSON.pretty_generate(log_entry)}")
|
129
|
-
|
130
|
-
response = executor.execute(prompt, options)
|
131
|
-
|
132
|
-
# Log the response
|
133
|
-
response_entry = {
|
134
|
-
timestamp: Time.now.utc.iso8601,
|
135
|
-
from_instance: instance_config[:name], # This instance is sending the response
|
136
|
-
to_instance: ClaudeMcpServer.calling_instance, # The instance that made the request receives the response
|
137
|
-
session_id: executor.session_id, # Update with new session ID if changed
|
138
|
-
response: {
|
139
|
-
result: response["result"],
|
140
|
-
cost_usd: response["cost_usd"],
|
141
|
-
duration_ms: response["duration_ms"],
|
142
|
-
is_error: response["is_error"],
|
143
|
-
total_cost: response["total_cost"]
|
144
|
-
}
|
145
|
-
}
|
146
|
-
|
147
|
-
logger.info("RESPONSE: #{JSON.pretty_generate(response_entry)}")
|
148
|
-
|
149
|
-
# Return just the result text as expected by MCP
|
150
|
-
response["result"]
|
151
|
-
rescue ClaudeCodeExecutor::ExecutionError => e
|
152
|
-
logger.error("Execution error for #{instance_config[:name]}: #{e.message}")
|
153
|
-
raise StandardError, "Execution failed: #{e.message}"
|
154
|
-
rescue ClaudeCodeExecutor::ParseError => e
|
155
|
-
logger.error("Parse error for #{instance_config[:name]}: #{e.message}")
|
156
|
-
raise StandardError, "Parse error: #{e.message}"
|
157
|
-
rescue StandardError => e
|
158
|
-
logger.error("Unexpected error for #{instance_config[:name]}: #{e.class} - #{e.message}")
|
159
|
-
logger.error("Backtrace: #{e.backtrace.join("\n")}")
|
160
|
-
raise StandardError, "Unexpected error: #{e.message}"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
class SessionInfoTool < FastMcp::Tool
|
166
|
-
tool_name "session_info"
|
167
|
-
description "Get information about the current Claude session for this agent"
|
168
|
-
|
169
|
-
arguments do
|
170
|
-
# No arguments needed
|
171
|
-
end
|
172
|
-
|
173
|
-
def call
|
174
|
-
executor = ClaudeMcpServer.executor
|
175
|
-
|
176
|
-
{
|
177
|
-
has_session: executor.has_session?,
|
178
|
-
session_id: executor.session_id,
|
179
|
-
working_directory: executor.working_directory
|
180
|
-
}
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
class ResetSessionTool < FastMcp::Tool
|
185
|
-
tool_name "reset_session"
|
186
|
-
description "Reset the Claude session for this agent, starting fresh on the next task"
|
187
|
-
|
188
|
-
arguments do
|
189
|
-
# No arguments needed
|
190
|
-
end
|
191
|
-
|
192
|
-
def call
|
193
|
-
executor = ClaudeMcpServer.executor
|
194
|
-
executor.reset_session
|
195
|
-
|
196
|
-
{
|
197
|
-
success: true,
|
198
|
-
message: "Session has been reset"
|
199
|
-
}
|
200
|
-
end
|
201
|
-
end
|
202
58
|
end
|
203
59
|
end
|
@@ -51,32 +51,43 @@ module ClaudeSwarm
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# Execute the main instance - this will cascade to other instances via MCP
|
54
|
-
|
54
|
+
Dir.chdir(main_instance[:directory]) do
|
55
|
+
system(*command)
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
private
|
58
60
|
|
59
61
|
def build_main_command(instance)
|
60
|
-
parts = [
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
parts = [
|
63
|
+
"claude",
|
64
|
+
"--model",
|
65
|
+
instance[:model]
|
66
|
+
]
|
64
67
|
|
65
68
|
if @vibe
|
66
69
|
parts << "--dangerously-skip-permissions"
|
67
70
|
elsif instance[:tools].any?
|
68
71
|
tools_str = instance[:tools].join(",")
|
69
|
-
parts << "--allowedTools
|
72
|
+
parts << "--allowedTools"
|
73
|
+
parts << tools_str
|
70
74
|
end
|
71
75
|
|
72
|
-
|
76
|
+
if instance[:prompt]
|
77
|
+
parts << "--append-system-prompt"
|
78
|
+
parts << instance[:prompt]
|
79
|
+
end
|
73
80
|
|
74
81
|
mcp_config_path = @generator.mcp_config_path(@config.main_instance)
|
75
|
-
parts << "--mcp-config
|
82
|
+
parts << "--mcp-config"
|
83
|
+
parts << mcp_config_path
|
76
84
|
|
77
|
-
|
78
|
-
|
79
|
-
|
85
|
+
if @prompt
|
86
|
+
parts << "-p"
|
87
|
+
parts << @prompt
|
88
|
+
else
|
89
|
+
parts << "#{instance[:prompt]}\n\nNow just say 'I am ready to start'"
|
90
|
+
end
|
80
91
|
end
|
81
92
|
end
|
82
93
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClaudeSwarm
|
4
|
+
class ResetSessionTool < FastMcp::Tool
|
5
|
+
tool_name "reset_session"
|
6
|
+
description "Reset the Claude session for this agent, starting fresh on the next task"
|
7
|
+
|
8
|
+
arguments do
|
9
|
+
# No arguments needed
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
executor = ClaudeMcpServer.executor
|
14
|
+
executor.reset_session
|
15
|
+
|
16
|
+
{
|
17
|
+
success: true,
|
18
|
+
message: "Session has been reset"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClaudeSwarm
|
4
|
+
class SessionInfoTool < FastMcp::Tool
|
5
|
+
tool_name "session_info"
|
6
|
+
description "Get information about the current Claude session for this agent"
|
7
|
+
|
8
|
+
arguments do
|
9
|
+
# No arguments needed
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
executor = ClaudeMcpServer.executor
|
14
|
+
|
15
|
+
{
|
16
|
+
has_session: executor.has_session?,
|
17
|
+
session_id: executor.session_id,
|
18
|
+
working_directory: executor.working_directory
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClaudeSwarm
|
4
|
+
class TaskTool < FastMcp::Tool
|
5
|
+
tool_name "task"
|
6
|
+
description "Execute a task using Claude Code"
|
7
|
+
|
8
|
+
arguments do
|
9
|
+
required(:prompt).filled(:string).description("The task or question for the agent")
|
10
|
+
optional(:new_session).filled(:bool).description("Start a new session (default: false)")
|
11
|
+
optional(:system_prompt).filled(:string).description("Override the system prompt for this request")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(prompt:, new_session: false, system_prompt: nil)
|
15
|
+
executor = ClaudeMcpServer.executor
|
16
|
+
instance_config = ClaudeMcpServer.instance_config
|
17
|
+
|
18
|
+
options = {
|
19
|
+
new_session: new_session,
|
20
|
+
system_prompt: system_prompt || instance_config[:prompt]
|
21
|
+
}
|
22
|
+
|
23
|
+
# Add allowed tools from instance config
|
24
|
+
options[:allowed_tools] = instance_config[:tools] if instance_config[:tools]&.any?
|
25
|
+
|
26
|
+
response = executor.execute(prompt, options)
|
27
|
+
|
28
|
+
# Return just the result text as expected by MCP
|
29
|
+
response["result"]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/claude_swarm/version.rb
CHANGED
data/sdk-docs.md
ADDED
@@ -0,0 +1,426 @@
|
|
1
|
+
# SDK
|
2
|
+
|
3
|
+
> Programmatically integrate Claude Code into your applications using the SDK.
|
4
|
+
|
5
|
+
The Claude Code SDK allows developers to programmatically integrate Claude Code into their applications. It enables running Claude Code as a subprocess, providing a way to build AI-powered coding assistants and tools that leverage Claude's capabilities.
|
6
|
+
|
7
|
+
The SDK currently support command line usage. TypeScript and Python SDKs are coming soon.
|
8
|
+
|
9
|
+
## Authentication
|
10
|
+
|
11
|
+
To use the Claude Code SDK, we recommend creating a dedicated API key:
|
12
|
+
|
13
|
+
1. Create an Anthropic API key in the [Anthropic Console](https://console.anthropic.com/)
|
14
|
+
2. Then, set the `ANTHROPIC_API_KEY` environment variable. We recommend storing this key securely (eg. using a Github [secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions))
|
15
|
+
|
16
|
+
## Basic SDK usage
|
17
|
+
|
18
|
+
The Claude Code SDK allows you to use Claude Code in non-interactive mode from your applications. Here's a basic example:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
# Run a single prompt and exit (print mode)
|
22
|
+
$ claude -p "Write a function to calculate Fibonacci numbers"
|
23
|
+
|
24
|
+
# Using a pipe to provide stdin
|
25
|
+
$ echo "Explain this code" | claude -p
|
26
|
+
|
27
|
+
# Output in JSON format with metadata
|
28
|
+
$ claude -p "Generate a hello world function" --output-format json
|
29
|
+
|
30
|
+
# Stream JSON output as it arrives
|
31
|
+
$ claude -p "Build a React component" --output-format stream-json
|
32
|
+
```
|
33
|
+
|
34
|
+
## Advanced usage
|
35
|
+
|
36
|
+
### Multi-turn conversations
|
37
|
+
|
38
|
+
For multi-turn conversations, you can resume conversations or continue from the most recent session:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
# Continue the most recent conversation
|
42
|
+
$ claude --continue
|
43
|
+
|
44
|
+
# Continue and provide a new prompt
|
45
|
+
$ claude --continue "Now refactor this for better performance"
|
46
|
+
|
47
|
+
# Resume a specific conversation by session ID
|
48
|
+
$ claude --resume 550e8400-e29b-41d4-a716-446655440000
|
49
|
+
|
50
|
+
# Resume in print mode (non-interactive)
|
51
|
+
$ claude -p --resume 550e8400-e29b-41d4-a716-446655440000 "Update the tests"
|
52
|
+
|
53
|
+
# Continue in print mode (non-interactive)
|
54
|
+
$ claude -p --continue "Add error handling"
|
55
|
+
```
|
56
|
+
|
57
|
+
### Custom system prompts
|
58
|
+
|
59
|
+
You can provide custom system prompts to guide Claude's behavior:
|
60
|
+
|
61
|
+
```bash
|
62
|
+
# Override system prompt (only works with --print)
|
63
|
+
$ claude -p "Build a REST API" --system-prompt "You are a senior backend engineer. Focus on security, performance, and maintainability."
|
64
|
+
|
65
|
+
# System prompt with specific requirements
|
66
|
+
$ claude -p "Create a database schema" --system-prompt "You are a database architect. Use PostgreSQL best practices and include proper indexing."
|
67
|
+
```
|
68
|
+
|
69
|
+
You can also append instructions to the default system prompt:
|
70
|
+
|
71
|
+
```bash
|
72
|
+
# Append system prompt (only works with --print)
|
73
|
+
$ claude -p "Build a REST API" --append-system-prompt "After writing code, be sure to code review yourself."
|
74
|
+
```
|
75
|
+
|
76
|
+
### MCP Configuration
|
77
|
+
|
78
|
+
The Model Context Protocol (MCP) allows you to extend Claude Code with additional tools and resources from external servers. Using the `--mcp-config` flag, you can load MCP servers that provide specialized capabilities like database access, API integrations, or custom tooling.
|
79
|
+
|
80
|
+
Create a JSON configuration file with your MCP servers:
|
81
|
+
|
82
|
+
```json
|
83
|
+
{
|
84
|
+
"mcpServers": {
|
85
|
+
"filesystem": {
|
86
|
+
"command": "npx",
|
87
|
+
"args": [
|
88
|
+
"-y",
|
89
|
+
"@modelcontextprotocol/server-filesystem",
|
90
|
+
"/path/to/allowed/files"
|
91
|
+
]
|
92
|
+
},
|
93
|
+
"github": {
|
94
|
+
"command": "npx",
|
95
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
96
|
+
"env": {
|
97
|
+
"GITHUB_TOKEN": "your-github-token"
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
```
|
103
|
+
|
104
|
+
Then use it with Claude Code:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
# Load MCP servers from configuration
|
108
|
+
$ claude -p "List all files in the project" --mcp-config mcp-servers.json
|
109
|
+
|
110
|
+
# Important: MCP tools must be explicitly allowed using --allowedTools
|
111
|
+
# MCP tools follow the format: mcp__$serverName__$toolName
|
112
|
+
$ claude -p "Search for TODO comments" \
|
113
|
+
--mcp-config mcp-servers.json \
|
114
|
+
--allowedTools "mcp__filesystem__read_file,mcp__filesystem__list_directory"
|
115
|
+
|
116
|
+
# Use an MCP tool for handling permission prompts in non-interactive mode
|
117
|
+
$ claude -p "Deploy the application" \
|
118
|
+
--mcp-config mcp-servers.json \
|
119
|
+
--allowedTools "mcp__permissions__approve" \
|
120
|
+
--permission-prompt-tool mcp__permissions__approve
|
121
|
+
```
|
122
|
+
|
123
|
+
Note: When using MCP tools, you must explicitly allow them using the `--allowedTools` flag. MCP tool names follow the pattern `mcp__<serverName>__<toolName>` where:
|
124
|
+
|
125
|
+
* `serverName` is the key from your MCP configuration file
|
126
|
+
* `toolName` is the specific tool provided by that server
|
127
|
+
|
128
|
+
This security measure ensures that MCP tools are only used when explicitly permitted.
|
129
|
+
|
130
|
+
### Custom permission prompt tool
|
131
|
+
|
132
|
+
Optionally, use `--permission-prompt-tool` to pass in an MCP tool that we will use to check whether or not the user grants the model permissions to invoke a given tool. When the model invokes a tool the following happens:
|
133
|
+
|
134
|
+
1. We first check permission settings: all [settings.json files](/en/docs/claude-code/settings), as well as `--allowedTools` and `--disallowedTools` passed into the SDK; if one of these allows or denies the tool call, we proceed with the tool call
|
135
|
+
2. Otherwise, we invoke the MCP tool you provided in `--permission-prompt-tool`
|
136
|
+
|
137
|
+
The `--permission-prompt-tool` MCP tool is passed the tool name and input, and must return a JSON-stringified payload with the result. The payload must be one of:
|
138
|
+
|
139
|
+
```ts
|
140
|
+
// tool call is allowed
|
141
|
+
{
|
142
|
+
"behavior": "allow",
|
143
|
+
"updatedInput": {...}, // updated input, or just return back the original input
|
144
|
+
}
|
145
|
+
|
146
|
+
// tool call is denied
|
147
|
+
{
|
148
|
+
"behavior": "deny",
|
149
|
+
"message": "..." // human-readable string explaining why the permission was denied
|
150
|
+
}
|
151
|
+
```
|
152
|
+
|
153
|
+
For example, a TypeScript MCP permission prompt tool implementation might look like this:
|
154
|
+
|
155
|
+
```ts
|
156
|
+
const server = new McpServer({
|
157
|
+
name: "Test permission prompt MCP Server",
|
158
|
+
version: "0.0.1",
|
159
|
+
});
|
160
|
+
|
161
|
+
server.tool(
|
162
|
+
"approval_prompt",
|
163
|
+
'Simulate a permission check - approve if the input contains "allow", otherwise deny',
|
164
|
+
{
|
165
|
+
tool_name: z.string().describe("The tool requesting permission"),
|
166
|
+
input: z.object({}).passthrough().describe("The input for the tool"),
|
167
|
+
},
|
168
|
+
async ({ tool_name, input }) => {
|
169
|
+
return {
|
170
|
+
content: [
|
171
|
+
{
|
172
|
+
type: "text",
|
173
|
+
text: JSON.stringify(
|
174
|
+
JSON.stringify(input).includes("allow")
|
175
|
+
? {
|
176
|
+
behavior: "allow",
|
177
|
+
updatedInput: input,
|
178
|
+
}
|
179
|
+
: {
|
180
|
+
behavior: "deny",
|
181
|
+
message: "Permission denied by test approval_prompt tool",
|
182
|
+
}
|
183
|
+
),
|
184
|
+
},
|
185
|
+
],
|
186
|
+
};
|
187
|
+
}
|
188
|
+
);
|
189
|
+
```
|
190
|
+
|
191
|
+
To use this tool, add your MCP server (eg. with `--mcp-config`), then invoke the SDK like so:
|
192
|
+
|
193
|
+
```sh
|
194
|
+
claude -p "..." \
|
195
|
+
--permission-prompt-tool mcp__test-server__approval_prompt \
|
196
|
+
--mcp-config my-config.json
|
197
|
+
```
|
198
|
+
|
199
|
+
Usage notes:
|
200
|
+
|
201
|
+
* Use `updatedInput` to tell the model that the permission prompt mutated its input; otherwise, set `updatedInput` to the original input, as in the example above. For example, if the tool shows a file edit diff to the user and lets them edit the diff manually, the permission prompt tool should return that updated edit.
|
202
|
+
* The payload must be JSON-stringified
|
203
|
+
|
204
|
+
## Available CLI options
|
205
|
+
|
206
|
+
The SDK leverages all the CLI options available in Claude Code. Here are the key ones for SDK usage:
|
207
|
+
|
208
|
+
| Flag | Description | Example |
|
209
|
+
| :------------------------- | :--------------------------------------------------------------- | :------------------------------------------------------------- |
|
210
|
+
| `--print`, `-p` | Run in non-interactive mode | `claude -p "query"` |
|
211
|
+
| `--output-format` | Specify output format (`text`, `json`, `stream-json`) | `claude -p --output-format json` |
|
212
|
+
| `--resume`, `-r` | Resume a conversation by session ID | `claude --resume abc123` |
|
213
|
+
| `--continue`, `-c` | Continue the most recent conversation | `claude --continue` |
|
214
|
+
| `--verbose` | Enable verbose logging | `claude --verbose` |
|
215
|
+
| `--max-turns` | Limit agentic turns in non-interactive mode | `claude --max-turns 3` |
|
216
|
+
| `--system-prompt` | Override system prompt (only with `--print`) | `claude --system-prompt "Custom instruction"` |
|
217
|
+
| `--append-system-prompt` | Append to system prompt (only with `--print`) | `claude --append-system-prompt "Custom instruction"` |
|
218
|
+
| `--allowedTools` | Comma/space-separated list of allowed tools (includes MCP tools) | `claude --allowedTools "Bash(npm install),mcp__filesystem__*"` |
|
219
|
+
| `--disallowedTools` | Comma/space-separated list of denied tools | `claude --disallowedTools "Bash(git commit),mcp__github__*"` |
|
220
|
+
| `--mcp-config` | Load MCP servers from a JSON file | `claude --mcp-config servers.json` |
|
221
|
+
| `--permission-prompt-tool` | MCP tool for handling permission prompts (only with `--print`) | `claude --permission-prompt-tool mcp__auth__prompt` |
|
222
|
+
|
223
|
+
For a complete list of CLI options and features, see the [CLI usage](/en/docs/claude-code/cli-usage) documentation.
|
224
|
+
|
225
|
+
## Output formats
|
226
|
+
|
227
|
+
The SDK supports multiple output formats:
|
228
|
+
|
229
|
+
### Text output (default)
|
230
|
+
|
231
|
+
Returns just the response text:
|
232
|
+
|
233
|
+
```bash
|
234
|
+
$ claude -p "Explain file src/components/Header.tsx"
|
235
|
+
# Output: This is a React component showing...
|
236
|
+
```
|
237
|
+
|
238
|
+
### JSON output
|
239
|
+
|
240
|
+
Returns structured data including metadata:
|
241
|
+
|
242
|
+
```bash
|
243
|
+
$ claude -p "How does the data layer work?" --output-format json
|
244
|
+
```
|
245
|
+
|
246
|
+
Response format:
|
247
|
+
|
248
|
+
```json
|
249
|
+
{
|
250
|
+
"type": "result",
|
251
|
+
"subtype": "success",
|
252
|
+
"cost_usd": 0.003,
|
253
|
+
"is_error": false,
|
254
|
+
"duration_ms": 1234,
|
255
|
+
"duration_api_ms": 800,
|
256
|
+
"num_turns": 6,
|
257
|
+
"result": "The response text here...",
|
258
|
+
"session_id": "abc123"
|
259
|
+
}
|
260
|
+
```
|
261
|
+
|
262
|
+
### Streaming JSON output
|
263
|
+
|
264
|
+
Streams each message as it is received:
|
265
|
+
|
266
|
+
```bash
|
267
|
+
$ claude -p "Build an application" --output-format stream-json
|
268
|
+
```
|
269
|
+
|
270
|
+
Each conversation begins with an initial `init` system message, followed by a list of user and assistant messages, followed by a final `result` system message with stats. Each message is emitted as a separate JSON object.
|
271
|
+
|
272
|
+
## Message schema
|
273
|
+
|
274
|
+
Messages returned from the JSON API are strictly typed according to the following schema:
|
275
|
+
|
276
|
+
```ts
|
277
|
+
type SDKMessage =
|
278
|
+
// An assistant message
|
279
|
+
| {
|
280
|
+
type: "assistant";
|
281
|
+
message: Message; // from Anthropic SDK
|
282
|
+
session_id: string;
|
283
|
+
}
|
284
|
+
|
285
|
+
// A user message
|
286
|
+
| {
|
287
|
+
type: "user";
|
288
|
+
message: MessageParam; // from Anthropic SDK
|
289
|
+
session_id: string;
|
290
|
+
}
|
291
|
+
|
292
|
+
// Emitted as the last message
|
293
|
+
| {
|
294
|
+
type: "result";
|
295
|
+
subtype: "success";
|
296
|
+
cost_usd: float;
|
297
|
+
duration_ms: float;
|
298
|
+
duration_api_ms: float;
|
299
|
+
is_error: boolean;
|
300
|
+
num_turns: int;
|
301
|
+
result: string;
|
302
|
+
session_id: string;
|
303
|
+
}
|
304
|
+
|
305
|
+
// Emitted as the last message, when we've reached the maximum number of turns
|
306
|
+
| {
|
307
|
+
type: "result";
|
308
|
+
subtype: "error_max_turns";
|
309
|
+
cost_usd: float;
|
310
|
+
duration_ms: float;
|
311
|
+
duration_api_ms: float;
|
312
|
+
is_error: boolean;
|
313
|
+
num_turns: int;
|
314
|
+
session_id: string;
|
315
|
+
}
|
316
|
+
|
317
|
+
// Emitted as the first message at the start of a conversation
|
318
|
+
| {
|
319
|
+
type: "system";
|
320
|
+
subtype: "init";
|
321
|
+
session_id: string;
|
322
|
+
tools: string[];
|
323
|
+
mcp_servers: {
|
324
|
+
name: string;
|
325
|
+
status: string;
|
326
|
+
}[];
|
327
|
+
};
|
328
|
+
```
|
329
|
+
|
330
|
+
We will soon publish these types in a JSONSchema-compatible format. We use semantic versioning for the main Claude Code package to communicate breaking changes to this format.
|
331
|
+
|
332
|
+
`Message` and `MessageParam` types are available in Anthropic SDKs. For example, see the Anthropic [TypeScript](https://github.com/anthropics/anthropic-sdk-typescript) and [Python](https://github.com/anthropics/anthropic-sdk-python/) SDKs.
|
333
|
+
|
334
|
+
## Examples
|
335
|
+
|
336
|
+
### Simple script integration
|
337
|
+
|
338
|
+
```bash
|
339
|
+
#!/bin/bash
|
340
|
+
|
341
|
+
# Simple function to run Claude and check exit code
|
342
|
+
run_claude() {
|
343
|
+
local prompt="$1"
|
344
|
+
local output_format="${2:-text}"
|
345
|
+
|
346
|
+
if claude -p "$prompt" --output-format "$output_format"; then
|
347
|
+
echo "Success!"
|
348
|
+
else
|
349
|
+
echo "Error: Claude failed with exit code $?" >&2
|
350
|
+
return 1
|
351
|
+
fi
|
352
|
+
}
|
353
|
+
|
354
|
+
# Usage examples
|
355
|
+
run_claude "Write a Python function to read CSV files"
|
356
|
+
run_claude "Optimize this database query" "json"
|
357
|
+
```
|
358
|
+
|
359
|
+
### Processing files with Claude
|
360
|
+
|
361
|
+
```bash
|
362
|
+
# Process a file through Claude
|
363
|
+
$ cat mycode.py | claude -p "Review this code for bugs"
|
364
|
+
|
365
|
+
# Process multiple files
|
366
|
+
$ for file in *.js; do
|
367
|
+
echo "Processing $file..."
|
368
|
+
claude -p "Add JSDoc comments to this file:" < "$file" > "${file}.documented"
|
369
|
+
done
|
370
|
+
|
371
|
+
# Use Claude in a pipeline
|
372
|
+
$ grep -l "TODO" *.py | while read file; do
|
373
|
+
claude -p "Fix all TODO items in this file" < "$file"
|
374
|
+
done
|
375
|
+
```
|
376
|
+
|
377
|
+
### Session management
|
378
|
+
|
379
|
+
```bash
|
380
|
+
# Start a session and capture the session ID
|
381
|
+
$ claude -p "Initialize a new project" --output-format json | jq -r '.session_id' > session.txt
|
382
|
+
|
383
|
+
# Continue with the same session
|
384
|
+
$ claude -p --resume "$(cat session.txt)" "Add unit tests"
|
385
|
+
```
|
386
|
+
|
387
|
+
## Best practices
|
388
|
+
|
389
|
+
1. **Use JSON output format** for programmatic parsing of responses:
|
390
|
+
|
391
|
+
```bash
|
392
|
+
# Parse JSON response with jq
|
393
|
+
result=$(claude -p "Generate code" --output-format json)
|
394
|
+
code=$(echo "$result" | jq -r '.result')
|
395
|
+
cost=$(echo "$result" | jq -r '.cost_usd')
|
396
|
+
```
|
397
|
+
|
398
|
+
2. **Handle errors gracefully** - check exit codes and stderr:
|
399
|
+
|
400
|
+
```bash
|
401
|
+
if ! claude -p "$prompt" 2>error.log; then
|
402
|
+
echo "Error occurred:" >&2
|
403
|
+
cat error.log >&2
|
404
|
+
exit 1
|
405
|
+
fi
|
406
|
+
```
|
407
|
+
|
408
|
+
3. **Use session management** for maintaining context in multi-turn conversations
|
409
|
+
|
410
|
+
4. **Consider timeouts** for long-running operations:
|
411
|
+
|
412
|
+
```bash
|
413
|
+
timeout 300 claude -p "$complex_prompt" || echo "Timed out after 5 minutes"
|
414
|
+
```
|
415
|
+
|
416
|
+
5. **Respect rate limits** when making multiple requests by adding delays between calls
|
417
|
+
|
418
|
+
## Real-world applications
|
419
|
+
|
420
|
+
The Claude Code SDK enables powerful integrations with your development workflow. One notable example is the [Claude Code GitHub Actions](/en/docs/claude-code/github-actions), which uses the SDK to provide automated code review, PR creation, and issue triage capabilities directly in your GitHub workflow.
|
421
|
+
|
422
|
+
## Related resources
|
423
|
+
|
424
|
+
* [CLI usage and controls](/en/docs/claude-code/cli-usage) - Complete CLI documentation
|
425
|
+
* [GitHub Actions integration](/en/docs/claude-code/github-actions) - Automate your GitHub workflow with Claude
|
426
|
+
* [Tutorials](/en/docs/claude-code/tutorials) - Step-by-step guides for common use cases
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: claude_swarm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paulo Arruda
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-06-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: thor
|
@@ -67,7 +67,11 @@ files:
|
|
67
67
|
- lib/claude_swarm/configuration.rb
|
68
68
|
- lib/claude_swarm/mcp_generator.rb
|
69
69
|
- lib/claude_swarm/orchestrator.rb
|
70
|
+
- lib/claude_swarm/reset_session_tool.rb
|
71
|
+
- lib/claude_swarm/session_info_tool.rb
|
72
|
+
- lib/claude_swarm/task_tool.rb
|
70
73
|
- lib/claude_swarm/version.rb
|
74
|
+
- sdk-docs.md
|
71
75
|
homepage: https://github.com/parruda/claude-swarm
|
72
76
|
licenses: []
|
73
77
|
metadata:
|