Repository navigation
v1.1.0
Syncs with Python SDK 0.2.162. Additive only: one new option and a fix to when query() closes stdin.
Added
ClaudeAgentOptions#verbatim_prompts(defaultfalse; Python SDK #1269). Whentrue, every user message the SDK writes carriesclient_composed: true: String prompts and each message of a streamed prompt, throughquery,Client#connectandClient#query. Claude Code then delivers the text as written, with no@pathfile expansion and no slash-command dispatch. Use it when a prompt includes text your end user did not type.tools: []anddisallowed_toolsdo not stop@pathexpansion, which reads the file before the model runs. While the option is on, a caller'sclient_composedkey is overwritten, and caller Hashes are never mutated. A streamed JSONL String is parsed and re-serialized; one that is not a single JSON object raisesArgumentErrorrather than going out unmarked.Clientreads the option once, atconnect. On current CLIs such a turn also skips the turn-start attachment pass (nestedCLAUDE.mdand rules files, skill and tool listings). Requires Claude Code 2.1.248 or later; the SDK warns when it connects to an older CLI with the option on. Seedocs/configuration.md.- Development only, nothing ships in the gem: TLA+ models in
formal/tla/of the two most concurrency-sensitive designs.CLIInstaller.tlacoversCLIInstaller.install's publish order, the in-lock dist-tag resolve and the stale-temp sweep.ControlProtocol.tlacovers the outbound control-request waiter protocol inQuery.formal/tla/run.shmodel-checks both with TLC. It confirms that the shipped design passes and that each alternative the source comments reject, including the historical rename-then-record order, produces a counterexample.
Changed
CLIInstaller::PINNED_CLI_VERSIONmoves from 2.1.280 (the 1.0.0 pin) to 2.1.285, the CLI the Python SDK 0.2.162 bundles.CLIInstaller.install_pinnedinstalls it. It honors bothclient_composed(verbatim_prompts) andCLAUDE_CODE_SDK_READS_SESSION_STATE(the fix below).
Fixed
query()with hooks,can_use_toolor SDK MCP servers no longer closes stdin while a follow-up turn is still owed (Python SDK #1279, fixing Python issue #1190). A background subagent that finished just before the turn's result was already off the in-flight ledger, so stdin closed at that result, and the follow-up turn its completion triggered had every hook, permission and SDK MCP request fail with "Stream closed" (the model reported the tool as refused). The transport now setsCLAUDE_CODE_SDK_READS_SESSION_STATE=1unlessoptions.envor the environment already names it (in any case; anilvalue inoptions.envunsets it). The CLI then sendssession_state_changedframes markedsdk_host_only, which the SDK drops from the message stream forquery()andClientalike.query()keeps stdin open until the CLI reportsidleafter a result:- The wait between turns is bounded by
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS, read fromoptions.envand then the environment; the default is 10 minutes and0means no limit. The clock restarts at each result and at eachrunning. A main-thread turn, the CLI reportingrequires_action, a tracked background agent and a hook, permission or SDK MCP request the SDK is still answering each stop it. - With an Enumerable prompt, each message written waits for its own run. Work the CLI takes up after the run ended reopens it.
- A CLI that sends no state (2.1.282 and earlier) gets the old behavior: stdin closes at the first result with no tracked task in flight.
- Background agents, bounded monitors and MCP tasks can now keep a one-shot run open, up to the ceiling. Background shells, persistent monitors and remote agents do not, because the CLI leaves them out of its
runningreport. SessionStateChangedMessagereaches your code only if you setCLAUDE_CODE_EMIT_SESSION_STATE_EVENTS=1yourself; the SDK never sets it.- A custom transport must pass
CLAUDE_CODE_SDK_READS_SESSION_STATE=1to the CLI itself to get this behavior (seedocs/client.md); the E2B example transport now does.
- The wait between turns is bounded by
Usage
# Prompt text your end user did not type can no longer pull local files in via @path
options = ClaudeAgentSDK::ClaudeAgentOptions.new(verbatim_prompts: true)
ClaudeAgentSDK.query(prompt: untrusted_text, options: options) { |message| ... }What's changed
- #145 Sync with Python SDK 0.2.162: verbatim_prompts + stdin open until idle — @ya-luotao
- #144 Bump PINNED_CLI_VERSION to 2.1.285 — @github-actions
- #143 Bump PINNED_CLI_VERSION to 2.1.284 — @github-actions
- #142 Bump PINNED_CLI_VERSION to 2.1.283 — @github-actions
- #141 Add TLA+ models of the CLI installer and control-request protocol — @ya-luotao
Full Changelog: v1.0.0...v1.1.0
gem install claude-agent-sdk -v 1.1.0