This release is a pre-release and may not be stable for production use.
PydanTask: Deep Agentic Harness for Pydantic AI
PydanTask is an alpha harness for building deep, multi-step agents on top of Pydantic AI.
If you want agents that can plan, execute, self-critique, and ship a final artifact (not just chat), this gives you the backbone.
What you get:
- Dynamic task DAGs: a supervisor creates/patches a task graph at runtime
- Parallel execution: run dependency-satisfied tasks concurrently
- Critic QA + retries: failed tasks become
RERUNuntilmax_attempts, thenFAILED - Observability: optional tracing (Langfuse, Logfire, LangSmith)
- Recovery/auditability: optional event-sourced checkpointing (
events.jsonl+ summaries + large-result sidecars) - Extensibility: register your own capabilities via
CapabilityDescription
Try it in ~3 minutes
- Install:
pip install pydantask
- Set env vars:
export OPENAI_API_KEY="..."
# Optional: enables Tavily web search; otherwise DuckDuckGo-based search is used
export TAVILY_API_KEY="..."
- Run a minimal agent:
import asyncio
from pydantask.agents import DeepAgent
async def main() -> None:
agent = DeepAgent(
objective="Compare 3 open-source LLMs for local inference and recommend one.",
model="openai:gpt-4.1-mini", # or "anthropic:..." or pass a Model instance
trace=False,
checkpoint=False,
max_steps=10,
)
result = await agent.run()
print(result.final_result.detailed_output if result.final_result else result.errors)
if __name__ == "__main__":
asyncio.run(main())
Alpha note: the core loop is working and tested, but the API and prompts are still evolving. If you hit rough edges, please open an issue with a minimal repro.
For deeper docs and API reference, see: pydantask.readthedocs.io
High-Level Architecture
The core orchestrator is DeepAgent:
from pydantask.agents.agent import DeepAgent
DeepAgent coordinates several built‑in agents:
- Supervisor – plans and chooses which tasks to run next, based on statuses and dependencies.
- Researcher – performs web/external research for tasks that need new information.
- Producer – synthesizes intermediate results into a final answer or artifact.
- Critic – evaluates task outputs and drives deterministic retry/fail transitions.
They all operate over a shared RuntimeState:
from pydantask.models import RuntimeState, TaskItem, TaskResult, Plan
Key concepts:
- Plan (
Plan):reasoning_steps: planner’s internal notestasks: list ofTaskIteminstances
- TaskItem: one sub‑task in the plan, with:
task_id,overall_objective,sub_task_objectivecapability(which sub‑agent to use, e.g."research_agent")sub_task_dependencies(other task IDs that must complete first)status(TaskStatus:PENDING,READY,RUNNING,NEEDS_REVIEW,COMPLETED,FAILED,ERRORED,RERUN)result(TaskResult) andtask_feedback(TaskQAResult)
- RuntimeState:
plan: Dict[int, TaskItem]objective: strcapability_registry: Dict[str, CapabilityDescription](excluded from serialization)document_store,knowledge_store,runtime_steps, etc.
The control loop in DeepAgent.run():
- Supervisor incrementally builds a task DAG for the objective (via tools like
add_task). RuntimeStateis initialized with the capability registry.- In each cycle:
- Supervisor decides which tasks to execute next based on plan progress, task dependencies, and self reflection.
- Ready tasks, so long as dependencies are satisfied, are executed by the appropriate capability (sub‑agent).
- Critic reviews each result and produces a "QA" report for the supervisor to review if the task failed.
- Loop stops when:
- the Supervisor sets
all_tasks_completed = Trueand the run’s completion invariants are met (exactly one task is markedis_final=True, and that task isCOMPLETEDwith aTaskResult), or max_stepsis reached, or- the harness stops after several no-progress cycles (safety guardrail).
- the Supervisor sets
For more detail, see docs/agents.md.
Installation & Setup
PydanTask assumes you already have Pydantic AI and an OpenAI‑compatible model configured. A Tavily API key is optional for the built‑in research agent (it falls back to DuckDuckGo search if omitted).
1. Install dependencies
From your project root:
pip install pydantask
(or however you manage your environment; if you use Poetry, adjust accordingly.)
2. Environment variables
Set the following environment variables (e.g. in your shell or a .env file):
OPENAI_API_KEY– for the underlying OpenAIChatModel (or whatever your Pydantic AI provider expects).TAVILY_API_KEY– (optional) used by theresearch_agent(viatavily_search_tool). If this key is not set, it defaults to DuckDuckGo search.
Quickstart: Running a DeepAgent
Minimal example that creates a DeepAgent and runs it on a single objective:
import asyncio
from pydantask.agents.agent import DeepAgent
async def main() -> None:
agent = DeepAgent(
objective="Write an overview of ghost lights folklore and summarize scientific explanations.",
model="gpt-4.1-mini", # or any compatible OpenAIChatModel name
max_steps=10,
)
run_result = await agent.run()
runtime_state = run_result.runtime_state
# Inspect the final plan and results
for task_id, task in sorted(runtime_state.plan.items()):
print(f"Task {task_id} [{task.status}]: {task.sub_task_objective}")
if task.result is not None:
print(" Summary:", task.result.summary)
# The main long-form output for the task is stored in-memory:
print(" Detailed output:", (task.result.detailed_output or "<empty>"))
print()
if __name__ == "__main__":
asyncio.run(main())
What this does:
- Constructs a
DeepAgentwith default Supervisor, Researcher, Producer, and Critic. - Supervisor (dynamic DAG architect) breaks down the objective into
TaskItems using built-in capabilities. - Supervisor picks tasks to run in each loop iteration.
- Researcher and Producer execute those tasks and return structured
TaskResults. - Critic evaluates each task result and marks tasks as:
COMPLETEDwhen QA passesRERUNwhen QA fails but retries remain (critic feedback is appended to the task objective)FAILEDwhen QA fails andmax_attemptsis exceeded
- When done, you get a
RuntimeStatewith the full plan and results.
Note: by default, this harness treats task artifacts as in-memory outputs (e.g.
TaskResult.detailed_output).However, it does support optional event-sourced checkpointing (
checkpoint=True) which persists an append-onlyevents.jsonllog (plus summaries and, when needed, sidecar JSON files for large results) under_checkpoint/.Filesystem tools exist in
pydantask.tools.default_tools, but they are not enabled by default in the built-in agents.
Customizing Capabilities
You can add custom sub‑agents or tools via CapabilityDescription and the sub_agents argument.
Example: custom agent capability
from pydantic_ai import Agent
from pydantask.agents.agent import DeepAgent
from pydantask.models import CapabilityDescription, TaskResult, TaskRunDeps
my_special_agent = Agent(
model=..., # e.g. the same OpenAIChatModel
name="_my_special_agent",
system_prompt="You are a specialized agent for security analysis.",
deps_type=TaskRunDeps, # gives tools access to deps.runtime_state + deps.task
output_type=TaskResult,
tools=[...], # tools should typically accept RunContext[TaskRunDeps]
)
custom_capability = CapabilityDescription(
name="security_agent", # used in TaskItem.capability
description="Performs security-focused analysis and risk assessment.",
tool_func=my_special_agent,
)
agent = DeepAgent(
objective="Assess the security posture of this web application.",
sub_agents=[custom_capability],
)
# Now the Planner can choose `security_agent` as a capability in the plan.
Example: simple function capability (runnable capability)
DeepAgent expects a capability to be runnable (i.e. something with a .run(prompt, deps, usage_limits=...) method). For plain functions, wrap them with as_runner(...).
from pydantask.agents.agent import DeepAgent
from pydantask.capabilities.runner import as_runner
from pydantask.models import CapabilityDescription, TaskResult, TaskRunDeps
async def my_utility_capability(prompt: str, deps: TaskRunDeps) -> TaskResult:
# prompt is the task prompt; deps.runtime_state + deps.task give you context
return TaskResult(task_id=deps.task.task_id, summary="processed", detailed_output=prompt)
utility_capability = CapabilityDescription(
name="my_utility_tool",
description="Utility capability that processes a prompt and returns a TaskResult.",
tool_func=as_runner(my_utility_capability),
)
agent = DeepAgent(objective="Some goal...", sub_agents=[utility_capability])
For more customization details, see:
docs/customization.mddocs/tools.mddocs/agents.md
Running Unit Tests
Tests live under the test/ directory and are written to be compatible with both pytest and the standard library unittest.
Recommended: pytest
From the repository root:
pip install pytest
pytest
Using unittest directly
If you prefer unittest, you can still run the suite with:
python -m unittest discover -s test -p "test_*.py"
Make sure required environment variables (e.g. TAVILY_API_KEY, OPENAI_API_KEY) are set, or that tests patch them appropriately (as in test/test_agent.py).
Metadata
Release files for pydantask 0.1.0a6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pydantask-0.1.0a6.tar.gz | 83.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydantask-0.1.0a6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 166.7 kB
Release files / pydantask-0.1.0a6.tar.gz
| Download URL | pydantask-0.1.0a6.tar.gz |
|---|---|
| Size | 83.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8e64ead1ace781f17559a6cf2e0553fef4267013f45920155baf73f99608e0e8
|
|
BLAKE2b-256 checksum How to use checksums |
3ca383ff4625e9db84294b538c629f1a719a5b092c50323d95bb84caf80186b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.
Transparency logRelease files / pydantask-0.1.0a6-py3-none-any.whl
| Download URL | pydantask-0.1.0a6-py3-none-any.whl |
|---|---|
| Size | 83.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
136a98967f1dfbfa60296d802060704888705ce12dcd1e934d36bfea294a1647
|
|
BLAKE2b-256 checksum How to use checksums |
c1901287fd755ed24e2032dd3541ea1ec56b8ba78c54c7a4d564f8e1d97e69cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 11, 2026.
Transparency log