Skip to main content

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 usage is billed against your Claude subscription rather than the API. Supports the full ClaudeAgentOptions API including function tools, MCP servers, system prompts, multi-turn conversations, model selection, and more.

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

pip install claude-interactive-sdk

Requires tmux and the claude CLI to be installed. Install tmux via your package manager:

# macOS
brew install tmux

# Ubuntu/Debian
sudo apt install tmux

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.

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.

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

claude_interactive_sdk-0.0.3.tar.gz (127.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

claude_interactive_sdk-0.0.3-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file claude_interactive_sdk-0.0.3.tar.gz.

File metadata

  • Download URL: claude_interactive_sdk-0.0.3.tar.gz
  • Upload date:
  • Size: 127.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for claude_interactive_sdk-0.0.3.tar.gz
Algorithm Hash digest
SHA256 fc2a7a16febf3956744167ea4ac8c2ba4302c63843c2bb97e5fcd7828f1862c1
MD5 7589cbbbc9941d337053158cdbe9d562
BLAKE2b-256 acf09fb51c4831dd524fa9eec29ce784857a9e078d086c2bb1e1bfbcae1a25da

See more details on using hashes here.

File details

Details for the file claude_interactive_sdk-0.0.3-py3-none-any.whl.

File metadata

File hashes

Hashes for claude_interactive_sdk-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 cb949ee075c276669d08141aa8856cfe5dd901222956cf7dc3a57296763f81f1
MD5 3a4d584b22730e635beddba916de5c29
BLAKE2b-256 063cadff49f905982cc5c3ce86e3dd60df001f1406f2b96216f2803ce1e4a182

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page