Skip to main content

Drop-in ChatAnthropic replacement backed by the Claude Code CLI — use your Claude Pro/Max subscription, no API key needed

Project description

langchain-claude-cli

Drop-in replacement for ChatAnthropic that runs on the Claude Code CLI — use your Claude Pro/Max subscription, no API key needed.

Built on the official claude-agent-sdk (≥ 0.2.115). Real tool calling via in-process MCP, native structured output, native extended thinking, real token usage — no prompt-injection hacks.

pip install langchain-claude-cli

Quick Start

from langchain_claude_cli import ChatClaudeCli

# Just like ChatAnthropic, but no API key
llm = ChatClaudeCli(model="claude-sonnet-4-5")
response = llm.invoke("What is the capital of France?")
print(response.content)
print(response.usage_metadata)   # real token usage, including cache tokens

Prerequisites

  • Claude Code CLI installed and authenticated: npm install -g @anthropic-ai/claude-code, then claude → log in
  • Claude Pro or Max subscription
  • Python ≥ 3.10, Node.js ≥ 18

Feature parity with ChatAnthropic

Every ChatAnthropic constructor parameter is accepted — nothing breaks on migration. Parity comes in three levels:

🟢 Level A — Native

Feature Notes
invoke / ainvoke / stream / astream / batch Real token-by-token streaming
Tool calling (bind_tools) Classic LangChain pattern: model returns AIMessage.tool_calls without executing. Parallel tool calls supported
with_structured_output CLI-native JSON-schema enforcement (output_format)
Extended thinking Same config dict as ChatAnthropic: thinking={"type": "enabled", "budget_tokens": N} — plus {"type": "adaptive"}
effort All five levels (max/xhigh/high/medium/low), passthrough
Token usage usage_metadata incl. cache_read/cache_creation details, plus total_cost_usd in response_metadata
stop_reason In response_metadata, like ChatAnthropic
Images (base64 + URL)
PDFs (document blocks)
System messages
MCP servers Both ChatAnthropic API-connector format and CLI-native (stdio/SSE/HTTP)
Server tools web_search / web_fetch Mapped to the CLI's built-in WebSearch/WebFetch
max_retries / timeout Client-side retry on 429/5xx; plus fallback_model
LangGraph agents create_agent / create_react_agent work end-to-end

🟡 Level B — Client-side workaround

Feature How
stop_sequences Output scanned client-side; stream is cut and truncated at the sequence
max_tokens Client-side truncation (~4 chars/token) with synthetic stop_reason="max_tokens"
tool_choice="any" / specific tool System-prompt instruction + validation + one retry; explicit error if not satisfied
get_num_tokens_from_messages Heuristic estimate (no count-tokens endpoint without an API key)
Arbitrary message histories See How conversations work below

🔴 Level C — Accepted no-op (warns once)

temperature, top_k, top_p, anthropic_api_url, anthropic_proxy, default_headers, inference_geo, context_management, cache_control blocks (the CLI caches automatically — you still get cache token counts), citations, computer use, strict tool use.

Tool calling — the classic LangChain pattern

Tools are registered as an in-process MCP server; a PreToolUse hook defers execution back to you. The model never executes your tools — it returns tool_calls, your code (or your LangGraph) executes them:

from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"25°C, sunny in {city}"

llm = ChatClaudeCli(model="claude-sonnet-4-5")
llm_with_tools = llm.bind_tools([get_weather])

response = llm_with_tools.invoke("What's the weather in Tokyo?")
response.tool_calls
# [{'name': 'get_weather', 'args': {'city': 'Tokyo'}, 'id': 'toolu_...'}]

Works out of the box with LangGraph:

from langgraph.prebuilt import create_react_agent

agent = create_react_agent(model=llm, tools=[get_weather])
agent.invoke({"messages": [{"role": "user", "content": "Weather in Colombo?"}]})

Structured output

from pydantic import BaseModel

class Answer(BaseModel):
    answer: str
    confidence: float

structured = llm.with_structured_output(Answer)
structured.invoke("What is the capital of France?")
# Answer(answer='Paris', confidence=0.99)

