Skip to main content

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:

  1. Converts Pydantic AI messages → single prompt string
  2. Adds tool definitions with format instructions
  3. Adds JSON schema requirements for structured output
  4. Calls claude -p "prompt" --model sonnet via subprocess
  5. Parses response for tool calls or JSON output
  6. Returns typed ModelResponse to 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


Download files

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

Source Distribution

claude_code_model-0.4.4.tar.gz (229.2 kB view details)

Uploaded Source

Built Distribution

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

claude_code_model-0.4.4-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file claude_code_model-0.4.4.tar.gz.

File metadata

  • Download URL: claude_code_model-0.4.4.tar.gz
  • Upload date:
  • Size: 229.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for claude_code_model-0.4.4.tar.gz
Algorithm Hash digest
SHA256 3a6c4b0ea7cdbc525a980426e6b019bb9b31536ce51ea88a5ca61dede182a735
MD5 d16951ff71d97af8f04b5661c9b0ef10
BLAKE2b-256 4ddbbbe38975dcae7b3fb19f84b8bc7d6dee684242569bdfb762356e96b45a28

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_code_model-0.4.4.tar.gz:

Publisher: publish.yml on aleksandr-bogdanov/claude-code-model

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

File details

Details for the file claude_code_model-0.4.4-py3-none-any.whl.

File metadata

File hashes

Hashes for claude_code_model-0.4.4-py3-none-any.whl
Algorithm Hash digest
SHA256 5948103cb0bd3c86db347279e3ecad4edbd521f074152d323ee392051f276319
MD5 b98328f867041e4ff005a5d4c60150a4
BLAKE2b-256 3a19a936d5c50bfa8aac0eba4d613f31fe51e18c62844768572c2466e1b968c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_code_model-0.4.4-py3-none-any.whl:

Publisher: publish.yml on aleksandr-bogdanov/claude-code-model

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