We're Building an Open-Source Claude Code Alternative in Python
Table of Contents
Claude Code changed how developers think about AI coding assistants. An agent that lives in your terminal, reads your codebase, edits files, runs commands — no browser tab, no copy-pasting, no context window gymnastics.
But here’s the thing: it’s a closed-source monolith. You can’t swap the model. You can’t extend the toolset. You can’t deploy it in your own infrastructure. And if you’re building agents for clients — you can’t ship Claude Code as your product.
We wanted the same architecture — planning, checkpointing, file editing, human-in-the-loop — but modular, open-source, and built on top of Pydantic AI. So we built it.
What pydantic-deepagents Actually Is
pydantic-deepagents (pydantic-deep) is a Python framework for building Claude Code-style deep agents — the kind that plan, delegate, remember, and self-correct. It ships as two things:
- A framework —
create_deep_agent()with 30+ optional features you toggle on/off - A CLI —
pydantic-deep chat— a fully interactive terminal assistant
Both are built on Pydantic AI and follow the same deep agent pattern used by Claude Code, Devin, and Manus AI.
The key difference: everything is modular. The framework is split into 5 independent open-source packages:
pydantic-deep — core agent + CLI├── pydantic-ai-backend — file storage (local, state, Docker, Daytona)├── pydantic-ai-todo — task planning with dependencies├── subagents-pydantic-ai — sync/async agent delegation├── summarization-pydantic-ai — context management + sliding window└── pydantic-ai-middleware — lifecycle hooks, permissions, cost trackingEach package works standalone. You can use pydantic-ai-todo without the rest. You can swap pydantic-ai-backend for your own storage layer. The framework composes them — you pick what you need.
The One-Function API
Creating an agent with all features takes one function call:
from pydantic_deep import create_deep_agent, DeepAgentDeps, StateBackend
agent = create_deep_agent( model="openai:gpt-4.1", instructions="You are a helpful coding assistant", include_plan=True, # Planning subagent include_checkpoints=True, # Save/rewind state include_memory=True, # Persistent MEMORY.md include_skills=True, # Slash commands cost_tracking=True, # Budget enforcement cost_budget_usd=5.0,)
deps = DeepAgentDeps(backend=StateBackend())result = await agent.run("Refactor the auth module", deps=deps)Every feature is a boolean flag. Need teams? Add include_teams=True. Want hooks? Pass a hooks list. The framework assembles the right toolsets, middleware, and system prompt sections automatically.
Checkpointing and Rewind
This is the feature that changes how you work with agents. Every tool call creates a checkpoint — a snapshot of the conversation state. When the agent goes down the wrong path (and it will), you rewind:
from pydantic_deep import InMemoryCheckpointStore, RewindRequested
store = InMemoryCheckpointStore()agent = create_deep_agent( include_checkpoints=True, checkpoint_store=store, checkpoint_frequency="every_tool",)
while True: try: result = await agent.run(user_input, deps=deps, message_history=history) history = result.all_messages() except RewindRequested as e: print(f"Rewinding to '{e.label}'...") history = e.messagesThe agent says “save_checkpoint(‘before refactor’)” before risky operations. You say “rewind to ‘before refactor’” when it breaks something. The conversation state rolls back — no lost context, no re-explaining the task.
In the CLI, checkpoints show up as labeled snapshots you can jump between. Like git commits for your agent conversation.
Agent Teams
Single agents hit limits on complex tasks. Our solution: flat teams with shared state.
from pydantic_deep.toolsets.teams import AgentTeam, TeamMember
team = AgentTeam( name="backend-team", members=[ TeamMember(name="alice", role="api-designer", instructions="Focus on clean REST API design"), TeamMember(name="bob", role="db-architect", instructions="Design efficient database schema"), ],)
# Assign tasks with dependenciestask_a = await team.todos.add("Design the API schema", created_by="lead")task_b = await team.todos.add("Implement endpoints", blocked_by=[task_a], created_by="lead")Each team member shares a SharedTodoList (asyncio-safe task claiming with dependencies) and a TeamMessageBus for peer-to-peer messaging. No hierarchical subagent chains — agents coordinate as peers, claim tasks, and message each other when they need input.
Hooks — Claude Code-Style Lifecycle Events
Every tool call in pydantic-deep fires lifecycle events. You intercept them with hooks:
from pydantic_deep import Hook, HookEvent, HookInput, HookResult
async def safety_gate(hook_input: HookInput) -> HookResult: if "rm -rf" in str(hook_input.tool_input): return HookResult(allow=False, reason="Dangerous command blocked") return HookResult(allow=True)
agent = create_deep_agent( hooks=[ Hook( event=HookEvent.PRE_TOOL_USE, handler=safety_gate, matcher="execute", ), Hook( event=HookEvent.POST_TOOL_USE, command="echo '$TOOL_NAME' >> /tmp/audit.log", ), ],)Three event types: PRE_TOOL_USE, POST_TOOL_USE, POST_TOOL_USE_FAILURE. Hooks can be Python handlers or shell commands. Exit code 0 = allow, exit code 2 = deny.
Custom Slash Commands
Drop a Markdown file in .pydantic-deep/commands/, and it becomes a slash command:
# /commit
Create a conventional git commit for the current changes.
## Instructions1. Run `git diff --staged` to see what's staged2. If nothing is staged, run `git add -A`3. Generate a commit message following Conventional Commits4. Run `git commit -m "..."` with the generated messageThe CLI ships with built-in commands: /commit, /pr, /review, /test, /fix, /explain. Three-scope discovery: built-in, user-level (~/.pydantic-deep/commands/), and project-level (.pydantic-deep/commands/).
The CLI Terminal UX
The CLI (pydantic-deep chat) is where everything comes together:
Diff viewer for file approvals. When the agent wants to edit a file, you see a colored unified diff with gutter bars before approving.
Context progress bar. The status bar shows model name, accumulated cost, and a visual context usage indicator. Threshold colors: green below 60%, amber at 60–85%, red above 85%.
Streaming with braille spinner. Text streams in with a seamless transition — braille spinner during thinking, then live Markdown rendering.
@file mentions with tab completion. Type @src/ and get autocomplete for files to include in context.
Persistent Memory
The agent maintains a MEMORY.md file — persistent notes that survive across sessions:
agent = create_deep_agent(include_memory=True)# Agent can call: read_memory, write_memory, update_memory# MEMORY.md auto-injected into system prompt (first 200 lines)In the CLI, use /remember to save preferences: “always use pytest, never use unittest.” Next session, the agent already knows. Same pattern as Claude Code’s memory, with the same 200-line auto-injection.
Key Takeaways
- Deep agents are a pattern, not a product — Claude Code proved the architecture, but you don’t need a closed-source tool to build it
- Modularity wins — 5 packages that compose vs 1 monolith means you can swap any layer without rewriting everything
- Checkpointing changes the workflow — treating agent sessions like git branches (save, rewind, fork) makes AI coding assistants dramatically more useful
- The CLI is the interface — for coding tasks, a terminal agent beats a chat window every time
Try it: pydantic-deepagents on GitHub — pip install pydantic-deep[cli]
Related Articles
From create-react-app to create-ai-app: The New Default for AI Applications
In 2016, create-react-app standardized how we build frontends. In 2026, AI applications need the same moment — and it's...
AGENTS.md: Making Your Codebase AI-Agent Friendly (Copilot, Cursor, Codex, Claude Code)
Every AI coding tool reads your repo differently. Here's how AGENTS.md — the emerging tool-agnostic standard — gives the...
From 0 to Production AI Agent in 30 Minutes — Full-Stack Template with 5 AI Frameworks
Step-by-step walkthrough: web configurator, pick a preset, choose your AI framework, configure 75+ options, docker-compo...