Uses the CLI's native output_format (JSON-schema enforced by the model runtime, not by prompt begging). include_raw=True and dict/TypedDict schemas are supported.

What's new in 0.2

  • Persistent sessionssession_store="file": conversations survive process restarts (the prefix-cache lives in ~/.langchain-claude-cli/); LangGraph thread_id is used as a recovery path when checkpointers trim history.
  • Persistent clientpersistent=True: a live CLI client per conversation (~2× faster reused turns), plus interrupt() and set_session_model() for hot model swaps.
  • Typed errorsClaudeCliRateLimitError, ClaudeCliOverloadedError, ClaudeCliAuthError, ClaudeCliTimeoutError, ClaudeCliBudgetExceededError: build retry/fallback policies without parsing error text. Tip: set max_retries=0 if your own fallback layer should see raw errors.
  • OAuth guardauth="oauth" (default) neutralizes an inherited ANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKEN so the CLI can never silently bill your API account instead of using your subscription. auth="inherit" opts out.
  • Rate-limit visibilityresponse_metadata["rate_limit"] reports your subscription window: {status, type, utilization, resets_at}.
  • history_mode="replay" — replay arbitrary histories with full role fidelity (costs one generation per historical user message).
  • Files API blocksfile_id sources are materialized via the Anthropic API when a key is available (used only for the download, never passed to the CLI) or dropped with a warning.
  • ClaudeCodeToolsMiddleware — give ANY LangChain agent (any provider as orchestrator) a claude_code tool that delegates filesystem/shell work to a sandboxed, budget-capped Claude Code run:
from langchain.agents import create_agent
from langchain_claude_cli.middleware import ClaudeCodeToolsMiddleware

agent = create_agent(
    model=any_chat_model,   # ChatOpenAI, ChatAnthropic, ChatClaudeCli...
    tools=[...],
    middleware=[ClaudeCodeToolsMiddleware(cwd="/workspace", max_budget_usd=0.5)],
)

Production tip: always set timeout — if the CLI process is killed mid-run (e.g. subscription rate-limit exhaustion) the SDK stream can hang instead of raising.

Reliability

  • Inactivity watchdog (0.3): if the SDK stream goes silent (inactivity_timeout, default 120s in pure-LLM mode, disabled in agentic mode where slow tools are legitimate), the run aborts with ClaudeCliTimeoutError and the subprocess is cleaned up — a dead CLI can otherwise leave the stream open forever (upstream issue).
  • Logging: enable logging.getLogger("langchain_claude_cli") at DEBUG to see session resolution, pool activity, tool defer/delivery and retries.
  • Deterministic tests: the core E2E suite runs against recorded cassettes (no CLI, no quota — tests/cassette_tests, refresh with RECORD_CASSETTES=1); a nightly contract suite checks the live CLI still honors the behavior invariants the design depends on.
  • history_mode="replay" is experimental: fidelity of injected assistant turns is race-dependent (contract finding).

How conversations work

BaseChatModel is stateless; the CLI is a stateful session. The bridge is a session prefix-cache:

  • A conversation that grows by appending (chatbots, agent loops, tool cycles) resumes its CLI session and sends only the new messages — full fidelity, and the CLI's automatic prompt caching keeps input tokens cheap.
  • An arbitrary history with no known prefix (e.g. trimmed or hand-built) is flattened into a single user message — role-labelled text, with image/document blocks preserved. A ClaudeCliCompatWarning tells you when this happens.
  • You can pin a CLI session explicitly: llm.invoke(..., config={"configurable": {"session_id": "<uuid>"}}).

Agentic mode (opt-in)

By default the model runs with no built-in tools — pure-LLM semantics, same risk profile as an API call. Opt in to Claude Code's agentic capabilities:

from langchain_claude_cli import ChatClaudeCli, READ_ONLY_TOOLS

# Read-only code analyst
analyst = ChatClaudeCli(
    model="claude-sonnet-4-5",
    builtin_tools=READ_ONLY_TOOLS,          # Read, Glob, Grep
    max_turns=10,
    permission_mode="bypassPermissions",
    cwd="/path/to/project",
)
analyst.invoke("Find all TODO comments and summarize them")

# Full agent (filesystem + bash) — trusted prompts only!
agent = ChatClaudeCli(
    model="claude-sonnet-4-5",
    builtin_tools="claude_code",            # everything
    permission_mode="bypassPermissions",
    max_budget_usd=1.0,                     # hard cost cap
    cwd="/path/to/project",
)

builtin_tools accepts a list of tool names / ClaudeTool enum values, or the "claude_code" preset. allowed_tools, disallowed_tools, add_dirs, sandbox and max_budget_usd map straight to the CLI. LangChain tools (deferred) and built-in tools (executed in-run) can be combined.

Agentic runs stream too: each built-in tool call the CLI executes is emitted as a tool_use content block in the stream, so you can render live activity ("→ Read data.txt") alongside the text tokens.

Security

With builtin_tools + bypassPermissions the CLI subprocess runs as your OS user: prompt injection becomes code execution, and cwd does not sandbox file access. Never enable agentic mode on untrusted input; prefer READ_ONLY_TOOLS, disallowed_tools=["Bash"], sandbox, and containers for production. Pure-LLM mode (the default) has none of these risks.

Migration

From ChatAnthropic

# Before
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-sonnet-4-5", api_key="sk-ant-...")

# After — everything else stays the same
from langchain_claude_cli import ChatClaudeCli
llm = ChatClaudeCli(model="claude-sonnet-4-5")

From langchain-claude-code (the old library)

Old (ChatClaudeCode) New (ChatClaudeCli)
ChatClaudeCode(...) ChatClaudeCli(...)
bind_tools via prompt injection Real MCP-based tool calling
thinking (prompt text hack) Native extended thinking
Token usage unavailable Full usage_metadata
max_turns=5 to enable tools builtin_tools=[...] (explicit opt-in)
History flattened to text Session resume with full fidelity

⚖️ Legal & Terms of Service

Disclaimer: community project, not affiliated with or endorsed by Anthropic. You are responsible for complying with Anthropic's terms.

This package uses the official, MIT-licensed claude-agent-sdk published by Anthropic — no reverse engineering, no credential extraction. Your usage is governed by Anthropic's Consumer Terms (Pro/Max) or Commercial Terms (API), and the Acceptable Use Policy. Notably: consumer subscriptions are for individual use, may not be resold or used to power products for end users, and heavy automated usage counts against your subscription's rate limits. For anything beyond personal/internal use, use an Anthropic API key under the Commercial Terms (and then you likely want langchain-anthropic directly).

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

langchain_claude_cli-0.3.0.tar.gz (64.6 kB view details)

Uploaded Source

Built Distribution

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

langchain_claude_cli-0.3.0-py3-none-any.whl (36.9 kB view details)

Uploaded Python 3

File details

Details for the file langchain_claude_cli-0.3.0.tar.gz.

File metadata

  • Download URL: langchain_claude_cli-0.3.0.tar.gz
  • Upload date:
  • Size: 64.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for langchain_claude_cli-0.3.0.tar.gz
Algorithm Hash digest
SHA256 335352eab2a79861164a1aecc044f3323db8885871cd7b136470d3bd2d316cfb
MD5 0f7d7c9dfec13b7823dd7da7de352f1b
BLAKE2b-256 0296acc943ebf78fe293c12121ecc8304704241d7f52aaf66aed4b1ee9a32aef

See more details on using hashes here.

Provenance

The following attestation bundles were made for langchain_claude_cli-0.3.0.tar.gz:

Publisher: release.yml on clriesco/langchain-claude-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file langchain_claude_cli-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for langchain_claude_cli-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 264c17d5448419d273d4289f15abc4dae7fb86fc2f07dd88f5052934c655c1a6
MD5 407bd9585a9420b4b07244dd0eb45a9b
BLAKE2b-256 deacda99ab3e50cafd8a5b2e51750a83f624f0279c3d6272d83f56eff49ed5d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for langchain_claude_cli-0.3.0-py3-none-any.whl:

Publisher: release.yml on clriesco/langchain-claude-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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