This file provides context for AI agents working on the Dapr Python SDK. The project is the official Python SDK for Dapr (Distributed Application Runtime), enabling Python developers to build distributed applications using Dapr building blocks.
Repository: https://github.com/dapr/python-sdk License: Apache 2.0
Deeper documentation lives alongside the code. This root file gives you the big picture and tells you where to look. Each extension and the examples directory has its own
AGENTS.mdwith detailed architecture, APIs, and patterns.
dapr/ # Core SDK package
├── actor/ # Actor framework (virtual actor model)
├── aio/ # Async I/O modules
├── clients/ # Dapr clients (gRPC and HTTP)
├── common/ # Shared utilities
├── conf/ # Configuration (settings, environment)
├── proto/ # Auto-generated gRPC protobuf stubs (DO NOT EDIT)
├── serializers/ # JSON and pluggable serializers
└── version/ # Version metadata
ext/ # Extension packages (each is a separate PyPI package)
├── dapr-ext-workflow/ # Workflow authoring ← see ext/dapr-ext-workflow/AGENTS.md
├── dapr-ext-grpc/ # gRPC App extension ← see ext/dapr-ext-grpc/AGENTS.md
├── dapr-ext-fastapi/ # FastAPI integration ← see ext/dapr-ext-fastapi/AGENTS.md
├── dapr-ext-langgraph/ # LangGraph checkpointer ← see ext/dapr-ext-langgraph/AGENTS.md
├── dapr-ext-strands/ # Strands agent sessions ← see ext/dapr-ext-strands/AGENTS.md
└── flask_dapr/ # Flask integration ← see ext/flask_dapr/AGENTS.md
tests/ # Unit tests (mirrors dapr/ package structure)
├── examples/ # Output-based tests that run examples and check stdout
├── integration/ # Programmatic SDK tests using DaprClient directly
examples/ # User-facing example applications ← see examples/AGENTS.md
docs/ # Sphinx documentation source
tools/ # Build and release scripts
- Namespace packages: The
daprnamespace is shared across the core SDK and extensions viafind_namespace_packages. Extensions live inext/but install into thedapr.ext.*namespace. Do not add__init__.pyto namespace package roots in extensions. - Client architecture:
DaprGrpcClient(primary, high-performance) and HTTP-based clients. Both implement shared interfaces. - Actor model:
Actorbase class,ActorInterfacewith@actormethoddecorator,ActorProxy/ActorProxyFactoryfor client-side references,ActorRuntimefor server-side hosting. - Serialization: Pluggable via
Serializerbase class.DefaultJSONSerializeris the default. - Proto files: Auto-generated from Dapr proto definitions. Never edit files under
dapr/proto/directly.
Each extension is a separate PyPI package with its own pyproject.toml, setup.py, tests/, and AGENTS.md.
| Extension | Package | Purpose | Active development |
|---|---|---|---|
dapr-ext-workflow |
dapr.ext.workflow |
Durable workflow orchestration (durabletask vendored internally) | High — major focus area |
dapr-ext-grpc |
dapr.ext.grpc |
gRPC server for Dapr callbacks (methods, pub/sub, bindings, jobs) | Moderate |
dapr-ext-fastapi |
dapr.ext.fastapi |
FastAPI integration for pub/sub and actors | Moderate |
flask_dapr |
flask_dapr |
Flask integration for pub/sub and actors | Low |
dapr-ext-langgraph |
dapr.ext.langgraph |
LangGraph checkpoint persistence to Dapr state store | Moderate |
dapr-ext-strands |
dapr.ext.strands |
Strands agent session management via Dapr state store | New |
The examples/ directory contains user-facing example applications. These are validated by two test suites:
tests/examples/— Output-based tests that run examples viadapr runand check stdout for expected strings. Uses aDaprRunnerhelper to manage process lifecycle. Seeexamples/AGENTS.md.tests/integration/— Programmatic SDK tests that callDaprClientmethods directly and assert on return values, gRPC status codes, and SDK types. More reliable than output-based tests since they don't depend on print statement formatting. Seetests/integration/AGENTS.md.
Quick reference:
uv run pytest tests/examples/ # Run output-based example tests
uv run pytest tests/examples/test_state_store.py # Run a single example test
uv run pytest tests/integration/ # Run programmatic SDK tests
uv run pytest tests/integration/test_invoke.py # Run a single integration test- Minimum: Python 3.10
- Tested: 3.10, 3.11, 3.12, 3.13, 3.14
- Target version for tooling:
py310(ruff, mypy)
Install all packages in editable mode with dev dependencies:
uv sync --all-packages --group devTests use Python's built-in unittest framework with coverage. The vendored durabletask tests use pytest.
# Run all unit tests
uv run python -m unittest discover -v ./tests
# Extension tests (run each separately)
uv run python -m unittest discover -v ./ext/dapr-ext-workflow/tests
uv run pytest -m "not e2e" ./ext/dapr-ext-workflow/tests/durabletask/
uv run python -m unittest discover -v ./ext/dapr-ext-grpc/tests
uv run python -m unittest discover -v ./ext/dapr-ext-fastapi/tests
uv run python -m unittest discover -v ./ext/dapr-ext-langgraph/tests
uv run python -m unittest discover -v ./ext/dapr-ext-strands/tests
uv run python -m unittest discover -v ./ext/flask_dapr/tests
# Run linting and formatting
uv run ruff check --fix && uv run ruff format
# Run type checking
uv run mypy
# Run output-based example tests (requires Dapr runtime)
uv run pytest tests/examples/
# Run programmatic integration tests (requires Dapr runtime)
uv run pytest tests/integration/Formatter/Linter: Ruff (v0.14.1)
Key rules:
- Line length: 100 characters (E501 is currently ignored, but respect the 100-char target)
- Quote style: Single quotes
- Import sorting: isort-compatible (ruff
Irules) - Target: Python 3.10
- Excluded from linting:
.github/,dapr/proto/
Run formatting and lint fixes:
uv run ruff check --fix && uv run ruff formatType checking: MyPy
uv run mypyMyPy is configured to check: dapr/actor/, dapr/aio/, dapr/clients/, dapr/conf/, dapr/serializers/, ext/dapr-ext-grpc/, ext/dapr-ext-fastapi/, ext/flask_dapr/, and examples/demo_actor/. Proto stubs (dapr.proto.*) have errors ignored. Configuration lives in pyproject.toml under [tool.mypy].
- DCO required: Every commit must include a
Signed-off-byline. Usegit commit -sto add it automatically. - CI checks: Linting (ruff), unit tests (Python 3.10-3.14), type checking (mypy), and DCO verification run on all PRs.
- Branch targets: PRs go to
mainorrelease-*branches. - Tag-based releases: A single
v*tag triggers PyPI publishing for all packages (core SDK and all extensions).
When completing any task on this project, work through this checklist. Not every item applies to every change — use judgment — but always consider each one.
- Read the relevant existing source files before making changes
- Understand the existing patterns in the area you're modifying (naming, error handling, async vs sync)
- Check if there's both a sync and async variant that needs updating (see
dapr/aio/and extensionaio/subdirectories) - Read the relevant extension's
AGENTS.mdfor architecture and gotchas specific to that area
- Follow existing code style: single quotes, 100-char lines, Python 3.10+ syntax
- Do not edit files under
dapr/proto/— these are auto-generated - Do not add
__init__.pyfiles to namespace package roots in extensions
- Add or update unit tests under
tests/(core SDK) orext/*/tests/(extensions) - Tests use
unittest— follow the existing test patterns in the relevant directory - Verify tests pass:
python -m unittest discover -v ./tests(or the relevant test directory)
- Run
uv run ruff check --fix && uv run ruff formatand fix any remaining issues - Run
uv run mypyif you changed files covered by mypy (actor, aio, clients, conf, serializers, ext-grpc, ext-fastapi, flask_dapr)
- If you added a new user-facing feature or building block, add or update an example in
examples/ - Add a corresponding pytest test in
tests/examples/(output-based) and/ortests/integration/(programmatic) - If you changed output format of existing functionality, update expected output in
tests/examples/ - See
examples/AGENTS.mdfor full details on writing examples
- Update docstrings if you changed a public API's signature or behavior
- Update the relevant example README if the usage pattern changed
- Run
uv run ruff check --fix && uv run ruff format— linting must be clean - Run
uv run python -m unittest discover -v ./tests— all unit tests must pass - If you touched examples:
uv run pytest tests/examples/test_<example-name>.pyto validate locally - Commits must be signed off for DCO:
git commit -s
| File | Purpose |
|---|---|
pyproject.toml |
Package metadata, dependencies, ruff, mypy, and uv workspace config |
uv.lock |
Locked dependency versions (reproducible installs) |
setup.py |
PyPI publish helper (handles dev version suffixing) |
ext/*/pyproject.toml |
Extension package metadata and dependencies |
dapr/version/version.py |
SDK version string |
tests/examples/ |
Output-based tests that validate examples by checking stdout |
tests/integration/ |
Programmatic SDK tests using DaprClient directly |
- Namespace packages: Do not add
__init__.pyto the top-leveldapr/directory in extensions — it will break namespace package resolution. - Proto files: Never manually edit anything under
dapr/proto/. These are generated. - Extension independence: Each extension is a separate PyPI package. Core SDK changes should not break extensions; extension changes should not require core SDK changes unless intentional.
- DCO signoff: PRs will be blocked by the DCO bot if commits lack
Signed-off-by. Always usegit commit -s. - Ruff version pinned:
pyproject.tomlpinsruff==0.14.1in[dependency-groups].dev. Useuv sync --all-packages --group devto get the exact version. - Examples are tested by output matching: Changing output format (log messages, print statements) can break
tests/examples/. Always check expected output there when modifying user-visible output. - Background processes in examples: Examples that start background services (servers, subscribers) must include a cleanup step to stop them, or CI will hang.
- Workflow is the most active area: See
ext/dapr-ext-workflow/AGENTS.mdfor workflow-specific architecture and constraints.