Create a Python Agent Application
Overview
This skill describes how to create a durable AI agent application in Python. Two paths are supported:
- Native — the
dapr-agentsSDK. This is the Dapr Agents framework proper; it is Python-only. ItsDurableAgentruns on Dapr Workflow, reaches the LLM through a Dapr conversation component, and persists conversation memory in a Dapr state store. - Framework wrappers — the
diagriddistribution, which runs an agent you have already written in another framework (LangGraph, CrewAI, Strands, …) on Dapr Workflow so that each node / LLM call / tool call becomes a durable activity. One distribution, one extra per framework.
Single agent or coordinator + specialists, either way.
Execution Order
You MUST follow these phases in strict order:
- Check specification — Check if the user specified what needs to be built.
- Project Setup — Create all files and folders.
- Verify — Verify that the project builds.
- Create README.md — Create a readme that summarizes what is built and how to run & test the application. Do not provide instructions at the end of this phase.
- Show final message — Your LAST output MUST be EXACTLY the message defined in the
## Show final messagesection. Do NOT add any other text, summary, or commentary after it.
Check specification
If you don't have enough context what to build, ask the user the following clarifying questions one by one using an interview style:
- What is the purpose of the agent (or agent team)? This becomes the agent's
roleandinstructions. - Topology: a single agent, or a coordinator + N specialists?
- Framework:
dapr-agents(native, the default) or one of thediagridwrapper extras. Resolve the wrapper list at this point rather than reciting one — see "Resolving the framework list" below. - Pattern (only if Q3 selected native
dapr-agentsAND Q2 selected single-agent):augmented-llm(default),prompt-chaining,routing,parallelization,orchestrator-workers, orevaluator-optimizer. Skip this question entirely if the user picked a wrapper extra — those frameworks define their own agent loop and the pattern concept does not apply. - Tool definitions: name, purpose, and argument schema for each tool the agent should expose.
- LLM provider: OpenAI, Anthropic, Google Gemini, or local Ollama. Native
dapr-agentsroutes this through a Dapr conversation component; wrappers usually let the wrapped framework call the provider directly with an API key from the environment. - Include observability by default? (recommended: yes for native
dapr-agents; defaultnofor wrappers — they ship their own observability.) - Project name — used as the folder name. Don't use spaces.
Resolving the framework list
The wrapper extras live in one place — the [project.optional-dependencies] table of diagridio/python-ai's pyproject.toml — and PyPI republishes that table verbatim as the distribution's provides_extra metadata. Read it instead of hardcoding it:
curl -s https://pypi.org/pypi/diagrid/json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['info']['version']); print('\n'.join(e for e in d['info']['provides_extra'] if e not in ('agent-core','all')))"
Offer the user the extras that command prints. agent-core is the shared base every extra pulls in, and all is a meta-extra — neither is a framework choice, so both are filtered out above.
If the command fails (no network), fall back to the snapshot in REFERENCE.md and tell the user it is a snapshot with a date on it, so a missing framework is understood as staleness rather than as unsupported.
Prerequisites
The following must be installed by the user before this skill can run:
- Python
>=3.11,<3.14— the bound bothdapr-agentsanddiagriddeclare - uv (Astral)
- Docker or Podman
- Dapr CLI (version 1.18+)
- At least one LLM provider env var (
OPENAI_API_KEY,ANTHROPIC_API_KEY,GOOGLE_API_KEY) or a local Ollama instance
Additional runtime dependencies (handled during project setup):
- Python package:
dapr-agents>=1.0(native) ordiagrid[<extra>]>=0.4(wrappers). These are floors, not pins — the exact resolved set is captured inuv.lockduring Verify. SeeREFERENCE.md.
Optional, for inspecting workflow runs locally:
- The Diagrid Dev Dashboard is a separate container the user starts themselves —
dapr initdoes not provision it:docker run -p 8080:8080 ghcr.io/diagridio/diagrid-dashboard:latest
Project Setup
Create the project root folder inside the current location where the terminal is open:
mkdir <ProjectRoot>
cd <ProjectRoot>
The should start with the and end with -agent: -agent.
Folder structure (single agent)
<ProjectRoot>/
├── .gitignore
├── dapr.yaml
├── local.http
├── docker-compose.observability.yaml # (native only, if observability enabled)
├── resources/
│ ├── agent-memory.yaml
│ ├── agent-workflow.yaml
│ ├── llm-provider.yaml
│ └── tracing.yaml # (native only, if observability enabled)
└── <ProjectName>/
├── pyproject.toml
├── main.py
├── tools.py
├── models.py
└── logging_config.py # (native only, if observability enabled)
Folder structure (coordinator + specialists)
<ProjectRoot>/
├── .gitignore
├── dapr.yaml
├── local.http
├── docker-compose.observability.yaml # (native only)
├── resources/
│ ├── agent-memory.yaml
│ ├── agent-workflow.yaml
│ ├── agent-pubsub.yaml
│ ├── agent-registry.yaml
│ ├── llm-provider.yaml
│ └── tracing.yaml # (native only)
├── coordinator/
│ ├── pyproject.toml
│ ├── main.py
│ ├── tools.py
│ ├── models.py
│ └── logging_config.py # (native only, if observability enabled)
└── <specialist-N>/
├── pyproject.toml
├── main.py
├── tools.py
├── models.py
└── logging_config.py # (native only, if observability enabled)
.gitignore
Python .gitignore file in the project root. See REFERENCE.md.
dapr.yaml
Multi-app run file. Single-agent: see ../shared/agent-dapr-yaml-single.md. Multi-agent: see ../shared/agent-dapr-yaml-multi.md.
resources/agent-memory.yaml
Conversation memory state store. See ../shared/agent-statestore-memory.md.
resources/agent-workflow.yaml
Workflow state store (actor-enabled). See ../shared/agent-statestore-workflow.md.
resources/agent-pubsub.yaml (multi-agent only)
Pub/sub component for handoff. See ../shared/agent-pubsub-redis.md.
resources/agent-registry.yaml (multi-agent only)
Agent discovery state store. See ../shared/agent-statestore-registry.md.
resources/llm-provider.yaml
Dapr Conversation component. Pick one: OpenAI | Anthropic | Ollama.
resources/tracing.yaml (native, observability on)
Dapr Configuration with tracing enabled. See ../shared/agent-tracing-zipkin.md (default) or ../shared/agent-tracing-otlp.md.
docker-compose.observability.yaml (native, observability on)
Local Zipkin + Prometheus + Grafana. See ../shared/agent-observability-stack.md.
pyproject.toml
Python config file. Dependencies depend on the framework choice — see REFERENCE.md.
main.py
Agent entrypoint. See REFERENCE.md for the native template and for how to derive the wrapper template from the wrapper's own README.
tools.py
Tool definitions. See ../shared/agent-tools-python.md; tools for a wrapper project are defined with the wrapped framework's own decorator, not with dapr_agents.tool.
models.py
Pydantic input/output types. See REFERENCE.md.
logging_config.py (native, observability on)
Structured logging. See ../shared/agent-logging-python.md.
local.http
HTTP request file for testing the agent endpoints. See REFERENCE.md.
Verify
IMPORTANT: After Project Setup you MUST run these exact verification instructions:
- Run
uv venvin each<ProjectName>folder to create a virtual environment. - Run
uv syncin each<ProjectName>folder to resolve and install dependencies. This writesuv.locknext topyproject.toml. - Confirm
uv.lockexists and instruct the user to commit it — the>=floors inpyproject.tomlkeep the project on supported versions, anduv.lockis what makes a checkout reproduce byte-for-byte.
Create README.md
IMPORTANT: After Verify you MUST run these instructions:
Create a README.md file inside the folder.
The README contains the following sections:
- Summary of what this folder contains.
- Architecture description that explains the technology stack (which framework, which LLM provider, which state/pubsub components). DO NOT suggest to run Redis separately since it's part of the Dapr installation and is running in a container already.
- A mermaid diagram of the agent (or agent team) that shows the role, tools, and (if multi-agent) the pub/sub topics.
- How to start the application using the Dapr CLI (
dapr run -f .). - How to call the agent endpoints (POST the task, GET the workflow state). Include curl examples and link to
local.http. - Observability section (native only, observability on): how to start the observability stack (
docker compose -f docker-compose.observability.yaml up -d), the Zipkin URL (http://localhost:9411), Grafana URL (http://localhost:3000), and Prometheus URL (http://localhost:9099). Mention the Diagrid Dev Dashboard as a separate, optional container the reader starts themselves (docker run -p 8080:8080 ghcr.io/diagridio/diagrid-dashboard:latest→ http://localhost:8080) — it is not part ofdapr init. - How to run with Diagrid Catalyst:
../shared/running-with-catalyst.md.
See REFERENCE.md for the pyproject.toml templates, the native main.py, the wrapper entry-point table, tool patterns, and observability wiring.
Show final message
IMPORTANT: This is the LAST step. After Create README.md, your final output MUST be ONLY the message below — no preamble, no summary, no additional commentary, only replace the with the actual value:
The agent application is created. Open the README.md file in the folder for a summary and instructions for running locally.