Skip to main content

Use local Claude Code CLI as a Pydantic AI model provider with full support for structured responses, tools, and streaming

Project description

Pydantic AI Claude Code

Use your local Claude Code CLI as a Pydantic AI model provider.

This package provides a Pydantic AI-compatible model implementation that wraps the local Claude CLI, enabling you to use Claude locally with all Pydantic AI features including structured responses, tool calling, streaming, and multi-turn conversations.

Features

  • Full Pydantic AI Compatibility: Drop-in replacement for any Pydantic AI model
  • Structured Responses: Get validated, typed responses using Pydantic models
  • Custom Tool Calling: Use your own Python functions as tools
  • True Streaming: Real-time response streaming via Claude CLI's stream-json mode
  • Local Execution: All processing happens locally on your machine
  • Session Persistence: Maintain conversation context across multiple requests
  • Additional Files: Provide local files for Claude to read and analyze
  • Automatic Response Saving: Raw prompts and responses saved for debugging
  • Configurable: Fine-tune permissions, working directories, and tool access

Installation

# Using uv (recommended)
uv add pydantic-ai-claude-code

# Using pip
pip install pydantic-ai-claude-code

Prerequisites: You must have Claude Code CLI installed and authenticated on your system.

Quick Start

Basic Usage (String Format - Simplest!)

import pydantic_ai_claude_code  # Register the provider

from pydantic_ai import Agent

# Just use the string format - easiest way!
agent = Agent('claude-code:sonnet')

# Run a simple query
result = agent.run_sync("What is 2+2?")
print(result.output)  # Output: 4

Structured Responses

import pydantic_ai_claude_code

from pydantic import BaseModel
from pydantic_ai import Agent

class Analysis(BaseModel):
    complexity: int  # 1-10
    maintainability: str
    suggestions: list[str]

# String format works with all Pydantic AI features
agent = Agent('claude-code:sonnet', output_type=Analysis)

result = agent.run_sync("Analyze this code: def foo(): pass")
print(f"Complexity: {result.output.complexity}")

Custom Tools

import pydantic_ai_claude_code

from pydantic_ai import Agent

def get_weather(city: str) -> str:
    """Get weather for a city."""
    return f"Weather in {city}: Sunny, 22°C"

agent = Agent(
    'claude-code:sonnet',
    tools=[get_weather],
)

result = agent.run_sync("What's the weather in Paris?")
print(result.output)

Streaming

import pydantic_ai_claude_code

from pydantic_ai import Agent

agent = Agent('claude-code:sonnet')

async with agent.run_stream('Write a haiku about code') as result:
    async for text in result.stream_text():
        print(text, end='', flush=True)

Advanced Configuration

When you need fine-grained control, use the explicit model and provider:

from pydantic_ai import Agent
from pydantic_ai_claude_code import ClaudeCodeModel, ClaudeCodeProvider

# Custom provider with specific settings
provider = ClaudeCodeProvider(
    working_directory="/path/to/project",
    allowed_tools=["Read", "Edit", "Grep"],  # Restrict tool access
    permission_mode="acceptEdits",
    use_temp_workspace=False,  # Use specific directory instead of /tmp
)

model = ClaudeCodeModel("sonnet", provider=provider)
agent = Agent(model)

result = agent.run_sync("Analyze the codebase structure")

Temporary Workspace

from pydantic_ai_claude_code import ClaudeCodeModel, ClaudeCodeProvider

# Create isolated workspace that auto-cleans
with ClaudeCodeProvider(use_temp_workspace=True) as provider:
    model = ClaudeCodeModel("sonnet", provider=provider)
    agent = Agent(model)
    result = agent.run_sync("Create a test file")
# Workspace automatically cleaned up

Providing Additional Files

Provide local files for Claude to read and analyze:

from pathlib import Path
from pydantic_ai import Agent

agent = Agent('claude-code:sonnet')

result = agent.run_sync(
    "Read utils.py and config.json. Summarize what they configure.",
    model_settings={
        "additional_files": {
            "utils.py": Path("src/utils.py"),           # Copy single file
            "config.json": Path("config/prod.json"),    # From different location
            "docs/spec.md": Path("specs/feature.md"),   # Into subdirectory
        }
    }
)

Files are copied into the working directory before execution, and Claude can reference them directly:

  • "Read utils.py"
  • "Read config.json"
  • "Read docs/spec.md"

Each execution gets its own numbered subdirectory with isolated file copies.

Error Handling

OAuth Token Expiration

For long-running processes (>7 hours), OAuth tokens may expire. Handle gracefully with ClaudeOAuthError:

