claude_swarm 0.1.5 → 0.1.7

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.
@@ -41,6 +41,7 @@ module ClaudeSwarm
41
41
  puts " Directory: #{main_instance[:directory]}"
42
42
  puts " Tools: #{main_instance[:tools].join(", ")}" if main_instance[:tools].any?
43
43
  puts " Connections: #{main_instance[:connections].join(", ")}" if main_instance[:connections].any?
44
+ puts " 😎 Vibe mode ON for this instance" if main_instance[:vibe]
44
45
  puts
45
46
  end
46
47
 
@@ -65,12 +66,15 @@ module ClaudeSwarm
65
66
  instance[:model]
66
67
  ]
67
68
 
68
- if @vibe
69
+ if @vibe || instance[:vibe]
69
70
  parts << "--dangerously-skip-permissions"
70
71
  elsif instance[:tools].any?
71
72
  tools_str = instance[:tools].join(",")
72
73
  parts << "--allowedTools"
73
74
  parts << tools_str
75
+ # Add permission prompt tool
76
+ parts << "--permission-prompt-tool"
77
+ parts << "mcp__permissions__check_permission"
74
78
  end
75
79
 
76
80
  if instance[:prompt]
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fast_mcp"
5
+ require "logger"
6
+ require "fileutils"
7
+ require_relative "permission_tool"
8
+
9
+ module ClaudeSwarm
10
+ class PermissionMcpServer
11
+ SWARM_DIR = ".claude-swarm"
12
+ SESSIONS_DIR = "sessions"
13
+
14
+ def initialize(allowed_tools: nil)
15
+ @allowed_tools = allowed_tools
16
+ setup_logging
17
+ end
18
+
19
+ def start
20
+ # Parse allowed tools
21
+ allowed_patterns = parse_allowed_tools(@allowed_tools)
22
+
23
+ @logger.info("Starting permission MCP server with allowed patterns: #{allowed_patterns.inspect}")
24
+
25
+ # Set the patterns on the tool class
26
+ PermissionTool.allowed_patterns = allowed_patterns
27
+ PermissionTool.logger = @logger
28
+
29
+ server = FastMcp::Server.new(
30
+ name: "claude-swarm-permissions",
31
+ version: "1.0.0"
32
+ )
33
+
34
+ # Register the tool class
35
+ server.register_tool(PermissionTool)
36
+
37
+ @logger.info("Permission MCP server started successfully")
38
+
39
+ # Start the stdio server
40
+ server.start
41
+ end
42
+
43
+ private
44
+
45
+ def setup_logging
46
+ # Use environment variable for session timestamp if available
47
+ # Otherwise create a new timestamp
48
+ session_timestamp = ENV["CLAUDE_SWARM_SESSION_TIMESTAMP"] || Time.now.strftime("%Y%m%d_%H%M%S")
49
+
50
+ # Ensure the session directory exists
51
+ session_dir = File.join(Dir.pwd, SWARM_DIR, SESSIONS_DIR, session_timestamp)
52
+ FileUtils.mkdir_p(session_dir)
53
+
54
+ # Create logger with permissions.log filename
55
+ log_path = File.join(session_dir, "permissions.log")
56
+ @logger = Logger.new(log_path)
57
+ @logger.level = Logger::DEBUG
58
+
59
+ # Custom formatter for better readability
60
+ @logger.formatter = proc do |severity, datetime, _progname, msg|
61
+ "[#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")}] [#{severity}] #{msg}\n"
62
+ end
63
+
64
+ @logger.info("Permission MCP server logging initialized")
65
+ end
66
+
67
+ def parse_allowed_tools(tools)
68
+ return [] if tools.nil? || tools.empty?
69
+
70
+ # Handle both string and array inputs
71
+ tool_list = tools.is_a?(Array) ? tools : tools.split(/[,\s]+/)
72
+
73
+ # Clean up and return
74
+ tool_list.map(&:strip).reject(&:empty?)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fast_mcp"
5
+
6
+ module ClaudeSwarm
7
+ class PermissionTool < FastMcp::Tool
8
+ # Class variables to store allowed patterns and logger
9
+ class << self
10
+ attr_accessor :allowed_patterns, :logger
11
+ end
12
+
13
+ tool_name "check_permission"
14
+ description "Check if a tool is allowed to be used based on configured patterns"
15
+
16
+ arguments do
17
+ required(:tool_name).filled(:string).description("The tool requesting permission")
18
+ required(:input).value(:hash).description("The input for the tool")
19
+ end
20
+
21
+ def call(tool_name:, input:)
22
+ logger = self.class.logger
23
+ logger.info("Permission check requested for tool: #{tool_name}")
24
+ logger.info("Tool input: #{input.inspect}")
25
+
26
+ # Check if the tool matches any allowed pattern
27
+ patterns = self.class.allowed_patterns || []
28
+ logger.info("Checking against patterns: #{patterns.inspect}")
29
+
30
+ allowed = patterns.any? do |pattern|
31
+ match = if pattern.include?("*")
32
+ # Convert wildcard pattern to regex
33
+ regex_pattern = pattern.gsub("*", ".*")
34
+ tool_name.match?(/^#{regex_pattern}$/)
35
+ else
36
+ # Exact match
37
+ tool_name == pattern
38
+ end
39
+ logger.info("Pattern '#{pattern}' vs '#{tool_name}': #{match}")
40
+ match
41
+ end
42
+
43
+ result = if allowed
44
+ logger.info("ALLOWED: Tool '#{tool_name}' matches configured patterns")
45
+ {
46
+ "behavior" => "allow",
47
+ "updatedInput" => input
48
+ }
49
+ else
50
+ logger.info("DENIED: Tool '#{tool_name}' does not match any configured patterns")
51
+ {
52
+ "behavior" => "deny",
53
+ "message" => "Tool '#{tool_name}' is not allowed by configured patterns"
54
+ }
55
+ end
56
+
57
+ # Return JSON-stringified result as per SDK docs
58
+ response = JSON.generate(result)
59
+ logger.info("Returning response: #{response}")
60
+ response
61
+ end
62
+ end
63
+ 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeSwarm
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
data/lib/claude_swarm.rb CHANGED
@@ -4,6 +4,8 @@ require_relative "claude_swarm/version"
4
4
  require_relative "claude_swarm/cli"
5
5
  require_relative "claude_swarm/claude_code_executor"
6
6
  require_relative "claude_swarm/claude_mcp_server"
7
+ require_relative "claude_swarm/permission_tool"
8
+ require_relative "claude_swarm/permission_mcp_server"
7
9
 
8
10
  module ClaudeSwarm
9
11
  class Error < StandardError; end
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