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.3.tar.gz (229.0 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.3-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: claude_code_model-0.4.3.tar.gz
  • Upload date:
  • Size: 229.0 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.3.tar.gz
Algorithm Hash digest
SHA256 049cf752d2b55fe35ada9eff8862ed3ccc7f4db182fe3d62737772f59b3423d3
MD5 974cb79f9c559ff89e1f1f3884d8f644
BLAKE2b-256 0580a37d808a38a5eb493bc8bf36b9ae3f3efd9890f956f03bda5798a4415d61

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_code_model-0.4.3.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.3-py3-none-any.whl.

File metadata

File hashes

Hashes for claude_code_model-0.4.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d384a7264a7ce17525da8e5cf1fd6e1891b4e794efd87895765362345cfe2d18
MD5 26410087987c6c731a3ffb76f3a57c31
BLAKE2b-256 fdad8a35aa2ababcfbcf35300f8b69b84da09625c0c55680fe23b69e895a4417

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_code_model-0.4.3-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