Skip to main content

pydantic-claude-code

Use your Claude Code subscription from a plain pydantic-ai Agent, with full pydantic-ai tool support. No API key, no separate billing: if Claude Code works from your terminal, this wheel works too.

The repo is mpfaffenberger/pydantic-ai-claude-code and the import is pydantic_ai_claude_code; the PyPI project is pydantic-claude-code (pip install pydantic-claude-code).

Why

pydantic-ai gained a Codex OAuth path where openai-codex:gpt-6-astra just works against a ChatGPT subscription. This wheel brings the same experience to Claude: authenticate once, then run pydantic-ai agents against your Claude subscription, using claude-fable-5-1, claude-sonnet-5, claude-opus-5, or whatever model you subscribe to.

Two deliberate design choices distinguish this from a fork of pydantic-ai:

  1. pydantic-ai owns the loop. We don't hand the whole agent loop to the Claude Code CLI. pydantic-ai's own Agent machinery drives the conversation, executes your tools, and validates structured output. The wheel is a model
    • provider, not a second agent fighting for control.
  2. Object-only resolution. Instead of a claude-code: model-name string (which would require patching pydantic-ai's internals), construct a ClaudeCodeModel('claude-fable-5-1') directly; it wires itself up to a ClaudeCodeProvider by default.

Quick start

import asyncio

from pydantic_ai import Agent

from pydantic_ai_claude_code import ClaudeCodeModel, login

async def main() -> None:
    # One-time: opens your browser, mints tokens, stores them
    # (only needs to run again when tokens are revoked).
    await login()

    agent = Agent(ClaudeCodeModel('claude-fable-5-1'))

    result = await agent.run('Say hi in three words.')
    print(result.data)

asyncio.run(main())

With tools

from pydantic_ai import Agent
from pydantic_ai_claude_code import ClaudeCodeModel

agent = Agent(ClaudeCodeModel('claude-fable-5-1'))

@agent.tool_plain
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

Tools defined on the agent are passed to the API as standard Anthropic tool definitions, and structured output works the same way as with the built-in anthropic provider. That's the whole point of the wheel.

Structured output

from pydantic import BaseModel
from pydantic_ai import Agent
from pydantic_ai_claude_code import ClaudeCodeModel

class Weather(BaseModel):
    city: str
    temperature_c: float

agent = Agent(ClaudeCodeModel('claude-fable-5-1'), output_type=Weather)
result = await agent.run('Weather in Paris right now?')
assert result.output.city == 'Paris'

Streaming

from pydantic_ai import Agent
from pydantic_ai_claude_code import ClaudeCodeModel

agent = Agent(ClaudeCodeModel('claude-fable-5-1'))
async with agent.run_stream('Count from 1 to 3.') as stream:
    async for chunk in stream.stream_text():
        print(chunk, end='', flush=True)

How auth works

The flow uses the same shared OAuth client the Claude Code CLI uses:

  • Authorization URL: https://claude.ai/oauth/authorize
  • Token URL: https://platform.claude.com/v1/oauth/token
  • Scopes: org:create_api_key user:profile user:inference

Tokens are saved to the OS keyring by default: the Keychain on macOS, Credential Manager on Windows, and Secret Service on Linux. On machines without a keychain, credentials fall back to a JSON file (overridable via CLAUDE_CODE_AUTH_FILE):

~/.local/share/pydantic-ai-claude-code/auth.json

The fallback file is written with 0644 permissions and only ever contains what the issuer gave us. We never read the CLI's own credential files.

Force a backend with the CLAUDE_CODE_CREDENTIALS env var: keyring or file.

Refreshes happen automatically in the background: the auth shim refreshes before expiry and retries once on a 401, exactly like the codex provider does.

Requests identify as Claude Code: "You are Claude Code, Anthropic's official CLI for Claude." is prepended to the system context (position 0), the same persona the CLI sends. The subscription backend expects it and rate-gates premium models without it.

Security and scope

This is a plain Anthropic Messages API client authenticated by your Claude subscription tokens. It does not run the Claude Code CLI in a subprocess, so it does not inherit Claude Code's sandboxing, permission prompts, or hooks. Treat it like any code-executing agent: only give it tools you trust.

Projects using this are responsible for following Anthropic's rules for using Claude Code credentials in their own products.

Development

uv sync --extra dev  # or: source .venv/bin/activate && pip install -e ".[dev]"
ruff check src tests
pytest

Prior art

The OAuth mechanics (shared client id, PKCE, token storage and refresh) are lifted from the claude_code_oauth plugin in code_puppy_core_plugins, cleaned up and reshaped around the provider pattern in pydantic-ai.

Metadata

Release files for pydantic-claude-code 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pydantic-claude-code 0.3.0
File Size Uploaded
pydantic_claude_code-0.3.0.tar.gz 16.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pydantic-claude-code 0.3.0
File Interpreter ABI Platform
pydantic_claude_code-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 32.9 kB

Release files / pydantic_claude_code-0.3.0.tar.gz

Download URL pydantic_claude_code-0.3.0.tar.gz
Size 16.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8672bc27b16e599e98b2ad2a2647a3b24507c56a22305055a8efea15e1f5b179
BLAKE2b-256 checksum
How to use checksums
5797eae2467dbaf10e541daba2b5d64bfa925c2d2fcd21bcdec274bd41f1ab2f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pydantic_claude_code-0.3.0-py3-none-any.whl

Download URL pydantic_claude_code-0.3.0-py3-none-any.whl
Size 16.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
115835b451a24532237b6024dba51825a89b7ed2a04c78547dd0e57e53c9675a
BLAKE2b-256 checksum
How to use checksums
f082db939d324744d9625d329b92f59f1526b6bdc520e1f7aad39a05ecea0895
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page