Skip to content

Conversation

@rushilpatel0
Copy link
Contributor

@rushilpatel0 rushilpatel0 commented Jul 26, 2025

Summary

This PR exposes the Transport interface in the public API, enabling users to pass custom transport implementations to the query() function. Previously, transport selection was internal and users had no way to provide custom implementations.

Primary Benefits:

  • 🔌 Remote claude code - Connect to Claude Code CLIs running remotely
    • The concrete use case here is to be able to implement a custom transport that can communicate to claude code instances running in remote sandboxes. Currently the the sdk only works with Claude Codes running in a local subprocess limiting the scenarios in which this SDK can be used.

Changes

Public API Changes

  • Exposed the previously internal Transport abstract base class in claude_code_sdk.__init__.py
  • Added transport parameter to query() function signature
  • Updated docstring with transport parameter documentation

Internal Changes

  • Modified InternalClient.process_query() to accept optional transport parameter
  • Added transport selection logic - use provided transport or default to SubprocessCLITransport
  • Updated __all__ exports to include Transport

Testing

  • Updated existing tests to work with new transport parameter
  • Maintained backward compatibility - all existing code continues to work unchanged

Testing

Existing Tests

  • ✅ All existing unit tests pass with new transport parameter
  • ✅ Integration tests updated to mock new transport interface
  • ✅ Subprocess buffering tests continue to work with exposed transport

New Functionality Testing

  • ✅ Verified custom transport can be passed to query()
  • ✅ Confirmed default behavior unchanged when no transport provided
  • ✅ Validated transport lifecycle ( connect → receive → disconnect)
  • ✅ Tested transport interface compliance with abstract base class

Example Usage

Basic Custom Transport

from claude_code_sdk import query, ClaudeCodeOptions, Transport

class MyCustomTransport(Transport):
    # Implement abstract methods: connect, disconnect, 
    # send_request, receive_messages, is_connected
    pass

transport = MyCustomTransport()
async for message in query(
    prompt="Hello",
    transport=transport
):
    print(message)

Related

🤖 Generated with Claude Code

@rushilpatel0 rushilpatel0 marked this pull request as ready for review July 27, 2025 06:55
Copy link
Collaborator

@dicksontsai dicksontsai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is reasonable. Left some comments that should be addressed. Thanks!

@rushilpatel0
Copy link
Contributor Author

rushilpatel0 commented Jul 31, 2025

@dicksontsai Thanks for the review, i'll address these changes soon.

Looks like the ClaudeSDKClient will also need a similar update to accept a transport, I can include changes for that as well in a separate PR if needed

@rushilpatel0
Copy link
Contributor Author

@dicksontsai mind reviewing once more, addressed your prior comments

@dicksontsai
Copy link
Collaborator

Commits must have verified signatures.

Thanks for the changes. You'll need to run lint and also re-push your entire branch with new commits that have verified signatures.

See https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits for instructions.

@oneryalcin
Copy link

I'm building an application on claude code sdk and need isolation where claude code cli runs while I would like to use python sdk. Without this change nothing is prod ready. Would love to see 100% this is merged.

ltawfik and others added 23 commits August 17, 2025 12:55
- Uses claude-code-base-action for automated issue triage
- Analyzes new issues and applies appropriate labels
- Uses GitHub MCP server for issue operations
- Requires ANTHROPIC_API_KEY secret to be configured

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Previously was raised as a CLINotFoundError

Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
github-actions bot and others added 24 commits August 17, 2025 13:07
This PR updates the version to 0.0.16 after publishing to PyPI.

## Changes
- Updated version in `pyproject.toml`
- Updated version in `src/claude_code_sdk/__init__.py`

## Release Information
- Published to PyPI: https://pypi.org/project/claude-code-sdk/0.0.16/
- Install with: `pip install claude-code-sdk==0.0.16`

🤖 Generated by GitHub Actions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
## Summary
- Replace asyncio.create_task() with anyio task group for trio
compatibility
- Update client.py docstring example to use anyio.sleep
- Add trio example demonstrating multi-turn conversation

## Details
The SDK already uses anyio for most async operations, but one line was
using asyncio.create_task() which broke trio compatibility. This PR
fixes that by using anyio's task group API with proper lifecycle
management.

### Changes:
1. **subprocess_cli.py**: Replace asyncio.create_task() with anyio task
group, ensuring proper cleanup on disconnect
2. **client.py**: Update docstring example to use anyio.sleep instead of
asyncio.sleep
3. **streaming_mode_trio.py**: Add new example showing how to use the
SDK with trio

## Test plan
- [x] All existing tests pass
- [x] Manually tested with trio runtime (created test script that
successfully runs multi-turn conversation)
- [x] Linting and type checking pass

🤖 Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Rushil Patel <rpatel@codegen.com>
This PR updates the version to 0.0.17 after publishing to PyPI.

## Changes
- Updated version in `pyproject.toml`
- Updated version in `src/claude_code_sdk/__init__.py`

## Release Information
- Published to PyPI: https://pypi.org/project/claude-code-sdk/0.0.17/
- Install with: `pip install claude-code-sdk==0.0.17`

🤖 Generated by GitHub Actions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
- Add `settings` field to `ClaudeCodeOptions` to expose the `--settings`
CLI flag
- Allow SDK users to specify custom settings configuration path

- Added `settings: str | None = None` field to `ClaudeCodeOptions`
dataclass
- Added CLI argument conversion logic in `SubprocessCLITransport` to
pass `--settings` flag to Claude Code CLI

- [x] All existing tests pass
- [x] Linting passes (`python -m ruff check`)
- [x] Type checking passes (`python -m mypy src/`)

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Fixes anthropics#90

