claude_agent 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 791bfc30df3cce213645d97676501c53e0acd5cbcedeacadbd61b810469c2be5
4
- data.tar.gz: 5cdf1984dd821ce465165e6887dcb430989669692924d747e4a23d49f7aae0ad
3
+ metadata.gz: 0df3ed3f8ade7108ed89ab51e5f42ad2f0d358bfa99a63a88919a39899570e89
4
+ data.tar.gz: 19ad8e7da48f2ba038deec0b1dc31737009a8cfe8b079da53b34348f55b6fe7b
5
5
  SHA512:
6
- metadata.gz: 6824f825982dc3066a6512f9d2d8a84253f6b861916b76917792ab9bf5a7f52a026105de09ab357e0a99a9cd289a77f6f7574c3e71569d1f8d2bcfa6fb31997d
7
- data.tar.gz: df13b541959f5962c385b5295508b89f03471c2617e0b787747e130cddae9d2d74b512d3c2a63a9d959290d10c2d3f676241dec9f4ffc4a51caea12717e7eacf
6
+ metadata.gz: 39138c727a4bf8786302225d9cf1b7415117f9077fb494f6d0afb0c5b6f5aff5121a28696e435cfb321660b6e1ea7fb68f734fb673aca562b9f1fada84229784
7
+ data.tar.gz: aabad329d3a406695b9cd0fecc8a774464b23f7794aaa995b60f8755832759145d4a8e7c620939f39d1d3127dcf5a31042350ea473ef1bddfc8a0fcf2942646b
data/CHANGELOG.md CHANGED
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] - 2026-01-18
11
+
12
+ ### Added
13
+ - `TaskNotificationMessage` for background task completion notifications
14
+ - `Setup` hook event with `SetupInput` for init/maintenance triggers
15
+ - `skills` and `max_turns` fields in `AgentDefinition` (TypeScript SDK v0.2.12 parity)
16
+ - `init`, `init_only`, `maintenance` options for running Setup hooks
17
+ - `ClaudeAgent.run_setup` convenience method for CI/CD pipelines
18
+ - Hook-specific output fields documentation (`additionalContext`, `permissionDecision`, `updatedMCPToolOutput`, etc.)
19
+ - Document `settings` option accepts JSON strings (for plansDirectory, etc.)
20
+
21
+ ## [0.3.0] - 2026-01-16
22
+
23
+ ### Added
24
+ - `agent` option for specifying main thread agent name (TypeScript SDK v0.2.9 parity)
25
+ - `model` field in `SessionStartInput` hook input
26
+
10
27
  ## [0.2.0] - 2026-01-11
11
28
 
12
29
  ### Added
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ClaudeAgent
2
2
 
3
- A Ruby SDK for building AI-powered applications with [Claude Code](https://docs.anthropic.com/en/docs/claude-code). This library wraps the Claude Code CLI, providing both simple one-shot queries and interactive bidirectional sessions.
3
+ Ruby gem for building AI-powered applications with the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview). This library essentially wraps the Claude Code CLI, providing both simple one-shot queries and interactive bidirectional sessions.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -64,6 +64,26 @@ ClaudeAgent::Client.open do |client|
64
64
  end
65
65
  ```
66
66
 
67
+ ### Run Setup Hooks
68
+
69
+ Run Setup hooks without starting a conversation (useful for CI/CD pipelines):
70
+
71
+ ```ruby
72
+ require "claude_agent"
73
+
74
+ # Run init Setup hooks (default)
75
+ messages = ClaudeAgent.run_setup
76
+ result = messages.last
77
+ puts "Setup completed" if result.success?
78
+
79
+ # Run init Setup hooks with custom options
80
+ options = ClaudeAgent::Options.new(cwd: "/my/project")
81
+ ClaudeAgent.run_setup(trigger: :init, options: options)
82
+
83
+ # Run maintenance Setup hooks
84
+ ClaudeAgent.run_setup(trigger: :maintenance)
85
+ ```
86
+
67
87
  ## Configuration
68
88
 
69
89
  Use `ClaudeAgent::Options` to customize behavior:
@@ -95,6 +115,9 @@ options = ClaudeAgent::Options.new(
95
115
  cwd: "/path/to/project",
96
116
  add_dirs: ["/additional/path"],
97
117
 
118
+ # Agent configuration
119
+ agent: "my-agent", # Agent name for main thread
120
+
98
121
  # Session management
99
122
  resume: "session-id",
100
123
  continue_conversation: true,
@@ -158,7 +181,9 @@ agents = {
158
181
  description: "Runs tests and reports results",
159
182
  prompt: "You are a test runner. Execute tests and report failures clearly.",
160
183
  tools: ["Read", "Bash"],
161
- model: "haiku"
184
+ model: "haiku",
185
+ max_turns: 5, # Max agentic turns before stopping
186
+ skills: ["testing", "debug"] # Skills to preload into agent context
162
187
  )
163
188
  }
164
189
 
@@ -274,6 +299,20 @@ auth.output # Auth output messages
274
299
  auth.error # Error message (if any)
275
300
  ```
276
301
 
302
+ ### TaskNotificationMessage
303
+
304
+ Background task completion notifications:
305
+
306
+ ```ruby
307
+ notification.task_id # Background task ID
308
+ notification.status # "completed", "failed", or "stopped"
309
+ notification.output_file # Path to task output file
310
+ notification.summary # Task summary
311
+ notification.completed? # Convenience predicate
312
+ notification.failed? # Convenience predicate
313
+ notification.stopped? # Convenience predicate
314
+ ```
315
+
277
316
  ## Content Blocks
278
317
 
279
318
  Assistant messages contain content blocks:
