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, thenclaude→ 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 sessions —
session_store="file": conversations survive process restarts (the prefix-cache lives in~/.langchain-claude-cli/); LangGraphthread_idis used as a recovery path when checkpointers trim history. - Persistent client —
persistent=True: a live CLI client per conversation (~2× faster reused turns), plusinterrupt()andset_session_model()for hot model swaps. - Typed errors —
ClaudeCliRateLimitError,ClaudeCliOverloadedError,ClaudeCliAuthError,ClaudeCliTimeoutError,ClaudeCliBudgetExceededError: build retry/fallback policies without parsing error text. Tip: setmax_retries=0if your own fallback layer should see raw errors. - OAuth guard —
auth="oauth"(default) neutralizes an inheritedANTHROPIC_API_KEY/ANTHROPIC_AUTH_TOKENso the CLI can never silently bill your API account instead of using your subscription.auth="inherit"opts out. - Rate-limit visibility —
response_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 blocks —
file_idsources 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) aclaude_codetool 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.
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
ClaudeCliCompatWarningtells 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
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 langchain_claude_cli-0.2.1.tar.gz.
File metadata
- Download URL: langchain_claude_cli-0.2.1.tar.gz
- Upload date:
- Size: 42.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
858fee16245ef4cb1cc25262bc4662caab579351999bb24e3eefc642442990fd
|
|
| MD5 |
abcd7e7e3ba0befa58c4d6bb18c8eea0
|
|
| BLAKE2b-256 |
31149fc42a1f3dd8187c368d93bf14f51cbad525ea9f22acc2c9d6f76970d1a1
|
Provenance
The following attestation bundles were made for langchain_claude_cli-0.2.1.tar.gz:
Publisher:
release.yml on clriesco/langchain-claude-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_claude_cli-0.2.1.tar.gz -
Subject digest:
858fee16245ef4cb1cc25262bc4662caab579351999bb24e3eefc642442990fd - Sigstore transparency entry: 2141808435
- Sigstore integration time:
-
Permalink:
clriesco/langchain-claude-cli@e0c03750a9264e694873742e6d4ebbb2b4232aa4 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/clriesco
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0c03750a9264e694873742e6d4ebbb2b4232aa4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file langchain_claude_cli-0.2.1-py3-none-any.whl.
File metadata
- Download URL: langchain_claude_cli-0.2.1-py3-none-any.whl
- Upload date:
- Size: 35.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
faa7ce913ffaf75eaeec409c944b3a3677c87eae7ba65e4868123ea8c377edd9
|
|
| MD5 |
1b84d86fcb85ee81efdb7b00faf859d9
|
|
| BLAKE2b-256 |
a17924676ca9ba4e273c2ff5b09c5fc7773a7f8bd83c09954cee11840a07bd9f
|
Provenance
The following attestation bundles were made for langchain_claude_cli-0.2.1-py3-none-any.whl:
Publisher:
release.yml on clriesco/langchain-claude-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_claude_cli-0.2.1-py3-none-any.whl -
Subject digest:
faa7ce913ffaf75eaeec409c944b3a3677c87eae7ba65e4868123ea8c377edd9 - Sigstore transparency entry: 2141808472
- Sigstore integration time:
-
Permalink:
clriesco/langchain-claude-cli@e0c03750a9264e694873742e6d4ebbb2b4232aa4 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/clriesco
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e0c03750a9264e694873742e6d4ebbb2b4232aa4 -
Trigger Event:
push
-
Statement type: