Replace heredoc with echo statements to fix YAML parsing issue. The
unindented heredoc content was breaking out of the literal block scalar,
causing `---` to be interpreted as a YAML document separator.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.18 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.18
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.18
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.18/
- Bundled CLI version: 2.0.72
- Install with: `pip install claude-agent-sdk==0.1.18`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Add `Dockerfile.test`: Python 3.12 image with Claude Code CLI
installed
- Add `scripts/test-docker.sh`: Local script to run tests in Docker
- Add `test-e2e-docker` job to CI workflow that runs the full e2e suite
in a container
- Add `.dockerignore` to speed up Docker builds
## Context
This helps catch Docker-specific issues like #406 where filesystem-based
agents loaded via `setting_sources=["project"]` may silently fail in
Docker environments.
## Local Usage
```bash
# Run unit tests in Docker (no API key needed)
./scripts/test-docker.sh unit
# Run e2e tests in Docker
ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh e2e
# Run all tests
ANTHROPIC_API_KEY=sk-... ./scripts/test-docker.sh all
```
## Test plan
- [x] Unit tests pass in Docker locally (129 passed)
- [ ] CI job runs successfully
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Replace auto-generated release notes with content extracted from
CHANGELOG.md for the specific version being released. This provides more
structured and consistent release notes with proper sections like Bug
Fixes, New Features, etc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.17 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.17
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.17
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.17/
- Bundled CLI version: 2.0.70
- Install with: `pip install claude-agent-sdk==0.1.17`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.16 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.16
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.16
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.16/
- Bundled CLI version: 2.0.68
- Install with: `pip install claude-agent-sdk==0.1.16`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixes#401
Enables applications to detect API errors (especially `rate_limit`
errors) by properly parsing the `error` field in `AssistantMessage`.
## Problem
The SDK defines `AssistantMessage.error` (including `"rate_limit"`), but
the message parser never extracted this field from the CLI response.
This made it impossible for applications to:
- Detect when rate limits are hit
- Implement retry logic
- Handle other API errors gracefully
## Solution
Added error field extraction in the message parser:
```python
return AssistantMessage(
content=content_blocks,
model=data["message"]["model"],
parent_tool_use_id=data.get("parent_tool_use_id"),
error=data["message"].get("error"), # ← Now extracts error field
)
```
## Changes
**Modified: `src/claude_agent_sdk/_internal/message_parser.py`**
The parser now extracts the `error` field from API responses and
populates it in the `AssistantMessage` object.
## Usage Example
Applications can now detect and handle rate limits:
```python
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
if message.error == "rate_limit":
print("Rate limit hit! Implementing backoff...")
await asyncio.sleep(60)
# Retry logic here
elif message.error:
print(f"API error: {message.error}")
```
## Testing
- ✅ Passed ruff linting and formatting
- ✅ Passed mypy type checking
- ✅ All existing tests pass
## Type of Change
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
## Impact
This fix enables production applications to:
- Implement proper error handling for API errors
- Build robust retry logic for rate limits
- Provide better user feedback when errors occur
- Avoid silent failures when the API returns errors
---
🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
This PR updates the version to 0.1.15 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.15
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.15
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.15/
- Bundled CLI version: 2.0.62
- Install with: `pip install claude-agent-sdk==0.1.15`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Add `enable_file_checkpointing` option to `ClaudeAgentOptions`
- Add `rewind_files(user_message_id)` method to `ClaudeSDKClient` and
`Query`
- Add `SDKControlRewindFilesRequest` type for the control protocol
- Set `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` env var when enabled
This adds Python SDK support for the file rewind feature from
claude-cli-internal PR #11265.
## Test plan
- [x] Verified imports work correctly
- [x] Verified linting passes (`ruff check`)
- [x] Verified existing tests still pass (106 passed, pre-existing
failures unrelated to this change)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
This PR updates the version to 0.1.14 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.14
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.14
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.14/
- Bundled CLI version: 2.0.62
- Install with: `pip install claude-agent-sdk==0.1.14`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
The fetch-depth: 0 was on build-wheels but changelog generation happens
in the publish job. Moved it to the correct location and upgraded the
model for better changelog generation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.13 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.13
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.13
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.13/
- Bundled CLI version: 2.0.59
- Install with: `pip install claude-agent-sdk==0.1.13`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
When the CLI exits with an error (e.g., invalid session ID passed to
`--resume`), signal all pending control requests immediately instead of
waiting for the 60-second timeout.
**The fix adds 4 lines** to the exception handler in `_read_messages`:
```python
# Signal all pending control requests so they fail fast instead of timing out
for request_id, event in list(self.pending_control_responses.items()):
if request_id not in self.pending_control_results:
self.pending_control_results[request_id] = e
event.set()
```
## Problem
When the CLI exits with an error, the SDK's message reader catches it
but doesn't notify pending control requests. This causes `initialize()`
to wait for the full 60-second timeout even though the error is known
within seconds.
Example scenario:
1. User passes invalid session ID via
`ClaudeAgentOptions(resume="invalid-id")`
2. CLI prints `No conversation found with session ID: xxx` and exits
with code 1
3. SDK message reader catches the error after ~3 seconds
4. But `initialize()` keeps waiting for 60 seconds before timing out
## Solution
The existing code at `_send_control_request` lines 361-362 already
handles exceptions in results:
```python
if isinstance(result, Exception):
raise result
```
The fix simply signals all pending control events when an error occurs,
allowing them to fail fast with the actual error instead of timing out.
## Test Plan
- [ ] Test with invalid session ID - should fail fast (~3s) instead of
timing out (60s)
- [ ] Test normal flow still works
- [ ] Test multiple pending requests all get signaled
Fixes#387
## Summary
- Add runtime placeholder for `McpServer` type to fix Pydantic 2.12+
compatibility
- `McpServer` was only imported under `TYPE_CHECKING`, causing
`PydanticUserError` at runtime
Fixes#384
Co-authored-by: lyrica <lyrica@example.com>
## TL;DR
Adds a write lock to `SubprocessCLITransport` to prevent concurrent
writes from parallel subagents.
---
## Overview
When multiple subagents run in parallel and invoke MCP tools, the CLI
sends concurrent `control_request` messages. Each handler tries to write
a response back to the subprocess stdin at the same time. Trio's
`TextSendStream` isn't thread-safe for concurrent access, so this causes
`BusyResourceError`.
This PR adds an `anyio.Lock` around all write operations (`write()`,
`end_input()`, and the stdin-closing part of `close()`). The lock
serializes concurrent writes so they happen one at a time. The `_ready`
flag is now set inside the lock during `close()` to prevent a TOCTOU
race where `write()` checks `_ready`, then `close()` sets it and closes
the stream before `write()` actually sends data.
---
## Call Flow
```mermaid
flowchart TD
A["write()<br/>subprocess_cli.py:505"] --> B["acquire _write_lock<br/>subprocess_cli.py:507"]
B --> C["check _ready & stream<br/>subprocess_cli.py:509"]
C --> D["_stdin_stream.send()<br/>subprocess_cli.py:523"]
E["close()<br/>subprocess_cli.py:458"] --> F["acquire _write_lock<br/>subprocess_cli.py:478"]
F --> G["set _ready = False<br/>subprocess_cli.py:479"]
G --> H["close _stdin_stream<br/>subprocess_cli.py:481"]
I["end_input()<br/>subprocess_cli.py:531"] --> J["acquire _write_lock<br/>subprocess_cli.py:533"]
J --> K["close _stdin_stream<br/>subprocess_cli.py:535"]
```
This PR updates the version to 0.1.12 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.12
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.12
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.12/
- Bundled CLI version: 2.0.58
- Install with: `pip install claude-agent-sdk==0.1.12`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
Add support for the `tools` option matching the TypeScript SDK, which
controls the base set of available tools separately from
allowed/disallowed tool filtering.
Supports three modes:
- Array of tool names: `["Read", "Edit", "Bash"]`
- Empty array: `[]` (disables all built-in tools)
- Preset object: `{"type": "preset", "preset": "claude_code"}`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Port the SdkBeta type and betas option from the TypeScript SDK to enable
SDK users to pass beta feature flags (e.g., 1M context window) to the
CLI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.11 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.11
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.11
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.11/
- Bundled CLI version: 2.0.57
- Install with: `pip install claude-agent-sdk==0.1.11`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Currently wheels with packaged claude-code CLI are only published for
windows amd64, linux x86_64 and macos arm64. For version 0.1.10, we can
see the following download files are available on pypi contain the
following artifacts:
https://pypi.org/project/claude-agent-sdk/0.1.10/#files
- claude_agent_sdk-0.1.10.tar.gz
- claude_agent_sdk-0.1.10-py3-none-win_amd64.whl
- claude_agent_sdk-0.1.10-py3-none-manylinux_2_17_x86_64.whl
- claude_agent_sdk-0.1.10-py3-none-macosx_11_0_arm64.whl
The existing publishing code should support adding a new linux arm64
wheel builder, using the Github ARM runners:
https://github.blog/changelog/2025-08-07-arm64-hosted-runners-for-public-repositories-are-now-generally-available/
Unfortunately, there's no `ubuntu-latest-arm` label similar to the one
we use for the other builds, so I'm using the `ubuntu-24.04-arm` label.
Port SDK MCP fix from TypeScript to Python.
Now, when SDK MCP servers or hooks are present, stream_input() waits for
the first result message before closing stdin, allowing bidirectional
control protocol communication to complete.
Fixes repro in
https://github.com/anthropics/claude-agent-sdk-python/issues/266.
The `query()` design requires input streams to be held open by the user
for SDK MCP bidirectional communication to work. This has confused a lot
of folks, so we're moving towards a more explicit lifecycle design. In
the meantime, this is the way we've addressed it with V1 APIs in
https://github.com/anthropics/claude-agent-sdk-typescript.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Update type: ignore comments to use `untyped-decorator` instead of
`misc` to match the actual mypy error codes reported in CI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Adds programmatic sandbox configuration to the Python SDK, matching the
TypeScript SDK's approach.
Changes:
- Add SandboxSettings, SandboxNetworkConfig, SandboxIgnoreViolations
types
- Add sandbox field to ClaudeAgentOptions
- Merge sandbox into --settings CLI flag in SubprocessCLITransport
- Export sandbox types from package __init__.py
- Add comprehensive tests for sandbox settings
**Important:** Filesystem and network restrictions are configured via
permission rules (Read/Edit/WebFetch), not via these sandbox settings.
The sandbox settings control sandbox behavior (enabled, auto-allow,
excluded commands, etc.).
Example usage:
```python
from claude_agent_sdk import query, SandboxSettings
result = query(
prompt='Build and test the project',
options=ClaudeAgentOptions(
sandbox={
'enabled': True,
'autoAllowBashIfSandboxed': True,
'excludedCommands': ['docker'],
'network': {
'allowLocalBinding': True,
'allowUnixSockets': ['/var/run/docker.sock']
}
}
)
)
```
Co-authored-by: Claude <noreply@anthropic.com>
This PR updates the version to 0.1.10 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.10
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.10
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.10/
- Bundled CLI version: 2.0.53
- Install with: `pip install claude-agent-sdk==0.1.10`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Posts new issues to claude-agent-sdk-feedback. Can't use the default
github slack bot as it's too noisy (all comments and issue updates such
as comments, closing, etc...)
---------
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
This PR updates the version to 0.1.9 after publishing to PyPI.
## Changes
- Updated version in `pyproject.toml` to 0.1.9
- Updated version in `src/claude_agent_sdk/_version.py` to 0.1.9
- Updated `CHANGELOG.md` with release notes
## Release Information
- Published to PyPI: https://pypi.org/project/claude-agent-sdk/0.1.9/
- Bundled CLI version: 2.0.49
- Install with: `pip install claude-agent-sdk==0.1.9`
🤖 Generated by GitHub Actions
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
## Summary
- Adds optional `timeout` field to `HookMatcher` dataclass in `types.py`
that allows users to specify a custom timeout (in seconds) for hooks
- Propagates the timeout value through:
- `client.py` and `_internal/client.py`: `_convert_hooks_to_internal()`
method
- `_internal/query.py`: hook config sent to CLI
## Test plan
- [x] Verify hooks work without timeout specified (default behavior)
- [x] Verify custom timeout is passed to CLI when specified in
HookMatcher
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Remove the claude_code_version workflow input and instead read the CLI
version directly from src/claude_agent_sdk/_cli_version.py. This allows
the version to be managed separately and updated by automation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-19 09:49:35 -08:00
25 changed files with 1371 additions and 109 deletions
- **Docker-based test infrastructure**: Added Docker support for running e2e tests in containerized environments, helping catch Docker-specific issues (#424)
- Updated bundled Claude CLI to version 2.0.72
## 0.1.17
### New Features
- **UserMessage UUID field**: Added `uuid` field to `UserMessage` response type, making it easier to use the `rewind_files()` method by providing direct access to message identifiers needed for file checkpointing (#418)
### Internal/Other Changes
- Updated bundled Claude CLI to version 2.0.70
## 0.1.16
### Bug Fixes
- **Rate limit detection**: Fixed parsing of the `error` field in `AssistantMessage`, enabling applications to detect and handle API errors like rate limits. Previously, the `error` field was defined but never populated from CLI responses (#405)
### Internal/Other Changes
- Updated bundled Claude CLI to version 2.0.68
## 0.1.15
### New Features
- **File checkpointing and rewind**: Added `enable_file_checkpointing` option to `ClaudeAgentOptions` and `rewind_files(user_message_id)` method to `ClaudeSDKClient` and `Query`. This enables reverting file changes made during a session back to a specific checkpoint, useful for exploring different approaches or recovering from unwanted modifications (#395)
### Documentation
- Added license and terms section to README (#399)
## 0.1.14
### Internal/Other Changes
- Updated bundled Claude CLI to version 2.0.62
## 0.1.13
### Bug Fixes
- **Faster error handling**: CLI errors (e.g., invalid session ID) now propagate to pending requests immediately instead of waiting for the 60-second timeout (#388)
- **Pydantic 2.12+ compatibility**: Fixed `PydanticUserError` caused by `McpServer` type only being imported under `TYPE_CHECKING` (#385)
- **Concurrent subagent writes**: Added write lock to prevent `BusyResourceError` when multiple subagents invoke MCP tools in parallel (#391)
### Internal/Other Changes
- Updated bundled Claude CLI to version 2.0.59
## 0.1.12
### New Features
- **Tools option**: Added `tools` option to `ClaudeAgentOptions` for controlling the base set of available tools, matching the TypeScript SDK functionality. Supports three modes:
- Array of tool names to specify which tools should be available (e.g., `["Read", "Edit", "Bash"]`)
- Empty array `[]` to disable all built-in tools
- Preset object `{"type": "preset", "preset": "claude_code"}` to use the default Claude Code toolset
- **SDK beta support**: Added `betas` option to `ClaudeAgentOptions` for enabling Anthropic API beta features. Currently supports `"context-1m-2025-08-07"` for extended context window
@ -351,6 +351,6 @@ The package is published to PyPI via the GitHub Actions workflow in `.github/wor
The workflow tracks both the package version and the bundled CLI version separately, allowing you to release a new package version with an updated CLI without code changes.
## License
## License and terms
MIT
Use of this SDK is governed by Anthropic's [Commercial Terms of Service](https://www.anthropic.com/legal/commercial-terms), including when you use it to power products and services that you make available to your own customers and end users, except to the extent a specific component or dependency is covered by a different license as indicated in that component's LICENSE file.