Signed-off-by: Rushil Patel <rpatel@codegen.com>
This PR updates the version to 0.0.18 after publishing to PyPI.

## Changes
- Updated version in `pyproject.toml`
- Updated version in `src/claude_code_sdk/__init__.py`

## Release Information
- Published to PyPI: https://pypi.org/project/claude-code-sdk/0.0.18/
- Install with: `pip install claude-code-sdk==0.0.18`

🤖 Generated by GitHub Actions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
…ropics#103)

## Summary

Fixes a critical deadlock issue that occurs when MCP servers produce
verbose stderr output. The SDK would hang indefinitely when the stderr
pipe buffer filled up.

## The Problem

The deadlock occurred due to sequential reading of subprocess streams:
1. SDK reads stdout completely before reading stderr
2. When stderr pipe buffer fills (64KB on Linux, 16KB on macOS),
subprocess blocks on write
3. Subprocess can't continue to stdout, parent waits for stdout →
**DEADLOCK** 🔒

## The Solution

Redirect stderr to a temporary file instead of a pipe:
- **No pipe buffer** = no possibility of deadlock
- Temp file can grow as needed (no 64KB limit)
- Still capture stderr for error reporting (last 100 lines)
- Works consistently across all async backends

## Implementation Details

- `stderr=tempfile.NamedTemporaryFile()` instead of `stderr=PIPE`
- Use `deque(maxlen=100)` to keep only recent stderr lines in memory
- Temp file is automatically cleaned up on disconnect
- Add `[stderr truncated, showing last 100 lines]` message when buffer
is full

## Testing

- Verified no deadlock with 150+ lines of stderr output
- Confirmed stderr is still captured for error reporting
- All existing tests pass
- Works with asyncio, trio, and other anyio backends

## Impact

- Fixes consistent hangs in production with MCP servers
- No functional regression - stderr handling is preserved
- Simpler than concurrent reading alternatives
- More robust than pipe-based solutions

Fixes the issue reported in Slack where SDK would hang indefinitely when
receiving messages from MCP servers with verbose logging.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
This PR updates the version to 0.0.19 after publishing to PyPI.

## Changes
- Updated version in `pyproject.toml`
- Updated version in `src/claude_code_sdk/__init__.py`

## Release Information
- Published to PyPI: https://pypi.org/project/claude-code-sdk/0.0.19/
- Install with: `pip install claude-code-sdk==0.0.19`

🤖 Generated by GitHub Actions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
the `mcp_tools` field in `ClaudeCodeOptions` seems to have been there
since the initial commit but I couldn't find any references in the repo,
so I believe it may be vestigial and unused

Signed-off-by: Rushil Patel <rpatel@codegen.com>
…nthropics#111)

## Summary
- Adds `extra_args` field to `ClaudeCodeOptions` to support passing
arbitrary CLI flags
- Enables forward compatibility with future CLI flags without requiring
SDK updates
- Supports both valued flags (`--flag value`) and boolean flags
(`--flag`)

## Changes
- Add `extra_args: dict[str, str | None]` field to `ClaudeCodeOptions`
- Implement logic in `SubprocessCLITransport` to handle extra args:
- `None` values create boolean flags (e.g., `{"verbose": None}` →
`--verbose`)
- String values create flags with arguments (e.g., `{"output": "json"}`
→ `--output json`)
- Add comprehensive tests for the new functionality

## Test plan
- [x] Added unit tests for settings file path handling
- [x] Added unit tests for settings JSON object handling
- [x] Added unit tests for extra_args with both valued and boolean flags
- [x] All tests pass (`python -m pytest tests/`)
- [x] Type checking passes (`python -m mypy src/`)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
)

`claude`'s `--mcp-config` takes either a JSON file or string, so support
this in `ClaudeCodeOptions`
```
  --mcp-config <file or string>    Load MCP servers from a JSON file or string
```

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Sam Fu <shunfu@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
)

Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
## Summary

Fixes an issue where `thinking` content blocks in Claude Code responses
were not being parsed, resulting in empty `AssistantMessage` content
arrays.

## Changes
- Added `ThinkingBlock` dataclass to handle thinking content with
`thinking` and `signature` fields
- Updated client parsing logic in `_internal/client.py` to recognize and
create `ThinkingBlock` instances
- Added comprehensive test coverage for thinking block functionality

## Before

```python
# Claude Code response with thinking block resulted in:
AssistantMessage(content=[])  # Empty content!
```

## After

```python
# Now correctly parses to:
AssistantMessage(content=[
    ThinkingBlock(thinking="...", signature="...")
])
```

Fixes anthropics#27

---------

Co-authored-by: Dickson Tsai <dickson@anthropic.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
This PR updates the version to 0.0.20 after publishing to PyPI.

## Changes
- Updated version in `pyproject.toml`
- Updated version in `src/claude_code_sdk/__init__.py`

## Release Information
- Published to PyPI: https://pypi.org/project/claude-code-sdk/0.0.20/
- Install with: `pip install claude-code-sdk==0.0.20`

🤖 Generated by GitHub Actions

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Rushil Patel <rpatel@codegen.com>
@rushilpatel0 rushilpatel0 force-pushed the feat/enable-custom-transports branch from f18d4a1 to 0a730f3 Compare August 17, 2025 20:32
@rushilpatel0
Copy link
Contributor Author

@dicksontsai I've amended my commits with my signature and formatted/linted these changes. Let me know if anything else is needed

@dicksontsai dicksontsai merged commit bc01cd7 into anthropics:main Aug 19, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants