Home
Pick a pattern, edit the prompt, ship it.
Examples · Which pattern should I use? · FAQ
Agent Template is a clean, opinionated starting point for building AI agents using Pydantic AI, with ready-to-go scaffolding for seventeen popular agent patterns: tool calling, retrieval, multi-agent workflows, human approval, durable execution and more. Run one script, pick a pattern, and you get the agent, its prompt, an offline test and an eval starter in your own project, as code you own. There is no framework to depend on.
Every pattern has been run against a real model: each comes with a recorded run you can read, live tests that check what the agent actually did and tests that cover every line of its code. The guardrails are on from the start (limits on requests, tokens and spend) and any model is one setting away.
Get started¶
# 1. Create your project: click "Use this template" on GitHub, or clone it
git clone https://github.com/tmtabor/agent-template.git my-agent && cd my-agent
uv sync --group dev
cp .env.example .env # then add the API key for your model provider
# 2. Add an agent: pick a pattern from the menu
uv run python scripts/add_agent.py
# 3. Edit its prompt (agent/prompts/<name>.txt), then run the tests
uv run pytest
That gives you agent/agents/<name>.py, its prompt, a smoke test and an eval starter. Run add_agent.py again for each further agent; each can use a different pattern. The setup and commands below cover the rest, and Which pattern should I use? helps you choose.
What are you building?¶
From a first agent to a long-running multi-agent system, each of these is a pattern you add with one command. Each has working code, tests, and a recorded run against a real model.
Your first agent
One agent, one prompt, one typed output. Start from blank (empty) or single (a worked example).
An agent that uses your tools
Give the model tools that call your systems, with errors it can recover from, or use the tools of an existing MCP server.
from agent.agents.releases import run_tool_agent
result = await run_tool_agent("What changed in Python 3.13 compared with 3.12?")
Build this → tool_calling · mcp_tools
Answers from your own documents
Documents are embedded and stored in a vector database (Chroma, running as a Docker service), so questions are matched by meaning and every cited source is checked against what was really retrieved.
uv run python scripts/add_agent.py rag --name support_docs
docker compose -f services/support_docs/docker-compose.yml up -d --wait # the database
from agent.agents.support_docs import run_rag
result = await run_rag("How long can I send my hiking footwear back for my money?")
result.output.sources # ['returns-policy']
Build this → rag
Structured data from text
Turn free text into a validated schema, with an output validator that sends a wrong answer back for correction.
from agent.agents.contacts import run_extraction
result = await run_extraction(
"Hi, it's Ada Lovelace from Analytical Engines Ltd. Reach me at ada@example.com."
)
result.output # a validated Contact
Build this → extraction
Several agents working together
Six shapes, from the most predictable to the most flexible: a fixed pipeline, a router that picks a specialist, a parallel fan_out, an evaluator_optimizer loop, a planner_executor whose plan code checks, and a supervisor that decides as it goes. Which one?
from agent.agents.support import run_router
result = await run_router("I was charged twice for my subscription this month.")
result.steps # each agent run, in order
Build this → pipeline · router · fan_out · evaluator_optimizer · planner_executor · supervisor
Actions a person must approve
Pause a risky tool call until someone approves it, reject impossible requests before anyone is asked, or check input and output with guardrails.
from agent.agents.refunds import run_refunds
result = await run_refunds("Order A100 arrived with a broken sole. Please refund the full $84.50.")
Build this → human_in_the_loop · guardrails
Work that must not be lost
Run the agent as a Temporal workflow: a failing tool is retried, and a crashed worker is replaced, without repeating the model calls that already finished. Temporal runs as a Docker service.
uv run python scripts/add_agent.py temporal --name orders
docker compose -f services/orders/docker-compose.yml up -d --wait # the Temporal server
from agent.agents.orders import run_order_desk
result = await run_order_desk(
"I'd like to order 3 gizmos for Norway. Are they in stock, and what is the shipping?"
)
Build this → temporal
Exact answers over many lookups
Let the model write code that calls your tools in a loop and does the arithmetic, in a sandbox with hard limits, so one or two model requests do the work of dozens.
from agent.agents.expenses import run_expenses
result = await run_expenses("What is the total of Maya's travel expenses, in US dollars?")
result.output.amount_usd
Build this → code_mode
A conversation
Remember earlier turns, keep the context window bounded, and stream replies as they are generated.
from agent.agents.chat import run_chat
first = await run_chat("Hi! My name is Priya and I'm planning a trip to Lisbon.")
second = await run_chat("What's my name?", history=first.all_messages())
Build this → conversation
See all seventeen patterns, each with its source and a recorded run.
Why this template¶
It is opinionated on purpose. Four opinions are baked in, so you can tell whether they are yours:
- Copy, don't depend.
add_agent.pycopies a pattern into your project. There is no library to import and nothing to upgrade in place; the code is yours to change. - Guardrails from the start. Every agent has limits on requests and tokens, an optional spend cap, and a response the provider blocks raises an error instead of coming back half finished. A misconfigured provider fails at import, not at the first request.
- Observable by default. Runs are traced with no per-agent setup: to the console until you give it a Logfire token.
- Any model, one config.
AGENT_MODELis the one setting. The patterns' live tests assert behavior that holds for any capable model, not one model's wording.
Stack¶
- Python 3.13 and 3.14, uv
- Pydantic AI v2 (agents, tools) + pydantic-evals (evals)
- Logfire (observability)
- pytest + pytest-asyncio
Next steps¶
- Make it yours. Edit the prompt, replace the output schema, and add your tools: Customizing the prompt and Adding tools. Each pattern's README ends with how to adapt it.
- Test it for real. Grow the eval fixtures for your task, and run
uv run pytest -m evalwith your key: Evals. - Set your limits. Tune
USAGE_LIMITSand setAGENT_COST_LIMITbefore real use: Usage limits. - See what it did. Add a Logfire token and every model call and tool call is traced: Observability.
- Replace the stand-ins. The examples use invented data and demo services; swap in your own. The FAQ says what to check before production.
- Join in. Report a problem or send a fix: Contributing.
Projects using agent-template¶
- job-agent: a daily job-scanning agent. It fetches postings from several sources, filters and scores them against a candidate profile with an LLM, and emails a ranked digest. Runs on GitHub Actions.
- content-agent: a multi-brand agent that generates social posts, blogs and newsletters, built with Pydantic AI, FastAPI/HTMX and a local Ollama model.
- oss-notifier-agent: an LLM-triaged good-first-issue digest for GitHub repos, delivered by email. Runs on GitHub Actions, no server required.
Built something with it? Open a pull request to add it here.