Skip to content

v0.37.0

Choose a tag to compare

@ya-luotao ya-luotao released this 23 Sep 14:09
· 334 commits to main since this release

The last 0.x release before 1.0 (roadmap). No runtime behaviour changes — only new warnings for things 1.0 will reject. Run your suite on 0.37 with warnings visible before moving to 1.0:

  • A misspelled key on a value type you build (HookMatcher, AgentDefinition, SandboxSettings, MCP server configs, permission results, hook outputs, …) now warns once, pointing at your call; 1.0 raises ArgumentError.
  • msg[:name] / camelCase readers reaching a non-attribute method (e.g. msg[:to_h]) warn once; in 1.0 they only reach attributes.
  • The 1.0 SemVer surface is now visible: SDK internals are tagged @api private and hidden from the API docs, and the documented contracts (Hash-key rule, mcp_status / context_usage return Hashes, Type#[]) are written down.

Changed

  • Docs: pre-1.0 contracts written down (#126). No code changes. Client#mcp_status / #get_mcp_status and #context_usage / #get_context_usage return the CLI's raw Hash with camelCase Symbol keys. docs/types.md had described McpStatusResponse as the response type; it is the optional typed view, via McpStatusResponse.parse(client.mcp_status), and there is no typed context-usage class (docs/client.md). A new "Hash keys" section in docs/types.md states one rule: Hashes passed through from the live CLI stream (origin, usage, model_usage, hook tool_input, can_use_tool input, SDK MCP tool args, control responses) have Symbol keys spelled as on the wire, and Hashes read from transcripts or a SessionStore (SessionMessage#message, get_subagent_metadata, store keys and entries) have String keys. The docs, examples and bundled skill drop their h[:key] || h['key'] fallbacks in favour of the one correct form. Type#[], #[]= and the camelCase readers are documented as public API, including that #[]= changes the object you received. docs/sessions.md documents ClaudeAgentSDK.project_key_for_directory and ClaudeAgentSDK.fold_session_summary for adapter authors, and import_session_to_store's batching (batch_size: defaults to 500 entries, and a batch also ends at about 1 MiB).
  • SDK internals are now tagged @api private and hidden from the YARD docs (#126). The tagged namespaces are Query, MessageParser, TranscriptMirrorBatcher, Sessions, SessionMutations, SessionResume, MaterializedResume, SessionSummary, SessionStores, OptionWarnings and FiberBoundary, including everything nested in them. Some public classes also have internal members, and those are tagged individually: SubprocessCLITransport's methods outside the Transport interface and its constants; CommandBuilder's constants (.new and #build stay public); CLIInstaller::Http, Platform, Release and Metadata and the installer's constants other than PINNED_CLI_VERSION; SdkMcpServer#handle_json, #handle_message and SdkMcpServer::ToolInputSchema; Client#query_handler; and ClaudeAgentSDK::OBSERVER_INTERFACE. Their public faces are unchanged: ClaudeAgentSDK.offload, fold_session_summary, the session functions and SDKSessionInfo / SessionMessage remain public. Nothing changes at runtime. No method or constant was renamed, removed or made private, so every existing call keeps working. From 1.0, SemVer covers docs/ and the YARD API without @api private; objects tagged @api private are not covered and may change in any release. CONTRIBUTING.md has a new "What is public API" section.
  • lib/claude_agent_sdk/types.rb is split into one file per area under lib/claude_agent_sdk/types/ (messages, hooks, options, ...). The code moved without edits and types.rb still loads every part, so require 'claude_agent_sdk/types' and every class and constant are unchanged; no API change (#126).
  • Type's internal machinery is tagged @api private and leaves the rendered docs: Type#dup_for_options, Type.deep_dup_for_options, Type::OptionValue, Type.inspect_filtered, Type.inspect_filtered_attributes, and the new Type.strict_attributes / .strict_attributes? / .declare_attributes / .attribute? / .attribute_names. They are not part of the SemVer surface. Type#[], #[]=, the camelCase readers, #to_h, .wrap and .from_hash stay public (#126).

Deprecated

  • Unknown keys on user-constructed types. The value types you build and pass in (option values such as AgentDefinition, SandboxSettings, the thinking configs and the MCP server configs; HookMatcher; hook outputs; PermissionResultAllow / PermissionResultDeny; PermissionUpdate; PermissionRuleValue) silently dropped a misspelled key, so HookMatcher.new(matchr: 'Bash') quietly built a matcher with no matcher set. .new and #[]= now warn once per class and key, at the caller's line: ClaudeAgentSDK::HookMatcher: unknown attribute :matchr ignored; this will raise ArgumentError in 1.0 (known: hooks, matcher, timeout). In 1.0 they raise ArgumentError, as ClaudeAgentOptions already does. camelCase and String keys and a type's own discriminator (type, hook_event_name, behavior) are accepted, so klass.new(value.to_h) round-trips silently. Types parsed from CLI output (messages, content blocks, hook inputs) and every construction through .from_hash / .wrap stay lenient, so a newer CLI's extra fields never warn; permission suggestions from the CLI are now hydrated through PermissionUpdate.wrap for that reason. Full list in docs/types.md (#126).
  • Type#[], #[]= and camelCase methods reaching something other than an attribute. They are public API for a type's attributes (its attr_* fields, the backward-compatible RateLimitEvent#data, predicates such as options.forkSession?, and any method your own code adds to a subclass, mixin or instance), but they resolved any public method: msg[:to_h] returned a Hash, msg['freeze'] froze the message, msg.toH called #to_h. Such a call still works but warns once per class and name, e.g. ClaudeAgentSDK::ResultMessage#[]: :to_h is not an attribute; Type#[] will only read attributes in 1.0. In 1.0 a name that is not an attribute behaves like an undefined one: #[] returns nil, #[]= ignores it (raises on the types above), a camelCase call raises NoMethodError, and respond_to? says false. Names that are not methods at all keep today's behaviour and do not warn. UserMessage#text / AssistantMessage#text are convenience methods, not attributes (#126).

Check your app before 1.0

# warnings are on by default; make sure your test runner doesn't silence them
bundle exec rspec 2>&1 | grep -E "unknown attribute|is not an attribute|deprecated"

What's changed

  • #133 Split types.rb into lib/claude_agent_sdk/types/ (no API change) — @ya-luotao
  • #136 Warn on unknown keys and non-attribute access on Type (0.37; enforced in 1.0) — @ya-luotao
  • #134 Tag leaked SDK internals @api private — @ya-luotao
  • #135 Write down the pre-1.0 contracts — @ya-luotao
  • #137 Turn Metrics back on everywhere; delete .rubocop_todo.yml — @ya-luotao

Roadmap to 1.0: #126

Full Changelog: v0.36.0...v0.37.0


gem install claude-agent-sdk -v 0.37.0