from pydantic_ai import Agent
from pydantic_ai_claude_code import ClaudeOAuthError

agent = Agent('claude-code:sonnet')

try:
    result = agent.run_sync("Process large dataset")
except ClaudeOAuthError as e:
    print(f"Authentication expired: {e}")
    print(f"Please run: {e.reauth_instruction}")  # "Please run /login"
    # Prompt user to re-authenticate, then retry
except RuntimeError as e:
    # Handle other CLI errors
    print(f"CLI error: {e}")

For batch processing with automatic retry:

from pydantic_ai_claude_code import ClaudeOAuthError
import time

def process_batch_with_retry(items, max_auth_retries=3):
    """Process items with OAuth re-authentication support."""
    results = []

    for item in items:
        auth_retries = 0
        while auth_retries < max_auth_retries:
            try:
                result = agent.run_sync(f"Process: {item}")
                results.append(result.output)
                break  # Success

            except ClaudeOAuthError as e:
                auth_retries += 1
                print(f"\n{'='*60}")
                print(f"OAuth token expired: {e.reauth_instruction}")
                print(f"{'='*60}\n")

                if auth_retries >= max_auth_retries:
                    raise  # Give up after max retries

                input("Press Enter after running /login to continue...")
                time.sleep(2)  # Brief pause before retry

    return results

Logging

The package uses Python's standard logging module. To enable debug logging in your application:

import logging

# Enable debug logging for pydantic-ai-claude-code
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('pydantic_ai_claude_code').setLevel(logging.DEBUG)

# Or just for specific components
logging.getLogger('pydantic_ai_claude_code.model').setLevel(logging.DEBUG)
logging.getLogger('pydantic_ai_claude_code.utils').setLevel(logging.INFO)

This will log:

  • Model initialization and configuration
  • CLI command execution and responses
  • Message formatting and conversion
  • Tool call parsing and execution
  • Structured output handling
  • Streaming events and completion

Available Models

  • claude-code:sonnet - Claude 3.5 Sonnet (default, recommended)
  • claude-code:opus - Claude 3 Opus (most capable)
  • claude-code:haiku - Claude 3.5 Haiku (fastest)

Or use full model names like claude-code:claude-sonnet-4-5-20250929

Integration with Existing Projects

Replace your current LLM calls with Claude Code:

Before:

agent = Agent('openai:gpt-4o')
# or
agent = Agent('anthropic:claude-3-5-sonnet-latest')

After:

import pydantic_ai_claude_code  # Add this import

agent = Agent('claude-code:sonnet')  # Change this line

Everything else stays the same! All your tools, structured outputs, dependencies, and streaming code works identically.

Key Differences from Cloud Providers

Aspect Cloud Providers Claude Code Local
Execution Remote API calls Local on your machine
Cost Per-token pricing Uses Claude desktop subscription
Data Privacy Data sent to cloud Data stays local
Speed Network latency Local execution
API Key Required Not needed (uses local auth)

Examples

See the examples/ directory for more demonstrations:

  • basic_example.py - Simple queries and usage tracking
  • structured_example.py - Structured output with Pydantic models
  • async_example.py - Async/await usage patterns
  • advanced_example.py - Custom provider configurations
  • tools_and_streaming.py - Custom tools and streaming responses
  • additional_files_example.py - Providing local files for analysis

License

MIT License

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

pydantic_ai_claude_code-0.6.0.tar.gz (41.2 kB view details)

Uploaded Source

Built Distribution

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

pydantic_ai_claude_code-0.6.0-py3-none-any.whl (47.2 kB view details)

Uploaded Python 3

File details

Details for the file pydantic_ai_claude_code-0.6.0.tar.gz.

File metadata

File hashes

Hashes for pydantic_ai_claude_code-0.6.0.tar.gz
Algorithm Hash digest
SHA256 9c1a7b072bda539d5d68f64fcaff2cc0a29df93b7feb28715e770a6853a9d5a0
MD5 44061d992996b25298055c702f285d19
BLAKE2b-256 cae7978bc1f7e8da255d9c6e3c6d32dbde47c3c17a2af292565ee4cd028a92ea

See more details on using hashes here.

File details

Details for the file pydantic_ai_claude_code-0.6.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pydantic_ai_claude_code-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 05043ad9eb4531220d0088fd7c7d22e74570c9db1767be291372530285dc1fa7
MD5 302e11b6f88f16a4cafba30f697d189e
BLAKE2b-256 080090f0e3b377debd46b6046064749ad16462d513bc844c7b24e3b0f195f9e3

See more details on using hashes here.

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