Drop-in replacement for ClaudeSDKClient that drives Claude Code in interactive TUI mode via tmux
Project description
claude-interactive-sdk
A drop-in replacement for ClaudeSDKClient that runs claude Code in its interactive session mode instead of the SDK's headless stream-json mode, so that the conversation is billed as a normal interactive session. Sessions launched this way produce "entrypoint":"cli" in Claude's session logs, versus "entrypoint":"sdk-cli" for sessions launched via claude -p or the official SDK.
Why
Anthropic announced that programmatic usage via the API and SDK will be billed separately from subscription usage. This SDK lets you drive Claude programmatically while keeping usage on your existing Claude subscription, by launching claude exactly the way a human would (no -p, no --input-format, no --output-format) and exposing the same Python API on top.
Install
Not yet published. For local development:
make install # uv sync --all-extras
Usage
from claude_interactive_sdk import ClaudeInteractiveClient
from claude_agent_sdk import ClaudeAgentOptions, tool, create_sdk_mcp_server
@tool("get_weather", "Get current weather", {"location": str})
async def get_weather(args):
return {"content": [{"type": "text", "text": f"It's sunny in {args['location']}"}]}
mcp = create_sdk_mcp_server(name="my_tools", tools=[get_weather])
async with ClaudeInteractiveClient(
options=ClaudeAgentOptions(
model="claude-sonnet-4-6",
mcp_servers={"my_tools": mcp},
)
) as client:
await client.query("What's the weather in Sydney?")
async for message in client.receive_response():
print(message)
More in examples/.
Compatibility with ClaudeAgentOptions and ClaudeSDKClient
ClaudeSDKClient methods
| Method | Status | Notes |
|---|---|---|
connect() / disconnect() / __aenter__ / __aexit__ |
✅ | |
query(prompt: str) |
✅ | |
query(prompt: AsyncIterable[dict]) |
⚠️ | Each dict serialised as plain text — tool-result semantics lost |
receive_messages() / receive_response() |
✅ | |
interrupt() |
⚠️ | Best-effort — sends C-c to the running session |
get_server_info() |
⚠️ | Returns a minimal stub |
disconnect(detach=True) |
❌ | NotImplementedError |
set_model, set_permission_mode, rewind_files, reconnect_mcp_server, toggle_mcp_server, stop_task, get_mcp_status, get_context_usage |
❌ | All require the SDK control protocol, which doesn't exist in interactive mode |
ClaudeAgentOptions fields
Fully supported — translated to argv, env vars, or --settings JSON:
tools, allowed_tools, disallowed_tools, system_prompt (str or file), mcp_servers (all transport types), strict_mcp_config, continue_conversation, resume, session_id, fork_session, max_turns, max_budget_usd, model, fallback_model, betas, cwd, settings, sandbox, add_dirs, setting_sources, plugins, thinking, max_thinking_tokens, effort, output_format (json_schema), extra_args, cli_path, env, enable_file_checkpointing.
Adapted — same semantics, different mechanism:
| Field | Mechanism |
|---|---|
mcp_servers={"name": {"type": "sdk", …}} |
Materialised into an in-process HTTP MCP server; config rewritten to {"type": "http", "url": "http://127.0.0.1:<port>/mcp/<name>/"} |
can_use_tool |
Intercepted in the HTTP MCP server — MCP-hosted tools only |
hooks (command strings) |
Merged into --settings JSON alongside the internal Stop hook |
Restricted:
| Field | Restriction |
|---|---|
permission_mode |
Only bypassPermissions (default) and acceptEdits are accepted. default and plan would surface interactive permission prompts the harness can't answer, so they raise at construction |
can_use_tool |
Does not fire for built-in tools (Bash, Edit, etc.). Gate those statically via disallowed_tools (Layer 1) or settings.permissions.deny patterns (Layer 2) |
Not supported — raise at construction:
| Field | Reason |
|---|---|
hooks with Python callables |
No control-protocol channel for hook callbacks |
transport |
This package doesn't use the SDK's Transport abstraction |
debug_stderr |
Deprecated upstream |
Limited / best-effort:
| Field | Limitation |
|---|---|
include_partial_messages, include_hook_events |
Forwarded to the CLI, but the JSONL transcript may not emit the corresponding events |
agents, skills (inline dicts) |
Inline definitions use the control protocol — lost. File-based agents/skills in ~/.claude/agents / ~/.claude/skills work normally |
session_store |
Remote transcript mirroring not implemented |
Full details: docs/DESIGN.md §4, §10.
Implementation overview
claude runs in interactive mode inside a detached tmux session. Prompts go in via tmux paste-buffer; output comes back via the JSONL transcript that claude writes to <CLAUDE_CONFIG_DIR>/projects/<encoded-cwd>/<session-id>.jsonl. Turn termination is signalled by a Stop hook (installed via --settings) that writes to a FIFO the harness reads. User-defined tools are hosted in an in-process HTTP MCP server bound to an ephemeral localhost port. The harness wraps the launch in a stealth chain (env -u … script -q /dev/null setsid claude …) that strips harness-identifying env vars and gives the child a fresh PTY.
See docs/DESIGN.md for the full design including event-flow diagrams and rationale for each decision.
Development
make test # full test suite
make test-cov # with coverage
make lint # ruff
make format
make typecheck # mypy
make run-example NAME=01_hello_world
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_interactive_sdk-0.0.1.tar.gz.
File metadata
- Download URL: claude_interactive_sdk-0.0.1.tar.gz
- Upload date:
- Size: 127.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddf3491d7c72a4315e7bc0aadd0517bbbe81224587444da83a1066ff45579c9a
|
|
| MD5 |
faeb5bbbec36115dc191e04d617f9265
|
|
| BLAKE2b-256 |
dd497ec7a86112a450acb40d5bf6d02e34a3fb9caac57c61fc53bae1e06ce98e
|
File details
Details for the file claude_interactive_sdk-0.0.1-py3-none-any.whl.
File metadata
- Download URL: claude_interactive_sdk-0.0.1-py3-none-any.whl
- Upload date:
- Size: 21.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8df270fc2e07e28987b8d7eb381064502c5baa4f7cf7d0de25297a132866c4ed
|
|
| MD5 |
076dddfd3be255ed9c69ae3ea36c8b2c
|
|
| BLAKE2b-256 |
4397872e319840593c0c913804f50a78702a2f1e9b36817883de2f2783d62cf2
|