---
title: Claude
description: Drive Pictograph from Anthropic's SDK or the Claude Agent SDK. Both backed by the same registry.
section: Agents
order: 1
---
Toolkit setup and guardrails live on [Agents — overview](/docs/agents.md). This page shows the two Claude-specific integration paths.

## Path 1: Anthropic SDK (raw tool dicts)

No extra dependencies — works with the standard `anthropic` package. You manage the tool-use loop.

```python
import anthropic
from pictograph.agents import create_toolkit, for_anthropic_messages

toolkit = create_toolkit()
tools = for_anthropic_messages(toolkit)
client = anthropic.Anthropic()

messages = [
    {"role": "user", "content": "Upload ./photos to a dataset called 'demo' and auto-annotate cars and people."},
]

response = client.messages.create(
    model="claude-opus-4",
    max_tokens=4096,
    tools=tools,
    tool_choice={"type": "auto"},
    messages=messages,
)

while response.stop_reason == "tool_use":
    tool_uses = [b for b in response.content if b.type == "tool_use"]
    tool_results = [
        {
            "type": "tool_result",
            "tool_use_id": tu.id,
            "content": str(toolkit.dispatch(tu.name, tu.input)),
        }
        for tu in tool_uses
    ]
    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": tool_results})
    response = client.messages.create(
        model="claude-opus-4",
        max_tokens=4096,
        tools=tools,
        messages=messages,
    )

print(response.content)
```

`toolkit.dispatch(name, args)` validates `args` through the tool's Pydantic schema, invokes the handler, and returns a JSON-serializable result. Invalid input raises `ValidationError`.

## Path 2: Claude Agent SDK

The Agent SDK manages the loop, streaming, and dispatch. Requires the extra:

```bash
pip install 'pictograph[agents]'
```

```python
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from pictograph.agents import create_toolkit, for_claude_agent_sdk

toolkit = create_toolkit()
agent_tools = for_claude_agent_sdk(toolkit)

async with ClaudeSDKClient(
    options=ClaudeAgentOptions(
        system_prompt="You drive Pictograph for the user. Confirm destructive operations.",
        allowed_tools=[t.name for t in agent_tools],
    ),
) as client:
    async for response in client.query(
        "Train a YOLOX model on the 'road-signs' dataset, A10G GPU, 50 epochs"
    ):
        print(response)
```

## Picking between paths

| Path 1 (raw dicts) | Path 2 (Agent SDK) |
| --- | --- |
| You already call `messages.create()` directly | You want streaming + multi-turn with no loop boilerplate |
| You need custom logging or gating in the loop | You're building a long-running agent process |
| You don't want the `claude-agent-sdk` dependency | You're running inside Claude Code or another Agent-SDK runtime |

## See also

- [Agents](/docs/agents.md) — toolkit setup, guardrails, and the registry
- [Bundled Skill](/docs/agents.md) — `pictograph-cv` for Claude Code / claude.ai
- [Cookbook](/docs/agents/cookbook.md) — recipe-style examples