CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Development Commands
Core Development Tasks
- Install dependencies:
make install (requires uv and pre-commit)
- Run all checks:
make all or pre-commit run --all-files
- Run tests:
make test
- Build docs:
make docs or make docs-serve (local development)
Single Test Commands
- Run specific test:
uv run pytest tests/test_agent.py::test_function_name -v
- Run test file:
uv run pytest tests/test_agent.py -v
- Run with debug:
uv run pytest tests/test_agent.py -v -s
Project Architecture
Core Components
Agent Factory (pydantic_deep/agent.py)
create_deep_agent(): Main factory function for creating configured agents
create_default_deps(): Helper for creating DeepAgentDeps with sensible defaults
- Built on top of pydantic-ai's Agent class
Dependencies (pydantic_deep/deps.py)
DeepAgentDeps: Dataclass holding agent dependencies (backend, working_dir, skills_dirs, subagents)
- Passed to agent.run() for runtime configuration
Backends (from pydantic-ai-backend)
BackendProtocol: Interface for file storage backends
StateBackend: In-memory file storage (for testing, ephemeral use)
LocalBackend: Real filesystem operations
DockerSandbox: Isolated Docker container execution
CompositeBackend: Combines multiple backends with routing
Toolsets (pydantic_deep/toolsets/)
TodoToolset: Task planning and tracking tools (read_todos, write_todos) - from pydantic-ai-todo
create_console_toolset: File operations (ls, read, write, edit, glob, grep, execute) - from pydantic-ai-backend
SubAgentToolset: Spawn and delegate to subagents - from subagents-pydantic-ai
SkillsToolset: Load and use skill definitions from markdown files
Subagents (from subagents-pydantic-ai)
create_subagent_toolset(): Factory function to create subagent toolsets
get_subagent_system_prompt(): Generate system prompt for subagent tools
- Dual-mode execution: sync (blocking) or async (background)
- Task management: check_task, list_active_tasks, soft_cancel_task, hard_cancel_task
- Types:
SubAgentConfig, CompiledSubAgent, TaskHandle, TaskStatus, TaskPriority
Processors (from summarization-pydantic-ai)
SummarizationProcessor: LLM-based conversation summarization for token management
SlidingWindowProcessor: Zero-cost message trimming without LLM calls
create_summarization_processor(): Factory function for summarization processors
create_sliding_window_processor(): Factory function for sliding window processors
Types (pydantic_deep/types.py)
- Pydantic models for all data structures
FileData, FileInfo, WriteResult, EditResult, GrepMatch
Todo, SubAgentConfig, CompiledSubAgent
Skill, SkillDirectory, SkillFrontmatter
ResponseFormat: Alias for structured output specification
Checkpointing (pydantic_deep/toolsets/checkpointing.py)
Checkpoint: Immutable snapshot of conversation state (id, label, turn, messages, metadata)
CheckpointStore: Protocol for storage backends (save, get, list_all, remove, etc.)
InMemoryCheckpointStore: Default in-memory store
FileCheckpointStore: Persistent JSON file store
CheckpointMiddleware: Auto-checkpoint via middleware hooks (every_tool, every_turn, manual_only)
CheckpointToolset: Agent tools (save_checkpoint, list_checkpoints, rewind_to)
RewindRequested: Exception for app-level rewind (propagates out of agent.run())
fork_from_checkpoint(): Utility for session forking
Agent Teams (pydantic_deep/toolsets/teams.py)
SharedTodoItem: Task with assignment, dependencies, and status tracking
SharedTodoList: Asyncio-safe shared TODO list with claiming and dependency blocking
TeamMessage: Message between team members
TeamMessageBus: Peer-to-peer message bus using asyncio.Queue per agent
TeamMember: Member definition (name, role, description, instructions, model)
TeamMemberHandle: Runtime handle to a running team member
AgentTeam: Coordinator — spawn, assign, broadcast, wait_all, dissolve
create_team_toolset(): Factory for team management tools (spawn_team, assign_task, check_teammates, message_teammate, dissolve_team)
Output Styles (pydantic_deep/styles.py)
OutputStyle: Dataclass (name, description, content)
BUILTIN_STYLES: Dict of 4 built-in styles (concise, explanatory, formal, conversational)
resolve_style(): Resolve style name → OutputStyle (built-ins → styles_dir → error)
discover_styles(): Discover .md style files from a directory
load_style_from_file(): Load a single style with frontmatter parsing
format_style_prompt(): Format for system prompt injection
Hooks (pydantic_deep/middleware/hooks.py)
HookEvent: Enum (PRE_TOOL_USE, POST_TOOL_USE, POST_TOOL_USE_FAILURE)
Hook: Definition — event, command/handler, matcher regex, timeout, background
HookInput: Data passed to hooks (event, tool_name, tool_input, tool_result, tool_error)
HookResult: Result from hook (allow, reason, modified_args, modified_result)
HooksMiddleware: AgentMiddleware that dispatches hooks on tool events
EXIT_ALLOW = 0, EXIT_DENY = 2: Claude Code exit code conventions
Persistent Memory (pydantic_deep/toolsets/memory.py)
MemoryFile: Loaded memory (agent_name, path, content)
AgentMemoryToolset: FunctionToolset with read_memory, write_memory, update_memory
get_instructions(): Injects memory into system prompt (first N lines)
load_memory(), format_memory_prompt(), get_memory_path()
- Default path:
{memory_dir}/{agent_name}/MEMORY.md
Context Files (pydantic_deep/toolsets/context.py)
ContextFile: Loaded context file (name, path, content)
ContextToolset: FunctionToolset that injects context files via get_instructions()
discover_context_files(): Auto-discover DEEP.md, AGENTS.md, CLAUDE.md, SOUL.md
load_context_files(): Load from backend (missing files silently skipped)
format_context_prompt(): Format with subagent filtering and truncation
DEFAULT_CONTEXT_FILENAMES: [DEEP.md, AGENTS.md, CLAUDE.md, SOUL.md]
SUBAGENT_CONTEXT_ALLOWLIST: {DEEP.md, AGENTS.md} — subagents don't see SOUL.md/CLAUDE.md
Eviction Processor (pydantic_deep/processors/eviction.py)
EvictionProcessor: History processor — saves large tool outputs to files, replaces with preview
create_eviction_processor(): Factory function
create_content_preview(): Head/tail preview with truncation marker
- Default threshold: 20,000 tokens (80,000 chars)
- Uses runtime
ctx.deps.backend for writing
Cost Tracking (from pydantic-ai-middleware)
- Enabled by default via
cost_tracking=True
CostTrackingMiddleware: Tracks token usage and USD costs per run and cumulative
CostInfo: Per-run and cumulative token/cost data
BudgetExceededError: Raised when cumulative cost exceeds cost_budget_usd
- Pricing from
genai-prices package
Patch Tool Calls (pydantic_deep/processors/patch.py)
patch_tool_calls_processor(): HistoryProcessor that fixes orphaned tool calls
- Injects synthetic
ToolReturnPart with "Tool call was cancelled." message
- Used when resuming interrupted conversations (
patch_tool_calls=True)
Plan Mode (pydantic_deep/toolsets/plan/)
create_plan_toolset(): Factory for ask_user + save_plan tools
- Built-in 'planner' subagent registered when
include_plan=True
PLANNER_INSTRUCTIONS, PLANNER_DESCRIPTION: Planner configuration
- Plans saved as markdown files in
plans_dir (default: /plans)
ask_user supports headless mode (auto-selects recommended option)
Context Manager (from summarization-pydantic-ai)
- Enabled by default via
context_manager=True
ContextManagerMiddleware: Dual-protocol — history processor + AgentMiddleware
- Token tracking with
on_context_update callback (percentage, current, max)
- Auto-compression when approaching token budget (compress_threshold=0.9)
create_context_manager_middleware(): Factory function
Middleware Integration (from pydantic-ai-middleware)
middleware param: List of AgentMiddleware instances
permission_handler: Async callback for ToolDecision.ASK
middleware_context: Shared state between hooks
- Automatically wraps Agent in MiddlewareAgent when any middleware is used
share_todos on DeepAgentDeps
DeepAgentDeps.share_todos: bool = False
- When True,
clone_for_subagent() passes same todos list reference (shared)
- When False (default), subagents get an empty todos list (isolated)
Key Design Patterns
Backend Abstraction
from pydantic_ai_backends import StateBackend, LocalBackend, CompositeBackend
# In-memory for testing
backend = StateBackend()
# Real filesystem
backend = LocalBackend(root_dir="/path/to/workspace")
# Combined backends with routing
backend = CompositeBackend(
default=StateBackend(),
routes={
"/project/": LocalBackend(root_dir="/home/user/project"),
},
)
Toolset Registration
from pydantic_deep import create_deep_agent, DeepAgentDeps
from pydantic_ai_backends import create_console_toolset
from pydantic_ai_todo import create_todo_toolset
agent = create_deep_agent(
model="openai:gpt-4.1",
toolsets=[create_todo_toolset(), create_console_toolset()],
)
Skills System
# Skills are markdown files with YAML frontmatter
# Located in skills_dirs specified in DeepAgentDeps
deps = DeepAgentDeps(
backend=StateBackend(),
skills_dirs=["/path/to/skills"],
)
Structured Output
from pydantic import BaseModel
from pydantic_deep import create_deep_agent
class TaskResult(BaseModel):
status: str
details: str
# Agent returns TaskResult instead of str
agent = create_deep_agent(output_type=TaskResult)
Context Management / Summarization
from pydantic_deep import (
create_deep_agent,
create_summarization_processor,
create_sliding_window_processor,
)
# Automatically summarize when reaching token limits
processor = create_summarization_processor(
trigger=("tokens", 100000), # or ("messages", 50) or ("fraction", 0.8)
keep=("messages", 20), # Keep last N messages after summarization
)
# Or use sliding window for zero-cost trimming
window = create_sliding_window_processor(
trigger=("messages", 100),
keep=("messages", 50),
)
agent = create_deep_agent(history_processors=[processor])
Testing Strategy
- Unit tests:
tests/ directory with comprehensive coverage
- Test models: Use
TestModel from pydantic-ai for deterministic testing
- Async testing: pytest-asyncio with
asyncio_mode = "auto"
- Coverage requirement: 100% coverage is required for all PRs
Key Configuration Files
pyproject.toml: Main configuration (dependencies, tools, coverage)
Makefile: Development task automation
mkdocs.yml: Documentation configuration
.pre-commit-config.yaml: Pre-commit hook configuration
Important Implementation Notes
- Backend Protocol: All backends implement
BackendProtocol for consistent file operations
- Async-First: Most operations are async, use
await appropriately
- Type Safety: Full type annotations with Pyright strict mode
- Sandbox Support: DockerSandbox requires
docker optional dependency
Documentation Development
- Local docs:
make docs-serve (serves at http://localhost:8000)
- Docs source:
docs/ directory (MkDocs with Material theme)
- API reference: Auto-generated from docstrings using mkdocstrings
Dependencies Management
- Package manager: uv (fast Python package manager)
- Lock file:
uv.lock (commit this file)
- Sync command:
make sync to update dependencies
- Optional extras: sandbox, cli, dev
Best Practices
Coverage
Every pull request MUST have 100% coverage. You can check the coverage by running make test.
Use # pragma: no cover for legitimately untestable code (e.g., platform-specific branches).
Type Annotations
All code must pass both Pyright and MyPy strict checking:
make typecheck for Pyright
make typecheck-mypy for MyPy
Writing Documentation
Always reference Python objects with backticks and link to API reference:
The [`create_deep_agent`][pydantic_deep.agent.create_deep_agent] function creates a configured agent.
Rename a Class
When renaming a class, add deprecation warning:
from typing_extensions import deprecated
class NewClass: ...
@deprecated("Use `NewClass` instead.")
class OldClass(NewClass): ...
1---2name: development-commands-73description: This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.4---5# CLAUDE.md67This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.89## Development Commands1011### Core Development Tasks1213- **Install dependencies**: `make install` (requires uv and pre-commit)14- **Run all checks**: `make all` or `pre-commit run --all-files`15- **Run tests**: `make test`16- **Build docs**: `make docs` or `make docs-serve` (local development)1718### Single Test Commands1920- **Run specific test**: `uv run pytest tests/test_agent.py::test_function_name -v`21- **Run test file**: `uv run pytest tests/test_agent.py -v`22- **Run with debug**: `uv run pytest tests/test_agent.py -v -s`2324## Project Architecture2526### Core Components2728**Agent Factory (`pydantic_deep/agent.py`)**29- `create_deep_agent()`: Main factory function for creating configured agents30- `create_default_deps()`: Helper for creating DeepAgentDeps with sensible defaults31- Built on top of pydantic-ai's Agent class3233**Dependencies (`pydantic_deep/deps.py`)**34- `DeepAgentDeps`: Dataclass holding agent dependencies (backend, working_dir, skills_dirs, subagents)35- Passed to agent.run() for runtime configuration3637**Backends (from [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend))**38- `BackendProtocol`: Interface for file storage backends39- `StateBackend`: In-memory file storage (for testing, ephemeral use)40- `LocalBackend`: Real filesystem operations41- `DockerSandbox`: Isolated Docker container execution42- `CompositeBackend`: Combines multiple backends with routing4344**Toolsets (`pydantic_deep/toolsets/`)**45- `TodoToolset`: Task planning and tracking tools (read_todos, write_todos) - from [pydantic-ai-todo](https://github.com/vstorm-co/pydantic-ai-todo)46- `create_console_toolset`: File operations (ls, read, write, edit, glob, grep, execute) - from [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend)47- `SubAgentToolset`: Spawn and delegate to subagents - from [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai)48- `SkillsToolset`: Load and use skill definitions from markdown files4950**Subagents (from [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai))**51- `create_subagent_toolset()`: Factory function to create subagent toolsets52- `get_subagent_system_prompt()`: Generate system prompt for subagent tools53- Dual-mode execution: sync (blocking) or async (background)54- Task management: check_task, list_active_tasks, soft_cancel_task, hard_cancel_task55- Types: `SubAgentConfig`, `CompiledSubAgent`, `TaskHandle`, `TaskStatus`, `TaskPriority`5657**Processors (from [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai))**58- `SummarizationProcessor`: LLM-based conversation summarization for token management59- `SlidingWindowProcessor`: Zero-cost message trimming without LLM calls60- `create_summarization_processor()`: Factory function for summarization processors61- `create_sliding_window_processor()`: Factory function for sliding window processors6263**Types (`pydantic_deep/types.py`)**64- Pydantic models for all data structures65- `FileData`, `FileInfo`, `WriteResult`, `EditResult`, `GrepMatch`66- `Todo`, `SubAgentConfig`, `CompiledSubAgent`67- `Skill`, `SkillDirectory`, `SkillFrontmatter`68- `ResponseFormat`: Alias for structured output specification6970**Checkpointing (`pydantic_deep/toolsets/checkpointing.py`)**71- `Checkpoint`: Immutable snapshot of conversation state (id, label, turn, messages, metadata)72- `CheckpointStore`: Protocol for storage backends (save, get, list_all, remove, etc.)73- `InMemoryCheckpointStore`: Default in-memory store74- `FileCheckpointStore`: Persistent JSON file store75- `CheckpointMiddleware`: Auto-checkpoint via middleware hooks (every_tool, every_turn, manual_only)76- `CheckpointToolset`: Agent tools (save_checkpoint, list_checkpoints, rewind_to)77- `RewindRequested`: Exception for app-level rewind (propagates out of agent.run())78- `fork_from_checkpoint()`: Utility for session forking7980**Agent Teams (`pydantic_deep/toolsets/teams.py`)**81- `SharedTodoItem`: Task with assignment, dependencies, and status tracking82- `SharedTodoList`: Asyncio-safe shared TODO list with claiming and dependency blocking83- `TeamMessage`: Message between team members84- `TeamMessageBus`: Peer-to-peer message bus using asyncio.Queue per agent85- `TeamMember`: Member definition (name, role, description, instructions, model)86- `TeamMemberHandle`: Runtime handle to a running team member87- `AgentTeam`: Coordinator — spawn, assign, broadcast, wait_all, dissolve88- `create_team_toolset()`: Factory for team management tools (spawn_team, assign_task, check_teammates, message_teammate, dissolve_team)8990**Output Styles (`pydantic_deep/styles.py`)**91- `OutputStyle`: Dataclass (name, description, content)92- `BUILTIN_STYLES`: Dict of 4 built-in styles (concise, explanatory, formal, conversational)93- `resolve_style()`: Resolve style name → OutputStyle (built-ins → styles_dir → error)94- `discover_styles()`: Discover .md style files from a directory95- `load_style_from_file()`: Load a single style with frontmatter parsing96- `format_style_prompt()`: Format for system prompt injection9798**Hooks (`pydantic_deep/middleware/hooks.py`)**99- `HookEvent`: Enum (PRE_TOOL_USE, POST_TOOL_USE, POST_TOOL_USE_FAILURE)100- `Hook`: Definition — event, command/handler, matcher regex, timeout, background101- `HookInput`: Data passed to hooks (event, tool_name, tool_input, tool_result, tool_error)102- `HookResult`: Result from hook (allow, reason, modified_args, modified_result)103- `HooksMiddleware`: AgentMiddleware that dispatches hooks on tool events104- `EXIT_ALLOW = 0`, `EXIT_DENY = 2`: Claude Code exit code conventions105106**Persistent Memory (`pydantic_deep/toolsets/memory.py`)**107- `MemoryFile`: Loaded memory (agent_name, path, content)108- `AgentMemoryToolset`: FunctionToolset with read_memory, write_memory, update_memory109- `get_instructions()`: Injects memory into system prompt (first N lines)110- `load_memory()`, `format_memory_prompt()`, `get_memory_path()`111- Default path: `{memory_dir}/{agent_name}/MEMORY.md`112113**Context Files (`pydantic_deep/toolsets/context.py`)**114- `ContextFile`: Loaded context file (name, path, content)115- `ContextToolset`: FunctionToolset that injects context files via get_instructions()116- `discover_context_files()`: Auto-discover DEEP.md, AGENTS.md, CLAUDE.md, SOUL.md117- `load_context_files()`: Load from backend (missing files silently skipped)118- `format_context_prompt()`: Format with subagent filtering and truncation119- `DEFAULT_CONTEXT_FILENAMES`: [DEEP.md, AGENTS.md, CLAUDE.md, SOUL.md]120- `SUBAGENT_CONTEXT_ALLOWLIST`: {DEEP.md, AGENTS.md} — subagents don't see SOUL.md/CLAUDE.md121122**Eviction Processor (`pydantic_deep/processors/eviction.py`)**123- `EvictionProcessor`: History processor — saves large tool outputs to files, replaces with preview124- `create_eviction_processor()`: Factory function125- `create_content_preview()`: Head/tail preview with truncation marker126- Default threshold: 20,000 tokens (80,000 chars)127- Uses runtime `ctx.deps.backend` for writing128129**Cost Tracking (from pydantic-ai-middleware)**130- Enabled by default via `cost_tracking=True`131- `CostTrackingMiddleware`: Tracks token usage and USD costs per run and cumulative132- `CostInfo`: Per-run and cumulative token/cost data133- `BudgetExceededError`: Raised when cumulative cost exceeds `cost_budget_usd`134- Pricing from `genai-prices` package135136**Patch Tool Calls (`pydantic_deep/processors/patch.py`)**137- `patch_tool_calls_processor()`: HistoryProcessor that fixes orphaned tool calls138- Injects synthetic `ToolReturnPart` with "Tool call was cancelled." message139- Used when resuming interrupted conversations (`patch_tool_calls=True`)140141**Plan Mode (`pydantic_deep/toolsets/plan/`)**142- `create_plan_toolset()`: Factory for ask_user + save_plan tools143- Built-in 'planner' subagent registered when `include_plan=True`144- `PLANNER_INSTRUCTIONS`, `PLANNER_DESCRIPTION`: Planner configuration145- Plans saved as markdown files in `plans_dir` (default: `/plans`)146- `ask_user` supports headless mode (auto-selects recommended option)147148**Context Manager (from summarization-pydantic-ai)**149- Enabled by default via `context_manager=True`150- `ContextManagerMiddleware`: Dual-protocol — history processor + AgentMiddleware151- Token tracking with `on_context_update` callback (percentage, current, max)152- Auto-compression when approaching token budget (compress_threshold=0.9)153- `create_context_manager_middleware()`: Factory function154155**Middleware Integration (from pydantic-ai-middleware)**156- `middleware` param: List of AgentMiddleware instances157- `permission_handler`: Async callback for ToolDecision.ASK158- `middleware_context`: Shared state between hooks159- Automatically wraps Agent in MiddlewareAgent when any middleware is used160161**`share_todos` on DeepAgentDeps**162- `DeepAgentDeps.share_todos: bool = False`163- When True, `clone_for_subagent()` passes same todos list reference (shared)164- When False (default), subagents get an empty todos list (isolated)165166### Key Design Patterns167168**Backend Abstraction**169```python170from pydantic_ai_backends import StateBackend, LocalBackend, CompositeBackend171172# In-memory for testing173backend = StateBackend()174175# Real filesystem176backend = LocalBackend(root_dir="/path/to/workspace")177178# Combined backends with routing179backend = CompositeBackend(180 default=StateBackend(),181 routes={182 "/project/": LocalBackend(root_dir="/home/user/project"),183 },184)185```186187**Toolset Registration**188```python189from pydantic_deep import create_deep_agent, DeepAgentDeps190from pydantic_ai_backends import create_console_toolset191from pydantic_ai_todo import create_todo_toolset192193agent = create_deep_agent(194 model="openai:gpt-4.1",195 toolsets=[create_todo_toolset(), create_console_toolset()],196)197```198199**Skills System**200```python201# Skills are markdown files with YAML frontmatter202# Located in skills_dirs specified in DeepAgentDeps203deps = DeepAgentDeps(204 backend=StateBackend(),205 skills_dirs=["/path/to/skills"],206)207```208209**Structured Output**210```python211from pydantic import BaseModel212from pydantic_deep import create_deep_agent213214class TaskResult(BaseModel):215 status: str216 details: str217218# Agent returns TaskResult instead of str219agent = create_deep_agent(output_type=TaskResult)220```221222**Context Management / Summarization**223```python224from pydantic_deep import (225 create_deep_agent,226 create_summarization_processor,227 create_sliding_window_processor,228)229230# Automatically summarize when reaching token limits231processor = create_summarization_processor(232 trigger=("tokens", 100000), # or ("messages", 50) or ("fraction", 0.8)233 keep=("messages", 20), # Keep last N messages after summarization234)235236# Or use sliding window for zero-cost trimming237window = create_sliding_window_processor(238 trigger=("messages", 100),239 keep=("messages", 50),240)241242agent = create_deep_agent(history_processors=[processor])243```244245## Testing Strategy246247- **Unit tests**: `tests/` directory with comprehensive coverage248- **Test models**: Use `TestModel` from pydantic-ai for deterministic testing249- **Async testing**: pytest-asyncio with `asyncio_mode = "auto"`250- **Coverage requirement**: 100% coverage is required for all PRs251252## Key Configuration Files253254- **`pyproject.toml`**: Main configuration (dependencies, tools, coverage)255- **`Makefile`**: Development task automation256- **`mkdocs.yml`**: Documentation configuration257- **`.pre-commit-config.yaml`**: Pre-commit hook configuration258259## Important Implementation Notes260261- **Backend Protocol**: All backends implement `BackendProtocol` for consistent file operations262- **Async-First**: Most operations are async, use `await` appropriately263- **Type Safety**: Full type annotations with Pyright strict mode264- **Sandbox Support**: DockerSandbox requires `docker` optional dependency265266## Documentation Development267268- **Local docs**: `make docs-serve` (serves at http://localhost:8000)269- **Docs source**: `docs/` directory (MkDocs with Material theme)270- **API reference**: Auto-generated from docstrings using mkdocstrings271272## Dependencies Management273274- **Package manager**: uv (fast Python package manager)275- **Lock file**: `uv.lock` (commit this file)276- **Sync command**: `make sync` to update dependencies277- **Optional extras**: sandbox, cli, dev278279## Best Practices280281### Coverage282283Every pull request MUST have 100% coverage. You can check the coverage by running `make test`.284285Use `# pragma: no cover` for legitimately untestable code (e.g., platform-specific branches).286287### Type Annotations288289All code must pass both Pyright and MyPy strict checking:290- `make typecheck` for Pyright291- `make typecheck-mypy` for MyPy292293### Writing Documentation294295Always reference Python objects with backticks and link to API reference:296297```markdown298The [`create_deep_agent`][pydantic_deep.agent.create_deep_agent] function creates a configured agent.299```300301### Rename a Class302303When renaming a class, add deprecation warning:304305```python306from typing_extensions import deprecated307308class NewClass: ...309310@deprecated("Use `NewClass` instead.")311class OldClass(NewClass): ...312```