anthropics / anthropics/claude-agent-sdk-python
ClaudeSDKClient Cannot Be Shared Across Async Runtime Contexts
- Dominant language
- Python
- Stars
- 8.1k
- Forks
- 1.3k
- Avg merge
- 2d 31m
- Merged PRs (30d)
- 1
Description
## Bug: `ClaudeSDKClient` Cannot Be Shared Across Async Runtime Contexts
**Affected version:** v0.0.20+
**File:** `src/claude_agent_sdk/client.py`, line 55
---
### Description
`ClaudeSDKClient` instances are currently tied to the async context in which they were connected. Once `connect()` is called, the client spawns a persistent internal `anyio` task group responsible for reading incoming messages. This task group lives for the entire lifetime of the connection — from `connect()` through `disconnect()` — and cannot be safely accessed or reused from a different async runtime context.
This means the client **cannot** be passed to, or reused across:
- Different `trio` nurseries
- Different `asyncio` task groups
- Any other concurrent async scope that was not the original caller of `connect()`
---
### Why This Is a Problem
This constraint makes it difficult to build real-world applications where a single connected client needs to be shared or handed off between independent async workers, background tasks, or structured concurrency scopes. Common use cases that break under this limitation include:
- Connecting once at startup and reusing the client in multiple task groups
- Delegating work to a worker pool where individual tasks weren't the ones that called `connect()`
- Using the client inside frameworks that manage their own async lifecycles (e.g., FastAPI, Starlette, or Hypercorn with Trio)
---
### Expected Behavior
A connected `ClaudeSDKClient` instance should be usable from any async context, not just the one in which it was originally connected. The internal message-reading task group should either:
1. Be scoped independently of any caller-owned nursery/task group, or
2. Support safe cross-context handoff via a well-defined mechanism
---
### Suggested Fix
Consider running the internal `anyio` task group in a dedicated background thread or a standalone top-level task scope that is not a child of the caller's nursery. This would decouple the client's lifetime from the async scope of the connecting caller.
---
### References
- [`client.py` line 55](https://github.com/anthropics/claude-agent-sdk-python/blob/main/src/claude_agent_sdk/client.py#L55)
- anyio structured concurrency docs: https://anyio.readthedocs.io/en/stable/tasks.html
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.