Pydantic AI model adapter for Claude Code CLI
Project description
claude-code-model
Use Pydantic AI with your Claude Max subscription instead of paying per token.
A drop-in replacement that routes Pydantic AI through Claude Code CLI. Same code, same features, zero API costs.
The Problem
You want to use Pydantic AI for type-safe AI agents, but the API costs add up:
# This costs $3-15 per 1M tokens
from pydantic_ai.models.anthropic import AnthropicModel
model = AnthropicModel("claude-sonnet-4-20250514")
Meanwhile, your Claude Max subscription ($100-200/month) gives you unlimited Claude access via CLI, but no programmatic interface for building agents.
The Solution
claude-code-model bridges this gap. Change 2 lines and your Pydantic AI code runs on your Max subscription:
- from pydantic_ai.models.anthropic import AnthropicModel
- model = AnthropicModel("claude-sonnet-4-20250514")
+ from claude_code_model import ClaudeCodeModel
+ model = ClaudeCodeModel(model="sonnet")
That's it. Your agents, tools, schemas, and prompts stay exactly the same.
Quick Comparison
| Feature | Pydantic AI + API | claude-code-model |
|---|---|---|
| Cost | $3-15/M tokens | $0 (Max subscription) |
| Structured output | Yes | Yes |
| Tool calling | Yes | Yes |
| Vision / images | Yes | Yes (binary only) |
| Type safety | Yes | Yes |
| Streaming | Yes | No |
| Concurrent requests | Yes | No |
| Migration effort | — | 2 lines |
Installation
# 1. Install Claude Code CLI (requires Node.js)
npm install -g @anthropic-ai/claude-code
# 2. Login to Claude
claude auth
# 3. Install this package
pip install claude-code-model
Usage
Basic Example
from pydantic import BaseModel
from pydantic_ai import Agent
from claude_code_model import ClaudeCodeModel
class MovieReview(BaseModel):
title: str
rating: int # 1-10
summary: str
agent = Agent(
ClaudeCodeModel(),
output_type=MovieReview,
system_prompt="You are a film critic. Review movies concisely."
)
result = agent.run_sync("Review: The Matrix (1999)")
print(f"{result.output.title}: {result.output.rating}/10")
# The Matrix: 9/10
With Tools
from pydantic_ai import Agent
from claude_code_model import ClaudeCodeModel
agent = Agent(ClaudeCodeModel())
@agent.tool_plain
def get_weather(city: str) -> str:
"""Get current weather for a city."""
# Your implementation here
return f"Weather in {city}: 72°F, sunny"
result = agent.run_sync("What's the weather in Tokyo?")
# Agent calls get_weather("Tokyo") and uses the result
Vision / Image Input
from pydantic_ai import Agent
from pydantic_ai.messages import BinaryContent
from claude_code_model import ClaudeCodeModel
agent = Agent(
ClaudeCodeModel(),
system_prompt="Describe images concisely.",
)
# Load an image as binary content
image = BinaryContent.from_path("photo.jpg")
result = agent.run_sync(["What's in this image?", image])
print(result.output)
Images are sent to the CLI via stdin JSON format using --input-format stream-json. Multiple images can be passed in a single message.
Multi-Agent Systems
from pydantic_ai import Agent
from claude_code_model import ClaudeCodeModel
# Fast agent for simple tasks
fast_agent = Agent(
ClaudeCodeModel(model="haiku"),
system_prompt="Quick factual responses only."
)
# Powerful agent for complex reasoning
smart_agent = Agent(
ClaudeCodeModel(model="sonnet"),
system_prompt="Deep analysis and reasoning."
)
# Agents can delegate to each other via tools
@smart_agent.tool_plain
async def quick_lookup(query: str) -> str:
"""Delegate simple lookups to the fast agent."""
result = await fast_agent.run(query)
return result.output
See examples/multi_agent_comparison.py for a complete multi-agent pipeline.
Migration from Pydantic AI
Step 1: Install
pip install claude-code-model
Step 2: Replace Import
# Before
from pydantic_ai.models.anthropic import AnthropicModel
# After
from claude_code_model import ClaudeCodeModel
Step 3: Replace Model
# Before
model = AnthropicModel("claude-sonnet-4-20250514")
# After
model = ClaudeCodeModel(model="sonnet") # or "opus", "haiku"
That's It
All your existing code works unchanged:
# This code is IDENTICAL for both API and CLI
agent = Agent(
model, # <-- Only this changes
output_type=MySchema,
system_prompt="Your prompt here",
retries=3,
)
@agent.tool_plain
def my_tool(arg: str) -> str:
return do_something(arg)
result = agent.run_sync("Your query")
print(result.output) # Typed result
Configuration
from claude_code_model import ClaudeCodeModel
model = ClaudeCodeModel(
model="sonnet", # "sonnet" (default), "opus", or "haiku"
timeout=30, # Seconds per CLI request (default: 30)
verbose=False, # Enable debug logging
)
Model Selection
| Model | Speed | Capability | Use Case |
|---|---|---|---|
haiku |
Fast | Good | Simple tasks, quick lookups |
sonnet |
Medium | Great | Most tasks (default) |
opus |
Slow | Best | Complex reasoning, analysis |
Debug Mode
model = ClaudeCodeModel(verbose=True)
Shows request/response timing, prompts sent, tool calls detected, and JSON extraction status.
How It Works
Your Code claude-code-model Claude CLI
─────────────────────────────────────────────────────────────────────────
agent.run_sync("prompt") → Build prompt string → claude -p "..."
Add tool definitions --model sonnet
Add JSON schema
result.output ← Parse response ← {"rating": 9, ...}
Extract JSON
Validate with Pydantic
The adapter:
- Converts Pydantic AI messages → single prompt string
- Adds tool definitions with format instructions
- Adds JSON schema requirements for structured output
- Calls
claude -p "prompt" --model sonnetvia subprocess - Parses response for tool calls or JSON output
- Returns typed
ModelResponseto Pydantic AI
Examples
Run the examples to see it in action:
# Basic structured output
uv run python examples/simple.py
# Interactive tool usage
uv run python examples/with_tools.py
# Multi-agent pipeline with comparison
uv run python examples/multi_agent_comparison.py
Limitations
No streaming — CLI doesn't support streaming well. Each request returns complete.
No concurrent requests — Run one request at a time. CLI sessions don't parallelize.
No token counting — CLI doesn't report token usage. result.usage returns zeros.
Image URLs not supported — Only binary image data (BinaryContent) is supported. ImageUrl references are not sent to the CLI.
Slower than API — Each CLI invocation takes 2-10 seconds overhead. Multi-step tasks with tool calls take longer.
Tool calling is prompt-based — Unlike native API tools, this adapter instructs Claude to output TOOL_CALL: name({args}) format. Works well but occasionally needs retries. Use retries=3-5 on your agents.
Exceptions
from claude_code_model import (
ClaudeCodeError, # Base exception
ClaudeCodeNotFoundError, # CLI not installed
ClaudeCodeTimeoutError, # Request timed out
ClaudeCodeExecutionError, # CLI returned error
)
Development
git clone https://github.com/yourusername/claude-code-model.git
cd claude-code-model
uv sync
# Run tests
uv run pytest
# Type check
uv run mypy src/
# Lint
uv run ruff check src/ tests/
Requirements
- Python 3.11+
- Claude Code CLI installed and authenticated
- Claude Max subscription (for unlimited CLI access)
- pydantic-ai >= 0.1.0
- pydantic >= 2.0.0
License
MIT — see LICENSE.
Links
Disclaimer: Unofficial adapter, not affiliated with Anthropic. Use in accordance with Claude's Terms of Service.
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_code_model-0.4.2.tar.gz.
File metadata
- Download URL: claude_code_model-0.4.2.tar.gz
- Upload date:
- Size: 229.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e1931d5cf73de97651df5ff290e7a9126edb6a385c81d8d069ab496694e8303
|
|
| MD5 |
6d10cac80a50fed184336d14e3ab33a9
|
|
| BLAKE2b-256 |
5989c4a17941c9d9f977a48d97760c8865a1b29d91597633deac9f1b99193041
|
Provenance
The following attestation bundles were made for claude_code_model-0.4.2.tar.gz:
Publisher:
publish.yml on aleksandr-bogdanov/claude-code-model
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_code_model-0.4.2.tar.gz -
Subject digest:
8e1931d5cf73de97651df5ff290e7a9126edb6a385c81d8d069ab496694e8303 - Sigstore transparency entry: 1055402787
- Sigstore integration time:
-
Permalink:
aleksandr-bogdanov/claude-code-model@4d8839cba68f1bf588792542a0a371475a93436f -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/aleksandr-bogdanov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d8839cba68f1bf588792542a0a371475a93436f -
Trigger Event:
release
-
Statement type:
File details
Details for the file claude_code_model-0.4.2-py3-none-any.whl.
File metadata
- Download URL: claude_code_model-0.4.2-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48504c9da39f93b7dacba65f7343d95ede04ae336ef54b67b8a5860b5f87e1e1
|
|
| MD5 |
3aae620b901d05f8b6de2e25f4e2ca41
|
|
| BLAKE2b-256 |
d1dfcb6af56a0a2e882c7c6ba4bcb4b3cb5d0cd8d66632378612119782311bd4
|
Provenance
The following attestation bundles were made for claude_code_model-0.4.2-py3-none-any.whl:
Publisher:
publish.yml on aleksandr-bogdanov/claude-code-model
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_code_model-0.4.2-py3-none-any.whl -
Subject digest:
48504c9da39f93b7dacba65f7343d95ede04ae336ef54b67b8a5860b5f87e1e1 - Sigstore transparency entry: 1055402845
- Sigstore integration time:
-
Permalink:
aleksandr-bogdanov/claude-code-model@4d8839cba68f1bf588792542a0a371475a93436f -
Branch / Tag:
refs/tags/v0.4.2 - Owner: https://github.com/aleksandr-bogdanov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4d8839cba68f1bf588792542a0a371475a93436f -
Trigger Event:
release
-
Statement type: