claude-code-langchain 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Moésio Filho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-code-langchain
3
+ Version: 0.1.0
4
+ Summary: LangChain chat model for Claude Code, built on the Claude Agent SDK
5
+ Keywords: langchain,claude,anthropic,claude-code,claude-agent-sdk
6
+ Author: Moésio Filho
7
+ Author-email: Moésio Filho <moesio.f@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Requires-Dist: claude-agent-sdk>=0.2.0
19
+ Requires-Dist: langchain-core>=1.0.0,<2.0.0
20
+ Requires-Python: >=3.10
21
+ Project-URL: Homepage, https://github.com/moesio-f/claude-code-langchain
22
+ Project-URL: Repository, https://github.com/moesio-f/claude-code-langchain
23
+ Project-URL: Issues, https://github.com/moesio-f/claude-code-langchain/issues
24
+ Description-Content-Type: text/markdown
25
+
26
+ # claude-code-langchain
27
+
28
+ [![PyPI version](https://img.shields.io/pypi/v/claude-code-langchain.svg)](https://pypi.org/project/claude-code-langchain/)
29
+ [![Python versions](https://img.shields.io/pypi/pyversions/claude-code-langchain.svg)](https://pypi.org/project/claude-code-langchain/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/moesio-f/claude-code-langchain/blob/main/LICENSE)
31
+
32
+ A LangChain chat model that runs Claude through the **Claude Code CLI**, using the
33
+ [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python).
34
+
35
+ > **Not affiliated with Anthropic.** This is an independent community project.
36
+ > "Anthropic", "Claude", and "Claude Code" are trademarks of Anthropic PBC.
37
+
38
+ Authentication is delegated entirely to the `claude` CLI, so the model runs with whatever
39
+ the CLI is already configured with. For products or services that serve other users,
40
+ Anthropic requires API-key authentication — see the
41
+ [Claude Code legal and compliance page](https://code.claude.com/docs/en/legal-and-compliance).
42
+
43
+ > Built on the ideas of [ChamaruAmasara/langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code),
44
+ > rewritten for the current stack: the new `claude-agent-sdk` (replacing the deprecated
45
+ > `claude-code-sdk`) and LangChain 1.0+.
46
+
47
+ ## What the rewrite changes
48
+
49
+ | Area | Original (`claude-code-sdk`) | Here (`claude-agent-sdk`) |
50
+ |---|---|---|
51
+ | SDK options | `ClaudeCodeOptions` | `ClaudeAgentOptions` |
52
+ | Tool calling | Tool schemas injected into the system prompt, JSON parsed out of the reply | Real Anthropic tool use: tools are served over an in-process MCP server, so `AIMessage.tool_calls` comes from actual `tool_use` blocks |
53
+ | Structured output | Prompted, best-effort | The CLI's `--json-schema` output format, validated against your schema |
54
+ | Extended thinking | A "think step by step" hint appended to the prompt | The SDK's native `thinking` config, returned as a `reasoning` content block |
55
+ | Effort | `--effort` via `extra_args` | First-class `effort` option, `low` → `max` |
56
+ | Token usage | Not available | `usage_metadata`, including cache reads/writes, plus cost in `response_metadata` |
57
+ | Built-in tools | Implicitly on, gated by `max_turns` | Explicit `builtin_tools`; off by default, so plain chat stays plain |
58
+ | LangChain | 0.3 | 1.0+ (v1 content blocks, `usage_metadata`, standard `bind_tools` / `with_structured_output`) |
59
+
60
+ ## Requirements
61
+
62
+ - Python 3.10+
63
+ - Node.js 18+ and the Claude Code CLI: `npm install -g @anthropic-ai/claude-code && claude`
64
+ - The CLI authenticated with the method you intend to use (API key, Claude subscription, or
65
+ a supported cloud provider)
66
+
67
+ ```bash
68
+ pip install claude-code-langchain
69
+ ```
70
+
71
+ ## Quick start
72
+
73
+ ```python
74
+ from claude_code_langchain import ChatClaudeCode
75
+
76
+ llm = ChatClaudeCode(model="claude-opus-5")
77
+ print(llm.invoke("What is the capital of France?").text)
78
+ ```
79
+
80
+ `model` accepts a model id (`claude-opus-5`, `claude-sonnet-5`, `claude-haiku-4-5`) or a CLI
81
+ alias (`opus`, `sonnet`, `haiku`). Leave it unset to use whatever the CLI is configured with.
82
+
83
+ ### Messages, streaming, async
84
+
85
+ ```python
86
+ from langchain_core.messages import HumanMessage, SystemMessage
87
+
88
+ llm.invoke([SystemMessage("Be concise."), HumanMessage("Explain generators.")])
89
+
90
+ for chunk in llm.stream("Count from 1 to 5"):
91
+ print(chunk.text, end="", flush=True)
92
+
93
+ await llm.ainvoke("Hello") # also: astream, batch, abatch
94
+ ```
95
+
96
+ ### Tool calling
97
+
98
+ ```python
99
+ from langchain_core.tools import tool
100
+
101
+
102
+ @tool
103
+ def get_weather(city: str) -> str:
104
+ """Get the weather for a city."""
105
+ return "12C and sunny"
106
+
107
+
108
+ response = llm.bind_tools([get_weather]).invoke("What is the weather in Paris?")
109
+ response.tool_calls
110
+ # [{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': 'toolu_…', 'type': 'tool_call'}]
111
+ ```
112
+
113
+ Your tools are exposed to the CLI over an in-process MCP server, but they are never executed
114
+ there — the call is handed back to you, exactly like any other LangChain chat model, so it
115
+ works with LangGraph's `create_agent` and the usual `ToolNode` loop.
116
+
117
+ ### Structured output
118
+
119
+ ```python
120
+ from pydantic import BaseModel
121
+
122
+
123
+ class Person(BaseModel):
124
+ """A person."""
125
+
126
+ name: str
127
+ age: int
128
+
129
+
130
+ llm.with_structured_output(Person).invoke("Bob is 42.")
131
+ # Person(name='Bob', age=42)
132
+ ```
133
+
134
+ This uses the CLI's native JSON-schema output mode, so the response is constrained rather
135
+ than merely requested. Pass `include_raw=True` to get `{"raw", "parsed", "parsing_error"}`.
136
+
137
+ ### Thinking and effort
138
+
139
+ ```python
140
+ llm = ChatClaudeCode(
141
+ model="claude-opus-5",
142
+ thinking={"type": "adaptive", "display": "summarized"},
143
+ effort="high",
144
+ )
145
+ message = llm.invoke("Prove that sqrt(2) is irrational.")
146
+ message.content # [{'type': 'reasoning', ...}, {'type': 'text', ...}]
147
+ message.text # just the answer
148
+ ```
149
+
150
+ ### Agentic mode
151
+
152
+ Claude Code's own tools are **off by default**, so the model behaves like a normal chat model.
153
+ Turn them on when you want an agent that can touch your filesystem:
154
+
155
+ ```python
156
+ from claude_code_langchain import READ_ONLY_TOOLS, ChatClaudeCode, ClaudeTool
157
+
158
+ reader = ChatClaudeCode(
159
+ builtin_tools=READ_ONLY_TOOLS, # Read, Glob, Grep
160
+ allowed_tools=READ_ONLY_TOOLS, # run without asking for permission
161
+ max_turns=10,
162
+ cwd="/path/to/project",
163
+ )
164
+ reader.invoke("Find every TODO comment in this project")
165
+
166
+ full = ChatClaudeCode(
167
+ builtin_tools="claude_code", # the complete Claude Code toolset
168
+ permission_mode="acceptEdits",
169
+ max_turns=20,
170
+ cwd="/path/to/project",
171
+ )
172
+ ```
173
+
174
+ Presets: `READ_ONLY_TOOLS`, `WRITE_TOOLS`, `SHELL_TOOLS`, `NETWORK_TOOLS`, `ALL_TOOLS`, plus the
175
+ `ClaudeTool` enum for individual names.
176
+
177
+ ### Sessions
178
+
179
+ Every response carries the CLI session id, which you can resume later:
180
+
181
+ ```python
182
+ first = llm.invoke("Remember the number 7.")
183
+ session = first.response_metadata["session_id"]
184
+
185
+ resumed = ChatClaudeCode(session_id=session).invoke("What number did I mention?")
186
+ ```
187
+
188
+ ## Configuration
189
+
190
+ | Option | Purpose |
191
+ |---|---|
192
+ | `model`, `system_prompt` | Model id/alias; system prompt used when no `SystemMessage` is present |
193
+ | `thinking`, `effort` | Extended thinking config; `low` / `medium` / `high` / `xhigh` / `max` |
194
+ | `max_turns`, `max_budget_usd` | Agent loop limits (defaults to a single turn) |
195
+ | `builtin_tools`, `allowed_tools`, `disallowed_tools`, `permission_mode` | Which Claude Code tools exist, which run unattended, and how permissions are handled |
196
+ | `mcp_servers` | Additional MCP servers for the session |
197
+ | `cwd`, `add_dirs`, `env`, `cli_path`, `settings`, `setting_sources` | Where and how the CLI subprocess runs |
198
+ | `session_id`, `fork_session` | Resume or branch a previous session |
199
+ | `extra_args` | Any other CLI flag |
200
+
201
+ `setting_sources` defaults to `[]` so a run is not affected by your local Claude settings or
202
+ `CLAUDE.md`. Pass `None` to load user, project and local settings like the interactive CLI.
203
+
204
+ ## Compared with `ChatAnthropic`
205
+
206
+ | Feature | `ChatAnthropic` | `ChatClaudeCode` |
207
+ |---|---|---|
208
+ | `invoke` / `stream` / `batch` / async | ✅ | ✅ |
209
+ | System messages, image input | ✅ | ✅ |
210
+ | Tool calling, structured output | ✅ | ✅ |
211
+ | Extended thinking, effort | ✅ | ✅ |
212
+ | Token usage and cost | ✅ | ✅ (plus USD cost per call) |
213
+ | Authentication | API key | Delegated to the `claude` CLI |
214
+ | Built-in filesystem/bash/web tools, MCP servers, subagents, skills | ❌ | ✅ |
215
+ | `temperature`, `top_p`, `top_k`, `stop` | ✅ | Accepted for compatibility, ignored by the CLI |
216
+ | Multi-turn history | Sent verbatim | Flattened into one prompt (see below) |
217
+
218
+ ### Known limitations
219
+
220
+ - The CLI owns conversation state, so a message list is flattened into a single prompt with
221
+ labelled turns. Prior tool calls and results are rendered as text. Use `session_id` when you
222
+ want the CLI's own memory of a conversation instead.
223
+ - Sampling parameters and stop sequences are not exposed by the CLI.
224
+ - Streaming yields text only; thinking arrives on the final non-streamed message.
225
+ - Each call spawns a `claude` subprocess, so latency is higher than a direct API call.
226
+
227
+ ## Development
228
+
229
+ ```bash
230
+ uv sync --group dev
231
+ uv run pytest # unit tests, no CLI needed
232
+ uv run ruff check . && uv run mypy src
233
+ CLAUDE_CODE_LANGCHAIN_INTEGRATION=1 uv run pytest tests/integration # runs the CLI
234
+ ```
235
+
236
+ ## Related projects
237
+
238
+ Other LangChain adapters for Claude Code:
239
+
240
+ | Project | Notes |
241
+ |---|---|
242
+ | [ChamaruAmasara/langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code) | The original project this one was inspired by; on PyPI as `langchain-claude-code-cli` |
243
+ | [thehumanworks/langchain-claude-code](https://github.com/thehumanworks/langchain-claude-code) | Wrapper for the Claude Agent SDK; on PyPI as `langchain-claude-code` |
244
+ | [brhodes/langchain-claude-agent-sdk](https://codeberg.org/brhodes/langchain-claude-agent-sdk) | `langchain-claude-agent-sdk` on PyPI (hosted on Codeberg rather than GitHub) |
245
+ | [langchain-ai/langchain#40131](https://github.com/langchain-ai/langchain/issues/40131) | Proposal to add an Agent SDK-backed model to `langchain-anthropic` |
246
+
247
+ Each takes a different approach to authentication and conversation state. Some accept OAuth
248
+ tokens directly; review the auth method and Anthropic's terms before using one in production.
249
+
250
+ ## Credits
251
+
252
+ Original project: [langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code)
253
+ by Chamaru Amasara. This package is an independent rewrite on the Claude Agent SDK and
254
+ LangChain 1.0+.
@@ -0,0 +1,229 @@
1
+ # claude-code-langchain
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/claude-code-langchain.svg)](https://pypi.org/project/claude-code-langchain/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/claude-code-langchain.svg)](https://pypi.org/project/claude-code-langchain/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/moesio-f/claude-code-langchain/blob/main/LICENSE)
6
+
7
+ A LangChain chat model that runs Claude through the **Claude Code CLI**, using the
8
+ [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-python).
9
+
10
+ > **Not affiliated with Anthropic.** This is an independent community project.
11
+ > "Anthropic", "Claude", and "Claude Code" are trademarks of Anthropic PBC.
12
+
13
+ Authentication is delegated entirely to the `claude` CLI, so the model runs with whatever
14
+ the CLI is already configured with. For products or services that serve other users,
15
+ Anthropic requires API-key authentication — see the
16
+ [Claude Code legal and compliance page](https://code.claude.com/docs/en/legal-and-compliance).
17
+
18
+ > Built on the ideas of [ChamaruAmasara/langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code),
19
+ > rewritten for the current stack: the new `claude-agent-sdk` (replacing the deprecated
20
+ > `claude-code-sdk`) and LangChain 1.0+.
21
+
22
+ ## What the rewrite changes
23
+
24
+ | Area | Original (`claude-code-sdk`) | Here (`claude-agent-sdk`) |
25
+ |---|---|---|
26
+ | SDK options | `ClaudeCodeOptions` | `ClaudeAgentOptions` |
27
+ | Tool calling | Tool schemas injected into the system prompt, JSON parsed out of the reply | Real Anthropic tool use: tools are served over an in-process MCP server, so `AIMessage.tool_calls` comes from actual `tool_use` blocks |
28
+ | Structured output | Prompted, best-effort | The CLI's `--json-schema` output format, validated against your schema |
29
+ | Extended thinking | A "think step by step" hint appended to the prompt | The SDK's native `thinking` config, returned as a `reasoning` content block |
30
+ | Effort | `--effort` via `extra_args` | First-class `effort` option, `low` → `max` |
31
+ | Token usage | Not available | `usage_metadata`, including cache reads/writes, plus cost in `response_metadata` |
32
+ | Built-in tools | Implicitly on, gated by `max_turns` | Explicit `builtin_tools`; off by default, so plain chat stays plain |
33
+ | LangChain | 0.3 | 1.0+ (v1 content blocks, `usage_metadata`, standard `bind_tools` / `with_structured_output`) |
34
+
35
+ ## Requirements
36
+
37
+ - Python 3.10+
38
+ - Node.js 18+ and the Claude Code CLI: `npm install -g @anthropic-ai/claude-code && claude`
39
+ - The CLI authenticated with the method you intend to use (API key, Claude subscription, or
40
+ a supported cloud provider)
41
+
42
+ ```bash
43
+ pip install claude-code-langchain
44
+ ```
45
+
46
+ ## Quick start
47
+
48
+ ```python
49
+ from claude_code_langchain import ChatClaudeCode
50
+
51
+ llm = ChatClaudeCode(model="claude-opus-5")
52
+ print(llm.invoke("What is the capital of France?").text)
53
+ ```
54
+
55
+ `model` accepts a model id (`claude-opus-5`, `claude-sonnet-5`, `claude-haiku-4-5`) or a CLI
56
+ alias (`opus`, `sonnet`, `haiku`). Leave it unset to use whatever the CLI is configured with.
57
+
58
+ ### Messages, streaming, async
59
+
60
+ ```python
61
+ from langchain_core.messages import HumanMessage, SystemMessage
62
+
63
+ llm.invoke([SystemMessage("Be concise."), HumanMessage("Explain generators.")])
64
+
65
+ for chunk in llm.stream("Count from 1 to 5"):
66
+ print(chunk.text, end="", flush=True)
67
+
68
+ await llm.ainvoke("Hello") # also: astream, batch, abatch
69
+ ```
70
+
71
+ ### Tool calling
72
+
73
+ ```python
74
+ from langchain_core.tools import tool
75
+
76
+
77
+ @tool
78
+ def get_weather(city: str) -> str:
79
+ """Get the weather for a city."""
80
+ return "12C and sunny"
81
+
82
+
83
+ response = llm.bind_tools([get_weather]).invoke("What is the weather in Paris?")
84
+ response.tool_calls
85
+ # [{'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': 'toolu_…', 'type': 'tool_call'}]
86
+ ```
87
+
88
+ Your tools are exposed to the CLI over an in-process MCP server, but they are never executed
89
+ there — the call is handed back to you, exactly like any other LangChain chat model, so it
90
+ works with LangGraph's `create_agent` and the usual `ToolNode` loop.
91
+
92
+ ### Structured output
93
+
94
+ ```python
95
+ from pydantic import BaseModel
96
+
97
+
98
+ class Person(BaseModel):
99
+ """A person."""
100
+
101
+ name: str
102
+ age: int
103
+
104
+
105
+ llm.with_structured_output(Person).invoke("Bob is 42.")
106
+ # Person(name='Bob', age=42)
107
+ ```
108
+
109
+ This uses the CLI's native JSON-schema output mode, so the response is constrained rather
110
+ than merely requested. Pass `include_raw=True` to get `{"raw", "parsed", "parsing_error"}`.
111
+
112
+ ### Thinking and effort
113
+
114
+ ```python
115
+ llm = ChatClaudeCode(
116
+ model="claude-opus-5",
117
+ thinking={"type": "adaptive", "display": "summarized"},
118
+ effort="high",
119
+ )
120
+ message = llm.invoke("Prove that sqrt(2) is irrational.")
121
+ message.content # [{'type': 'reasoning', ...}, {'type': 'text', ...}]
122
+ message.text # just the answer
123
+ ```
124
+
125
+ ### Agentic mode
126
+
127
+ Claude Code's own tools are **off by default**, so the model behaves like a normal chat model.
128
+ Turn them on when you want an agent that can touch your filesystem:
129
+
130
+ ```python
131
+ from claude_code_langchain import READ_ONLY_TOOLS, ChatClaudeCode, ClaudeTool
132
+
133
+ reader = ChatClaudeCode(
134
+ builtin_tools=READ_ONLY_TOOLS, # Read, Glob, Grep
135
+ allowed_tools=READ_ONLY_TOOLS, # run without asking for permission
136
+ max_turns=10,
137
+ cwd="/path/to/project",
138
+ )
139
+ reader.invoke("Find every TODO comment in this project")
140
+
141
+ full = ChatClaudeCode(
142
+ builtin_tools="claude_code", # the complete Claude Code toolset
143
+ permission_mode="acceptEdits",
144
+ max_turns=20,
145
+ cwd="/path/to/project",
146
+ )
147
+ ```
148
+
149
+ Presets: `READ_ONLY_TOOLS`, `WRITE_TOOLS`, `SHELL_TOOLS`, `NETWORK_TOOLS`, `ALL_TOOLS`, plus the
150
+ `ClaudeTool` enum for individual names.
151
+
152
+ ### Sessions
153
+
154
+ Every response carries the CLI session id, which you can resume later:
155
+
156
+ ```python
157
+ first = llm.invoke("Remember the number 7.")
158
+ session = first.response_metadata["session_id"]
159
+
160
+ resumed = ChatClaudeCode(session_id=session).invoke("What number did I mention?")
161
+ ```
162
+
163
+ ## Configuration
164
+
165
+ | Option | Purpose |
166
+ |---|---|
167
+ | `model`, `system_prompt` | Model id/alias; system prompt used when no `SystemMessage` is present |
168
+ | `thinking`, `effort` | Extended thinking config; `low` / `medium` / `high` / `xhigh` / `max` |
169
+ | `max_turns`, `max_budget_usd` | Agent loop limits (defaults to a single turn) |
170
+ | `builtin_tools`, `allowed_tools`, `disallowed_tools`, `permission_mode` | Which Claude Code tools exist, which run unattended, and how permissions are handled |
171
+ | `mcp_servers` | Additional MCP servers for the session |
172
+ | `cwd`, `add_dirs`, `env`, `cli_path`, `settings`, `setting_sources` | Where and how the CLI subprocess runs |
173
+ | `session_id`, `fork_session` | Resume or branch a previous session |
174
+ | `extra_args` | Any other CLI flag |
175
+
176
+ `setting_sources` defaults to `[]` so a run is not affected by your local Claude settings or
177
+ `CLAUDE.md`. Pass `None` to load user, project and local settings like the interactive CLI.
178
+
179
+ ## Compared with `ChatAnthropic`
180
+
181
+ | Feature | `ChatAnthropic` | `ChatClaudeCode` |
182
+ |---|---|---|
183
+ | `invoke` / `stream` / `batch` / async | ✅ | ✅ |
184
+ | System messages, image input | ✅ | ✅ |
185
+ | Tool calling, structured output | ✅ | ✅ |
186
+ | Extended thinking, effort | ✅ | ✅ |
187
+ | Token usage and cost | ✅ | ✅ (plus USD cost per call) |
188
+ | Authentication | API key | Delegated to the `claude` CLI |
189
+ | Built-in filesystem/bash/web tools, MCP servers, subagents, skills | ❌ | ✅ |
190
+ | `temperature`, `top_p`, `top_k`, `stop` | ✅ | Accepted for compatibility, ignored by the CLI |
191
+ | Multi-turn history | Sent verbatim | Flattened into one prompt (see below) |
192
+
193
+ ### Known limitations
194
+
195
+ - The CLI owns conversation state, so a message list is flattened into a single prompt with
196
+ labelled turns. Prior tool calls and results are rendered as text. Use `session_id` when you
197
+ want the CLI's own memory of a conversation instead.
198
+ - Sampling parameters and stop sequences are not exposed by the CLI.
199
+ - Streaming yields text only; thinking arrives on the final non-streamed message.
200
+ - Each call spawns a `claude` subprocess, so latency is higher than a direct API call.
201
+
202
+ ## Development
203
+
204
+ ```bash
205
+ uv sync --group dev
206
+ uv run pytest # unit tests, no CLI needed
207
+ uv run ruff check . && uv run mypy src
208
+ CLAUDE_CODE_LANGCHAIN_INTEGRATION=1 uv run pytest tests/integration # runs the CLI
209
+ ```
210
+
211
+ ## Related projects
212
+
213
+ Other LangChain adapters for Claude Code:
214
+
215
+ | Project | Notes |
216
+ |---|---|
217
+ | [ChamaruAmasara/langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code) | The original project this one was inspired by; on PyPI as `langchain-claude-code-cli` |
218
+ | [thehumanworks/langchain-claude-code](https://github.com/thehumanworks/langchain-claude-code) | Wrapper for the Claude Agent SDK; on PyPI as `langchain-claude-code` |
219
+ | [brhodes/langchain-claude-agent-sdk](https://codeberg.org/brhodes/langchain-claude-agent-sdk) | `langchain-claude-agent-sdk` on PyPI (hosted on Codeberg rather than GitHub) |
220
+ | [langchain-ai/langchain#40131](https://github.com/langchain-ai/langchain/issues/40131) | Proposal to add an Agent SDK-backed model to `langchain-anthropic` |
221
+
222
+ Each takes a different approach to authentication and conversation state. Some accept OAuth
223
+ tokens directly; review the auth method and Anthropic's terms before using one in production.
224
+
225
+ ## Credits
226
+
227
+ Original project: [langchain-claude-code](https://github.com/ChamaruAmasara/langchain-claude-code)
228
+ by Chamaru Amasara. This package is an independent rewrite on the Claude Agent SDK and
229
+ LangChain 1.0+.
@@ -0,0 +1,86 @@
1
+ [project]
2
+ name = "claude-code-langchain"
3
+ version = "0.1.0"
4
+ description = "LangChain chat model for Claude Code, built on the Claude Agent SDK"
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ readme = "README.md"
8
+ requires-python = ">=3.10"
9
+ keywords = [
10
+ "langchain",
11
+ "claude",
12
+ "anthropic",
13
+ "claude-code",
14
+ "claude-agent-sdk",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries",
25
+ ]
26
+ dependencies = [
27
+ "claude-agent-sdk>=0.2.0",
28
+ "langchain-core>=1.0.0,<2.0.0",
29
+ ]
30
+
31
+ [[project.authors]]
32
+ name = "Moésio Filho"
33
+ email = "moesio.f@gmail.com"
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/moesio-f/claude-code-langchain"
37
+ Repository = "https://github.com/moesio-f/claude-code-langchain"
38
+ Issues = "https://github.com/moesio-f/claude-code-langchain/issues"
39
+
40
+ [build-system]
41
+ requires = ["uv_build>=0.11.30,<0.12.0"]
42
+ build-backend = "uv_build"
43
+
44
+ [dependency-groups]
45
+ dev = [
46
+ "mypy>=1.18",
47
+ "pytest>=8.4",
48
+ "pytest-asyncio>=1.0",
49
+ "ruff>=0.13",
50
+ ]
51
+
52
+ [tool.pytest.ini_options]
53
+ asyncio_mode = "auto"
54
+ testpaths = ["tests"]
55
+
56
+ [tool.ruff.lint]
57
+ select = [
58
+ "E",
59
+ "F",
60
+ "I",
61
+ "UP",
62
+ "B",
63
+ "SIM",
64
+ "D",
65
+ ]
66
+ ignore = [
67
+ "D100",
68
+ "D107",
69
+ "D203",
70
+ "D213",
71
+ ]
72
+
73
+ [tool.ruff.lint.pydocstyle]
74
+ convention = "google"
75
+
76
+ [tool.ruff.lint.per-file-ignores]
77
+ "tests/**" = ["D"]
78
+
79
+ [tool.mypy]
80
+ plugins = ["pydantic.mypy"]
81
+ disallow_untyped_defs = true
82
+ warn_return_any = false
83
+
84
+ [[tool.mypy.overrides]]
85
+ module = "tests.*"
86
+ disallow_untyped_defs = false
@@ -0,0 +1,64 @@
1
+ [project]
2
+ name = "claude-code-langchain"
3
+ version = "0.1.0"
4
+ description = "LangChain chat model for Claude Code, built on the Claude Agent SDK"
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ readme = "README.md"
8
+ authors = [
9
+ { name = "Moésio Filho", email = "moesio.f@gmail.com" }
10
+ ]
11
+ requires-python = ">=3.10"
12
+ keywords = ["langchain", "claude", "anthropic", "claude-code", "claude-agent-sdk"]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: Software Development :: Libraries",
22
+ ]
23
+ dependencies = [
24
+ "claude-agent-sdk>=0.2.0",
25
+ "langchain-core>=1.0.0,<2.0.0",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/moesio-f/claude-code-langchain"
30
+ Repository = "https://github.com/moesio-f/claude-code-langchain"
31
+ Issues = "https://github.com/moesio-f/claude-code-langchain/issues"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.11.30,<0.12.0"]
35
+ build-backend = "uv_build"
36
+
37
+ [dependency-groups]
38
+ dev = [
39
+ "mypy>=1.18",
40
+ "pytest>=8.4",
41
+ "pytest-asyncio>=1.0",
42
+ "ruff>=0.13",
43
+ ]
44
+
45
+ [tool.pytest.ini_options]
46
+ asyncio_mode = "auto"
47
+ testpaths = ["tests"]
48
+
49
+ [tool.ruff.lint]
50
+ select = ["E", "F", "I", "UP", "B", "SIM", "D"]
51
+ ignore = ["D100", "D107", "D203", "D213"]
52
+ pydocstyle.convention = "google"
53
+
54
+ [tool.ruff.lint.per-file-ignores]
55
+ "tests/**" = ["D"]
56
+
57
+ [tool.mypy]
58
+ plugins = ["pydantic.mypy"]
59
+ disallow_untyped_defs = true
60
+ warn_return_any = false
61
+
62
+ [[tool.mypy.overrides]]
63
+ module = "tests.*"
64
+ disallow_untyped_defs = false