@@ -446,6 +485,7 @@ All available hook events:
446
485
  - `SubagentStop` - When subagent stops
447
486
  - `PreCompact` - Before conversation compaction
448
487
  - `PermissionRequest` - When permission is requested
488
+ - `Setup` - Initial setup or maintenance (trigger: "init" or "maintenance")
449
489
 
450
490
  ### Hook Input Types
451
491
 
@@ -456,13 +496,14 @@ All available hook events:
456
496
  | PostToolUseFailure | `PostToolUseFailureInput` | tool_name, tool_input, error, tool_use_id, is_interrupt |
457
497
  | Notification | `NotificationInput` | message, title, notification_type |
458
498
  | UserPromptSubmit | `UserPromptSubmitInput` | prompt |
459
- | SessionStart | `SessionStartInput` | source, agent_type |
499
+ | SessionStart | `SessionStartInput` | source, agent_type, model |
460
500
  | SessionEnd | `SessionEndInput` | reason |
461
501
  | Stop | `StopInput` | stop_hook_active |
462
502
  | SubagentStart | `SubagentStartInput` | agent_id, agent_type |
463
503
  | SubagentStop | `SubagentStopInput` | stop_hook_active, agent_id, agent_transcript_path |
464
504
  | PreCompact | `PreCompactInput` | trigger, custom_instructions |
465
505
  | PermissionRequest | `PermissionRequestInput` | tool_name, tool_input, permission_suggestions |
506
+ | Setup | `SetupInput` | trigger (init/maintenance) |
466
507
 
467
508
  All hook inputs inherit from `BaseHookInput` with: `hook_event_name`, `session_id`, `transcript_path`, `cwd`, `permission_mode`.
468
509
 
@@ -591,6 +632,88 @@ puts client.account_info.email
591
632
  client.disconnect
592
633
  ```
593
634
 
635
+ ## V2 Session API (Unstable)
636
+
637
+ > **⚠️ Alpha API**: This API is unstable and may change without notice.
638
+
639
+ The V2 Session API provides a simpler interface for multi-turn conversations, matching the TypeScript SDK's `SDKSession` interface.
640
+
641
+ ### Create a Session
642
+
643
+ ```ruby
644
+ # Create a new session
645
+ session = ClaudeAgent.unstable_v2_create_session(
646
+ model: "claude-sonnet-4-5-20250514",
647
+ permission_mode: "acceptEdits"
648
+ )
649
+
650
+ # Send a message
651
+ session.send("Hello, Claude!")
652
+
653
+ # Stream responses
654
+ session.stream.each do |msg|
655
+ case msg
656
+ when ClaudeAgent::AssistantMessage
657
+ puts msg.text
658
+ when ClaudeAgent::ResultMessage
659
+ puts "Done! Cost: $#{msg.total_cost_usd}"
660
+ end
661
+ end
662
+
663
+ # Continue the conversation
664
+ session.send("Tell me more")
665
+ session.stream.each { |msg| puts msg.text if msg.is_a?(ClaudeAgent::AssistantMessage) }
666
+
667
+ # Close when done
668
+ session.close
669
+ ```
670
+
671
+ ### Resume a Session
672
+
673
+ ```ruby
674
+ # Resume an existing session by ID
675
+ session = ClaudeAgent.unstable_v2_resume_session(
676
+ "session-abc123",
677
+ model: "claude-sonnet-4-5-20250514"
678
+ )
679
+
680
+ session.send("What were we discussing?")
681
+ session.stream.each { |msg| puts msg.text if msg.is_a?(ClaudeAgent::AssistantMessage) }
682
+ session.close
683
+ ```
684
+
685
+ ### One-Shot Prompt
686
+
687
+ ```ruby
688
+ # Simple one-shot prompt (auto-closes session)
689
+ result = ClaudeAgent.unstable_v2_prompt(
690
+ "What is 2 + 2?",
691
+ model: "claude-sonnet-4-5-20250514"
692
+ )
693
+
694
+ puts "Success: #{result.success?}"
695
+ puts "Cost: $#{result.total_cost_usd}"
696
+ ```
697
+
698
+ ### SessionOptions
699
+
700
+ The V2 API uses a simplified options type:
701
+
702
+ ```ruby
703
+ options = ClaudeAgent::SessionOptions.new(
704
+ model: "claude-sonnet-4-5-20250514", # Required
705
+ permission_mode: "acceptEdits", # Optional
706
+ allowed_tools: ["Read", "Grep"], # Optional
707
+ disallowed_tools: ["Write"], # Optional
708
+ can_use_tool: ->(name, input, ctx) { ... }, # Optional
709
+ hooks: { "PreToolUse" => [...] }, # Optional
710
+ env: { "MY_VAR" => "value" }, # Optional
711
+ path_to_claude_code_executable: "/custom/path" # Optional
712
+ )
713
+
714
+ session = ClaudeAgent.unstable_v2_create_session(options)
715
+ ```
716
+
594
717
  ## Types Reference
595
718
 
596
719
  ### Return Types
data/SPEC.md CHANGED
@@ -3,8 +3,8 @@
3
3
  This document provides a comprehensive specification of the Claude Agent SDK, comparing feature parity across the official TypeScript and Python SDKs with this Ruby implementation.
4
4
 
5
5
  **Reference Versions:**
6
- - TypeScript SDK: v0.2.5 (npm package)
7
- - Python SDK: Latest from GitHub (commit 3b7e3ba)
6
+ - TypeScript SDK: v0.2.12 (npm package)
7
+ - Python SDK: v0.1.20 from GitHub (commit 05d2eb4)
8
8
  - Ruby SDK: This repository
9
9
 
10
10
  ---
@@ -30,49 +30,54 @@ This document provides a comprehensive specification of the Claude Agent SDK, co
30
30
 
31
31
  Configuration options for SDK queries and clients.
32
32
 
33
- | Option | TypeScript | Python | Ruby | Notes |
34
- |-----------------------------------|:----------:|:------:|:----:|-------------------------------------------------------------|
35
- | `model` | ✅ | ✅ | ✅ | Claude model identifier |
36
- | `fallbackModel` | ✅ | ✅ | ✅ | Fallback if primary fails |
37
- | `systemPrompt` | ✅ | ✅ | ✅ | String or preset object |
38
- | `appendSystemPrompt` | ✅ | ❌ | ✅ | Append to system prompt (TS SDK has via preset) |
39
- | `tools` | ✅ | ✅ | ✅ | Array or preset |
40
- | `allowedTools` | ✅ | ✅ | ✅ | Auto-allowed tools |
41
- | `disallowedTools` | ✅ | ✅ | ✅ | Blocked tools |
42
- | `permissionMode` | ✅ | ✅ | ✅ | default/acceptEdits/plan/bypassPermissions/delegate/dontAsk |
43
- | `allowDangerouslySkipPermissions` | ✅ | ❌ | ✅ | Required for bypassPermissions |
44
- | `canUseTool` | ✅ | ✅ | ✅ | Permission callback |
45
- | `permissionPromptToolName` | ✅ | ✅ | ✅ | MCP tool for permission prompts |
46
- | `maxTurns` | ✅ | ✅ | ✅ | Max conversation turns |
47
- | `maxBudgetUsd` | ✅ | ✅ | ✅ | Max USD budget |
48
- | `maxThinkingTokens` | ✅ | ✅ | ✅ | Max thinking tokens |
49
- | `continue` | ✅ | ✅ | ✅ | Continue most recent conversation |
50
- | `resume` | ✅ | ✅ | ✅ | Resume session by ID |
51
- | `resumeSessionAt` | ✅ | ❌ | ✅ | Resume to specific message UUID |
52
- | `forkSession` | ✅ | ✅ | ✅ | Fork on resume |
53
- | `persistSession` | ✅ | ❌ | ✅ | Whether to persist to disk |
54
- | `enableFileCheckpointing` | ✅ | ✅ | ✅ | Track file changes for rewind |
55
- | `includePartialMessages` | ✅ | ✅ | ✅ | Include stream events |
56
- | `outputFormat` | ✅ | ✅ | ✅ | JSON schema for structured output |
57
- | `mcpServers` | ✅ | ✅ | ✅ | MCP server configurations |
58
- | `strictMcpConfig` | ✅ | ❌ | ✅ | Strict validation of MCP config |
59
- | `hooks` | ✅ | ✅ | ✅ | Hook callbacks |
60
- | `agents` | ✅ | ✅ | ✅ | Custom subagent definitions |
61
- | `cwd` | ✅ | ✅ | ✅ | Working directory |
62
- | `additionalDirectories` | ✅ | ✅ | ✅ | Extra allowed directories |
63
- | `env` | ✅ | ✅ | ✅ | Environment variables |
64
- | `sandbox` | ✅ | ✅ | ✅ | Sandbox settings |
65
- | `settingSources` | ✅ | | ✅ | Which settings to load |
66
- | `plugins` | ✅ | ✅ | ✅ | Plugin configurations |
67
- | `betas` | ✅ | ✅ | ✅ | Beta features (e.g., context-1m-2025-08-07) |
68
- | `abortController` | ✅ | | ✅ | Cancellation controller |
69
- | `stderr` | ✅ | | ✅ | Stderr callback |
70
- | `spawnClaudeCodeProcess` | ✅ | ❌ | ✅ | Custom spawn function |
71
- | `pathToClaudeCodeExecutable` | ✅ | ✅ | ✅ | Custom CLI path |
72
- | `executable` | ✅ | ❌ | | JS runtime (node/bun/deno) |
73
- | `executableArgs` | ✅ | | | JS runtime args |
74
- | `extraArgs` | ✅ | | | Extra CLI arguments |
75
- | `user` | | | | User identifier |
33
+ | Option | TypeScript | Python | Ruby | Notes |
34
+ |-----------------------------------|:----------:|:------:|:----:|--------------------------------------------------------------|
35
+ | `model` | ✅ | ✅ | ✅ | Claude model identifier |
36
+ | `fallbackModel` | ✅ | ✅ | ✅ | Fallback if primary fails |
37
+ | `systemPrompt` | ✅ | ✅ | ✅ | String or preset object |
38
+ | `appendSystemPrompt` | ✅ | ❌ | ✅ | Append to system prompt (TS SDK has via preset) |
39
+ | `tools` | ✅ | ✅ | ✅ | Array or preset |
40
+ | `allowedTools` | ✅ | ✅ | ✅ | Auto-allowed tools |
41
+ | `disallowedTools` | ✅ | ✅ | ✅ | Blocked tools |
42
+ | `permissionMode` | ✅ | ✅ | ✅ | default/acceptEdits/plan/bypassPermissions/delegate/dontAsk |
43
+ | `allowDangerouslySkipPermissions` | ✅ | ❌ | ✅ | Required for bypassPermissions |
44
+ | `canUseTool` | ✅ | ✅ | ✅ | Permission callback |
45
+ | `permissionPromptToolName` | ✅ | ✅ | ✅ | MCP tool for permission prompts |
46
+ | `maxTurns` | ✅ | ✅ | ✅ | Max conversation turns |
47
+ | `maxBudgetUsd` | ✅ | ✅ | ✅ | Max USD budget |
48
+ | `maxThinkingTokens` | ✅ | ✅ | ✅ | Max thinking tokens |
49
+ | `continue` | ✅ | ✅ | ✅ | Continue most recent conversation |
50
+ | `resume` | ✅ | ✅ | ✅ | Resume session by ID |
51
+ | `resumeSessionAt` | ✅ | ❌ | ✅ | Resume to specific message UUID |
52
+ | `forkSession` | ✅ | ✅ | ✅ | Fork on resume |
53
+ | `persistSession` | ✅ | ❌ | ✅ | Whether to persist to disk |
54
+ | `enableFileCheckpointing` | ✅ | ✅ | ✅ | Track file changes for rewind |
55
+ | `includePartialMessages` | ✅ | ✅ | ✅ | Include stream events |
56
+ | `outputFormat` | ✅ | ✅ | ✅ | JSON schema for structured output |
57
+ | `mcpServers` | ✅ | ✅ | ✅ | MCP server configurations |
58
+ | `strictMcpConfig` | ✅ | ❌ | ✅ | Strict validation of MCP config |
59
+ | `hooks` | ✅ | ✅ | ✅ | Hook callbacks |
60
+ | `agents` | ✅ | ✅ | ✅ | Custom subagent definitions |
61
+ | `cwd` | ✅ | ✅ | ✅ | Working directory |
62
+ | `additionalDirectories` | ✅ | ✅ | ✅ | Extra allowed directories |
63
+ | `env` | ✅ | ✅ | ✅ | Environment variables |
64
+ | `sandbox` | ✅ | ✅ | ✅ | Sandbox settings |
65
+ | `settings` | ✅ | | ✅ | Settings file path or JSON string (e.g., plansDirectory) |
66
+ | `settingSources` | ✅ | ✅ | ✅ | Which settings to load |
67
+ | `plugins` | ✅ | ✅ | ✅ | Plugin configurations |
68
+ | `betas` | ✅ | | ✅ | Beta features (e.g., context-1m-2025-08-07) |
69
+ | `agent` | ✅ | | ✅ | Agent name for main thread |
70
+ | `abortController` | ✅ | ❌ | ✅ | Cancellation controller |
71
+ | `stderr` | ✅ | ✅ | ✅ | Stderr callback |
72
+ | `spawnClaudeCodeProcess` | ✅ | ❌ | | Custom spawn function |
73
+ | `pathToClaudeCodeExecutable` | ✅ | | | Custom CLI path |
74
+ | `executable` | ✅ | N/A | N/A | JS runtime (node/bun/deno) - JS-specific |
75
+ | `executableArgs` | | N/A | N/A | JS runtime args - JS-specific |
76
+ | `extraArgs` | ✅ | ✅ | ✅ | Extra CLI arguments |
77
+ | `user` | ✅ | ✅ | ✅ | User identifier (V2 Session API) |
78
+ | `init` | ✅ | ❌ | ✅ | Run Setup hooks (init trigger), then continue (hidden CLI) |
79
+ | `initOnly` | ✅ | ❌ | ✅ | Run Setup hooks (init trigger), then exit (hidden CLI) |
80
+ | `maintenance` | ✅ | ❌ | ✅ | Run Setup hooks (maintenance trigger), continue (hidden CLI) |
76
81
 
77
82
  ---
78
83
 
@@ -93,6 +98,7 @@ Messages exchanged between SDK and CLI.
93
98
  | `ToolProgressMessage` | ✅ | ❌ | ✅ | Long-running tool progress |
94
99
  | `HookResponseMessage` | ✅ | ❌ | ✅ | Hook execution output |
95
100
  | `AuthStatusMessage` | ✅ | ❌ | ✅ | Authentication status |
101
+ | `TaskNotificationMessage`| ✅ | ❌ | ✅ | Background task completion |
96
102
 
97
103
  ### Message Fields
98
104
 
@@ -202,20 +208,21 @@ Event hooks for intercepting and modifying SDK behavior.
202
208
 
203
209
  ### Hook Events
204
210
 
205
- | Event | TypeScript | Python | Ruby | Notes |
206
- |----------------------|:----------:|:------:|:----:|------------------------|
207
- | `PreToolUse` | ✅ | ✅ | ✅ | Before tool execution |
208
- | `PostToolUse` | ✅ | ✅ | ✅ | After tool execution |
209
- | `PostToolUseFailure` | ✅ | ❌ | ✅ | After tool failure |
210
- | `Notification` | ✅ | ❌ | ✅ | System notifications |
211
- | `UserPromptSubmit` | ✅ | ✅ | ✅ | User message submitted |
212
- | `SessionStart` | ✅ | ❌ | ✅ | Session starts |
213
- | `SessionEnd` | ✅ | ❌ | ✅ | Session ends |
214
- | `Stop` | ✅ | ✅ | ✅ | Agent stops |
215
- | `SubagentStart` | ✅ | ❌ | ✅ | Subagent starts |
216
- | `SubagentStop` | ✅ | ✅ | ✅ | Subagent stops |
217
- | `PreCompact` | ✅ | ✅ | ✅ | Before compaction |
218
- | `PermissionRequest` | ✅ | ❌ | ✅ | Permission requested |
211
+ | Event | TypeScript | Python | Ruby | Notes |
212
+ |----------------------|:----------:|:------:|:----:|---------------------------|
213
+ | `PreToolUse` | ✅ | ✅ | ✅ | Before tool execution |
214
+ | `PostToolUse` | ✅ | ✅ | ✅ | After tool execution |
215
+ | `PostToolUseFailure` | ✅ | ❌ | ✅ | After tool failure |
216
+ | `Notification` | ✅ | ❌ | ✅ | System notifications |
217
+ | `UserPromptSubmit` | ✅ | ✅ | ✅ | User message submitted |
218
+ | `SessionStart` | ✅ | ❌ | ✅ | Session starts |
219
+ | `SessionEnd` | ✅ | ❌ | ✅ | Session ends |
220
+ | `Stop` | ✅ | ✅ | ✅ | Agent stops |
221
+ | `SubagentStart` | ✅ | ❌ | ✅ | Subagent starts |
222
+ | `SubagentStop` | ✅ | ✅ | ✅ | Subagent stops |
223
+ | `PreCompact` | ✅ | ✅ | ✅ | Before compaction |
224
+ | `PermissionRequest` | ✅ | ❌ | ✅ | Permission requested |
225
+ | `Setup` | ✅ | ❌ | ✅ | Initial setup/maintenance |
219
226
 
220
227
  ### Hook Input Types
221
228
 
@@ -233,6 +240,7 @@ Event hooks for intercepting and modifying SDK behavior.
233
240
  | `SubagentStopHookInput` | ✅ | ✅ | ✅ |
234
241
  | `PreCompactHookInput` | ✅ | ✅ | ✅ |
235
242
  | `PermissionRequestHookInput` | ✅ | ❌ | ✅ |
243
+ | `SetupHookInput` | ✅ | ❌ | ✅ |
236
244
 
237
245
  ### Hook Output Types
238
246
 
@@ -248,6 +256,62 @@ Event hooks for intercepting and modifying SDK behavior.
248
256
  | `reason` | ✅ | ✅ | ✅ | Reason feedback |
249
257
  | `hookSpecificOutput` | ✅ | ✅ | ✅ | Event-specific output |
250
258
 
259
+ ### Hook-Specific Output Fields
260
+
261
+ Event-specific fields returned via `hookSpecificOutput`:
262
+
263
+ #### PreToolUseHookSpecificOutput
264
+
265
+ | Field | TypeScript | Python | Ruby | Notes |
266
+ |----------------------------|:----------:|:------:|:----:|------------------------------------|
267
+ | `permissionDecision` | ✅ | ❌ | ✅ | `allow`, `deny`, or `ask` |
268
+ | `permissionDecisionReason` | ✅ | ❌ | ✅ | Reason for permission decision |
269
+ | `updatedInput` | ✅ | ✅ | ✅ | Modified tool input |
270
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
271
+
272
+ #### PostToolUseHookSpecificOutput
273
+
274
+ | Field | TypeScript | Python | Ruby | Notes |
275
+ |------------------------|:----------:|:------:|:----:|----------------------------------|
276
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
277
+ | `updatedMCPToolOutput` | ✅ | ❌ | ✅ | Modified MCP tool output |
278
+
279
+ #### PostToolUseFailureHookSpecificOutput
280
+
281
+ | Field | TypeScript | Python | Ruby | Notes |
282
+ |---------------------|:----------:|:------:|:----:|----------------------------------|
283
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
284
+
285
+ #### SessionStartHookSpecificOutput
286
+
287
+ | Field | TypeScript | Python | Ruby | Notes |
288
+ |---------------------|:----------:|:------:|:----:|----------------------------------|
289
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
290
+
291
+ #### SetupHookSpecificOutput
292
+
293
+ | Field | TypeScript | Python | Ruby | Notes |
294
+ |---------------------|:----------:|:------:|:----:|----------------------------------|
295
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
296
+
297
+ #### SubagentStartHookSpecificOutput
298
+
299
+ | Field | TypeScript | Python | Ruby | Notes |
300
+ |---------------------|:----------:|:------:|:----:|----------------------------------|
301
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
302
+
303
+ #### UserPromptSubmitHookSpecificOutput
304
+
305
+ | Field | TypeScript | Python | Ruby | Notes |
306
+ |---------------------|:----------:|:------:|:----:|----------------------------------|
307
+ | `additionalContext` | ✅ | ❌ | ✅ | Context string returned to model |
308
+
309
+ #### PermissionRequestHookSpecificOutput
310
+
311
+ | Field | TypeScript | Python | Ruby | Notes |
312
+ |------------|:----------:|:------:|:----:|------------------------------------------|
313
+ | `decision` | ✅ | ❌ | ✅ | `{ behavior: 'allow'/'deny', ... }` obj |
314
+
251
315
  ### Hook Matcher
252
316
 
253
317
  | Field | TypeScript | Python | Ruby |
@@ -414,6 +478,8 @@ Custom subagent definitions.
414
478
  | `model` | ✅ | ✅ | ✅ | Model override (sonnet/opus/haiku/inherit) |
415
479
  | `mcpServers` | ✅ | ❌ | ✅ | Agent-specific MCP servers |
416
480
  | `criticalSystemReminder_EXPERIMENTAL` | ✅ | ❌ | ✅ | Critical reminder (experimental) |
481
+ | `skills` | ✅ | ❌ | ✅ | Skills to preload into agent context |
482
+ | `maxTurns` | ✅ | ❌ | ✅ | Max agentic turns before stopping |
417
483
 
418
484
  ---
419
485
 
@@ -531,6 +597,7 @@ Public API surface for SDK clients.
531
597
 
532
598
  - ✅ = Fully implemented
533
599
  - ❌ = Not implemented
600
+ - N/A = Not applicable (language-specific feature)
534
601
  - Partial = Partially implemented
535
602
 
536
603
  ---
@@ -541,21 +608,27 @@ Public API surface for SDK clients.
541
608
  - Primary reference for API surface (most comprehensive)
542
609
  - Source is bundled/minified, but `sdk.d.ts` provides complete type definitions
543
610
  - Includes unstable V2 session API
544
- - Version 0.2.5 includes `maxOutputTokens` field in `ModelUsage`
545
611
  - Adds `deno` as supported executable option
546
612
  - Includes experimental `criticalSystemReminder_EXPERIMENTAL` for agent definitions
613
+ - `SessionStartHookInput` includes `model` field
614
+ - v0.2.12 adds `Setup` hook event for init/maintenance
615
+ - v0.2.12 adds `skills` and `maxTurns` to AgentDefinition
616
+ - v0.2.12 adds `TaskNotificationMessage` for background task completion
617
+ - v0.2.12 adds `user` option to SDKSessionOptions
547
618
 
548
619
  ### Python SDK
549
- - Full source available
620
+ - Full source available (v0.1.20)
550
621
  - Fewer control protocol features than TypeScript
551
622
  - Does not support SessionStart/SessionEnd/Notification hooks due to setup limitations
552
623
  - Missing several permission modes (delegate, dontAsk)
553
624
  - `excludedCommands` in sandbox now supported
625
+ - `tool_use_id` now included in PreToolUseHookInput
554
626
 
555
627
  ### Ruby SDK (This Repository)
556
- - Aims for TypeScript SDK parity
628
+ - Full TypeScript SDK feature parity achieved
557
629
  - Ruby-idiomatic patterns (Data.define, snake_case)
558
630
  - Complete control protocol support
559
631
  - Dedicated Client class for multi-turn conversations
560
- - Full hook event support including all 12 events
632
+ - Full hook event support including all 13 events
561
633
  - Full V2 Session API support (unstable)
634
+ - `executable`/`executableArgs` marked N/A (JS runtime options not applicable to Ruby)
@@ -15,6 +15,7 @@ module ClaudeAgent
15
15
  SubagentStop
16
16
  PreCompact
17
17
  PermissionRequest
18
+ Setup
18
19
  ].freeze
19
20
 
20
21
  # Matcher configuration for hooks
@@ -141,14 +142,16 @@ module ClaudeAgent
141
142
  # Input for SessionStart hook (TypeScript SDK parity)
142
143
  #
143
144
  class SessionStartInput < BaseHookInput
144
- attr_reader :source, :agent_type
145
+ attr_reader :source, :agent_type, :model
145
146
 
146
147
  # @param source [String] One of: "startup", "resume", "clear", "compact"
147
148
  # @param agent_type [String, nil] Type of agent if running in subagent context
148
- def initialize(source:, agent_type: nil, **kwargs)
149
+ # @param model [String, nil] Model being used for this session
150
+ def initialize(source:, agent_type: nil, model: nil, **kwargs)
149
151
  super(hook_event_name: "SessionStart", **kwargs)
150
152
  @source = source
151
153
  @agent_type = agent_type
154
+ @model = model
152
155
  end
153
156
  end
154
157
 
@@ -225,4 +228,35 @@ module ClaudeAgent
225
228
  @permission_suggestions = permission_suggestions
226
229
  end
227
230
  end
231
+
232
+ # Input for Setup hook (TypeScript SDK parity)
233
+ #
234
+ # Triggered during initial setup or maintenance operations.
235
+ #
236
+ # @example
237
+ # input = SetupInput.new(trigger: "init", session_id: "abc-123")
238
+ # input.trigger # => "init"
239
+ # input.init? # => true
240
+ #
241
+ class SetupInput < BaseHookInput
242
+ attr_reader :trigger
243
+
244
+ # @param trigger [String] One of: "init", "maintenance"
245
+ def initialize(trigger:, **kwargs)
246
+ super(hook_event_name: "Setup", **kwargs)
247
+ @trigger = trigger
248
+ end
249
+
250
+ # Check if this is an init trigger
251
+ # @return [Boolean]
252
+ def init?
253
+ trigger == "init"
254
+ end
255
+
256
+ # Check if this is a maintenance trigger
257
+ # @return [Boolean]
258
+ def maintenance?
259
+ trigger == "maintenance"
260
+ end
261
+ end
228
262
  end
@@ -11,7 +11,7 @@ module ClaudeAgent
11
11
  # Parse a raw message hash into a typed message object
12
12
  #
13
13
  # @param raw [Hash] Raw message from CLI
14
- # @return [UserMessage, UserMessageReplay, AssistantMessage, SystemMessage, ResultMessage, StreamEvent, CompactBoundaryMessage, StatusMessage, ToolProgressMessage, HookResponseMessage, AuthStatusMessage]
14
+ # @return [UserMessage, UserMessageReplay, AssistantMessage, SystemMessage, ResultMessage, StreamEvent, CompactBoundaryMessage, StatusMessage, ToolProgressMessage, HookResponseMessage, AuthStatusMessage, TaskNotificationMessage]
15
15
  # @raise [MessageParseError] If message cannot be parsed
16
16
  def parse(raw)
17
17
  type = raw["type"]
@@ -30,6 +30,8 @@ module ClaudeAgent
30
30
  parse_status_message(raw)
31
31
  when "hook_response"
32
32
  parse_hook_response_message(raw)
33
+ when "task_notification"
34
+ parse_task_notification_message(raw)
33
35
  else
34
36
  parse_system_message(raw)
35
37
  end
@@ -258,5 +260,16 @@ module ClaudeAgent
258
260
  error: raw["error"]
259
261
  )
260
262
  end
263
+
264
+ def parse_task_notification_message(raw)
265
+ TaskNotificationMessage.new(
266
+ uuid: raw["uuid"] || "",
267
+ session_id: fetch_dual(raw, :session_id, ""),
268
+ task_id: fetch_dual(raw, :task_id, ""),
269
+ status: raw["status"] || "unknown",
270
+ output_file: fetch_dual(raw, :output_file, ""),
271
+ summary: raw["summary"] || ""
272
+ )
273
+ end
261
274
  end
262
275
  end
@@ -404,6 +404,70 @@ module ClaudeAgent
404
404
  end
405
405
  end
406
406
 
407
+ # Task notification message (TypeScript SDK parity)
408
+ #
409
+ # Sent when a background task completes, fails, or is stopped.
410
+ # Used for tracking async task execution status.
411
+ #
412
+ # @example
413
+ # msg = TaskNotificationMessage.new(
414
+ # uuid: "msg-123",
415
+ # session_id: "session-abc",
416
+ # task_id: "task-456",
417
+ # status: "completed",
418
+ # output_file: "/path/to/output.txt",
419
+ # summary: "Task completed successfully"
420
+ # )
421
+ # msg.completed? # => true
422
+ # msg.failed? # => false
423
+ #
424
+ # Status values:
425
+ # - "completed" - Task finished successfully
426
+ # - "failed" - Task encountered an error
427
+ # - "stopped" - Task was manually stopped
428
+ #
429
+ TaskNotificationMessage = Data.define(
430
+ :uuid,
431
+ :session_id,
432
+ :task_id,
433
+ :status,
434
+ :output_file,
435
+ :summary
436
+ ) do
437
+ def initialize(
438
+ uuid:,
439
+ session_id:,
440
+ task_id:,
441
+ status:,
442
+ output_file:,
443
+ summary:
444
+ )
445
+ super
446
+ end
447
+
448
+ def type
449
+ :task_notification
450
+ end
451
+
452
+ # Check if task completed successfully
453
+ # @return [Boolean]
454
+ def completed?
455
+ status == "completed"
456
+ end
457
+
458
+ # Check if task failed
459
+ # @return [Boolean]
460
+ def failed?
461
+ status == "failed"
462
+ end
463
+
464
+ # Check if task was stopped
465
+ # @return [Boolean]
466
+ def stopped?
467
+ status == "stopped"
468
+ end
469
+ end
470
+
407
471
  # All message types
408
472
  MESSAGE_TYPES = [
409
473
  UserMessage,
@@ -416,6 +480,7 @@ module ClaudeAgent
416
480
  StatusMessage,
417
481
  ToolProgressMessage,
418
482
  HookResponseMessage,
419
- AuthStatusMessage
483
+ AuthStatusMessage,
484
+ TaskNotificationMessage
420
485
  ].freeze
421
486
  end
@@ -38,7 +38,10 @@ module ClaudeAgent
38
38
  include_partial_messages: false,
39
39
  enable_file_checkpointing: false,
40
40
  persist_session: true,
41
- betas: []
41
+ betas: [],
42
+ init: false,
43
+ init_only: false,
44
+ maintenance: false
42
45
  }.freeze
43
46
 
44
47
  # All configurable attributes
@@ -50,11 +53,12 @@ module ClaudeAgent
50
53
  continue_conversation resume fork_session resume_session_at
51
54
  max_turns max_budget_usd max_thinking_tokens
52
55
  strict_mcp_config mcp_servers hooks
53
- settings sandbox cwd add_dirs env user
56
+ settings sandbox cwd add_dirs env user agent
54
57
  cli_path extra_args agents setting_sources plugins
55
58
  include_partial_messages output_format enable_file_checkpointing
56
59
  persist_session betas max_buffer_size stderr_callback
57
60
  abort_controller spawn_claude_code_process
61
+ init init_only maintenance
58
62
  ].freeze
59
63
 
60
64
  attr_accessor(*ATTRIBUTES)
@@ -83,6 +87,7 @@ module ClaudeAgent
83
87
  args.concat(settings_args)
84
88
  args.concat(environment_args)
85
89
  args.concat(output_args)
90
+ args.concat(setup_hook_args)
86
91
  args.concat(extra_cli_args)
87
92
  end
88
93
  end
@@ -206,6 +211,7 @@ module ClaudeAgent
206
211
  def environment_args
207
212
  [].tap do |args|
208
213
  args.push("--user", user) if user
214
+ args.push("--agent", agent) if agent
209
215
  add_dirs.each { |dir| args.push("--add-dir", dir.to_s) }
210
216
  args.push("--setting-sources", setting_sources.join(",")) if setting_sources&.any?
211
217
  plugins.each do |plugin|
@@ -229,6 +235,14 @@ module ClaudeAgent
229
235
  end
230
236
  end
231
237
 
238
+ def setup_hook_args
239
+ [].tap do |args|
240
+ args.push("--init") if init
241
+ args.push("--init-only") if init_only
242
+ args.push("--maintenance") if maintenance
243
+ end
244
+ end
245
+
232
246
  def extra_cli_args
233
247
  [].tap do |args|
234
248
  extra_args.each do |key, value|
@@ -261,6 +275,11 @@ module ClaudeAgent
261
275
  if max_budget_usd && (!max_budget_usd.is_a?(Numeric) || max_budget_usd <= 0)
262
276
  raise ConfigurationError, "max_budget_usd must be a positive number"
263
277
  end
278
+
279
+ setup_options = [ init, init_only, maintenance ].count { |opt| opt }
280
+ if setup_options > 1
281
+ raise ConfigurationError, "Only one of init, init_only, or maintenance can be set at a time"
282
+ end
264
283
  end
265
284
  end
266
285
  end
@@ -2,6 +2,48 @@
2
2
 
3
3
  module ClaudeAgent
4
4
  class << self
5
+ # Run Setup hooks and exit
6
+ #
7
+ # This is a convenience method for running Setup hooks without starting
8
+ # a conversation. Useful for CI/CD pipelines or scripts that need to
9
+ # ensure setup is complete before proceeding.
10
+ #
11
+ # @param trigger [Symbol] The setup trigger (:init or :maintenance)
12
+ # @param options [Options, nil] Additional configuration options
13
+ # @return [Array<Message>] All messages received during setup
14
+ #
15
+ # @example Run init setup
16
+ # messages = ClaudeAgent.run_setup
17
+ # result = messages.last
18
+ # puts "Setup completed" if result.success?
19
+ #
20
+ # @example Run init setup with custom options
21
+ # options = ClaudeAgent::Options.new(cwd: "/my/project")
22
+ # ClaudeAgent.run_setup(trigger: :init, options: options)
23
+ #
24
+ # @note The :maintenance trigger requires --maintenance flag which
25
+ # continues into a conversation. For maintenance-only behavior,
26
+ # use options with maintenance: true and handle accordingly.
27
+ #
28
+ def run_setup(trigger: :init, options: nil)
29
+ options ||= Options.new
30
+
31
+ case trigger
32
+ when :init
33
+ # Create new options with init_only set
34
+ setup_options = Options.new(**options_to_hash(options).merge(init_only: true))
35
+ when :maintenance
36
+ # Note: There's no --maintenance-only flag, so we use --maintenance
37
+ # which will continue into a conversation. The caller should handle this.
38
+ setup_options = Options.new(**options_to_hash(options).merge(maintenance: true))
39
+ else
40
+ raise ArgumentError, "Invalid trigger: #{trigger}. Must be :init or :maintenance"
41
+ end
42
+
43
+ # Run with an empty prompt - setup hooks run before the prompt is processed
44
+ query(prompt: "", options: setup_options).to_a
45
+ end
46
+
5
47
  # One-shot query to Claude Code CLI
6
48
  #
7
49
  # This is a simple, stateless interface for sending a single prompt
@@ -86,5 +128,17 @@ module ClaudeAgent
86
128
  end
87
129
  end
88
130
  end
131
+
132
+ private
133
+
134
+ # Convert an Options object to a hash for merging
135
+ # @param options [Options] The options object
136
+ # @return [Hash] Hash of option values
137
+ def options_to_hash(options)
138
+ Options::ATTRIBUTES.each_with_object({}) do |attr, hash|
139
+ value = options.send(attr)
140
+ hash[attr] = value unless value.nil?
141
+ end
142
+ end
89
143
  end
90
144
  end
@@ -150,7 +150,7 @@ module ClaudeAgent
150
150
 
151
151
  # Agent definition for custom subagents (TypeScript SDK parity)
152
152
  #
153
- # @example
153
+ # @example Basic agent
154
154
  # agent = AgentDefinition.new(
155
155
  # description: "Runs tests and reports results",
156
156
  # prompt: "You are a test runner...",
@@ -158,6 +158,14 @@ module ClaudeAgent
158
158
  # model: "haiku"
159
159
  # )
160
160
  #
161
+ # @example Agent with skills and max_turns
162
+ # agent = AgentDefinition.new(
163
+ # description: "Research agent with specialized skills",
164
+ # prompt: "You are a research expert...",
165
+ # skills: ["web-search", "summarization"],
166
+ # max_turns: 10
167
+ # )
168
+ #
161
169
  AgentDefinition = Data.define(
162
170
  :description,
163
171
  :prompt,
@@ -165,7 +173,9 @@ module ClaudeAgent
165
173
  :disallowed_tools,
166
174
  :model,
167
175
  :mcp_servers,
168
- :critical_system_reminder
176
+ :critical_system_reminder,
177
+ :skills,
178
+ :max_turns
169
179
  ) do
170
180
  def initialize(
171
181
  description:,
@@ -174,7 +184,9 @@ module ClaudeAgent
174
184
  disallowed_tools: nil,
175
185
  model: nil,
176
186
  mcp_servers: nil,
177
- critical_system_reminder: nil
187
+ critical_system_reminder: nil,
188
+ skills: nil,
189
+ max_turns: nil
178
190
  )
179
191
  super
180
192
  end
@@ -189,6 +201,8 @@ module ClaudeAgent
189
201
  result[:model] = model if model
190
202
  result[:mcpServers] = mcp_servers if mcp_servers
191
203
  result[:criticalSystemReminder_EXPERIMENTAL] = critical_system_reminder if critical_system_reminder
204
+ result[:skills] = skills if skills
205
+ result[:maxTurns] = max_turns if max_turns
192
206
  result
193
207
  end
194
208
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeAgent
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/sig/claude_agent.rbs CHANGED
@@ -279,6 +279,7 @@ module ClaudeAgent
279
279
  attr_accessor add_dirs: Array[String]
280
280
  attr_accessor env: Hash[String, String]
281
281
  attr_accessor user: String?
282
+ attr_accessor agent: String?
282
283
 
283
284
  # CLI configuration
284
285
  attr_accessor cli_path: String?
@@ -633,8 +634,9 @@ module ClaudeAgent
633
634
  class SessionStartInput < BaseHookInput
634
635
  attr_reader source: String
635
636
  attr_reader agent_type: String?
637
+ attr_reader model: String?
636
638
 
637
- def initialize: (source: String, ?agent_type: String?, **untyped) -> void
639
+ def initialize: (source: String, ?agent_type: String?, ?model: String?, **untyped) -> void
638
640
  end
639
641
 
640
642
  class SessionEndInput < BaseHookInput
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Carr