|
| 1 | +# AGENTS.md — Dapr Python SDK |
| 2 | + |
| 3 | +This file provides context for AI agents working on the Dapr Python SDK. |
| 4 | +The project is the official Python SDK for [Dapr](https://dapr.io/) (Distributed Application Runtime), |
| 5 | +enabling Python developers to build distributed applications using Dapr building blocks. |
| 6 | + |
| 7 | +Repository: https://github.com/dapr/python-sdk |
| 8 | +License: Apache 2.0 |
| 9 | + |
| 10 | +> **Deeper documentation lives alongside the code.** This root file gives you the big picture and |
| 11 | +> tells you where to look. Each extension and the examples directory has its own `AGENTS.md` with |
| 12 | +> detailed architecture, APIs, and patterns. |
| 13 | +
|
| 14 | +## Project structure |
| 15 | + |
| 16 | +``` |
| 17 | +dapr/ # Core SDK package |
| 18 | +├── actor/ # Actor framework (virtual actor model) |
| 19 | +├── aio/ # Async I/O modules |
| 20 | +├── clients/ # Dapr clients (gRPC and HTTP) |
| 21 | +├── common/ # Shared utilities |
| 22 | +├── conf/ # Configuration (settings, environment) |
| 23 | +├── proto/ # Auto-generated gRPC protobuf stubs (DO NOT EDIT) |
| 24 | +├── serializers/ # JSON and pluggable serializers |
| 25 | +└── version/ # Version metadata |
| 26 | +
|
| 27 | +ext/ # Extension packages (each is a separate PyPI package) |
| 28 | +├── dapr-ext-workflow/ # Workflow authoring ← see ext/dapr-ext-workflow/AGENTS.md |
| 29 | +├── dapr-ext-grpc/ # gRPC App extension ← see ext/dapr-ext-grpc/AGENTS.md |
| 30 | +├── dapr-ext-fastapi/ # FastAPI integration ← see ext/dapr-ext-fastapi/AGENTS.md |
| 31 | +├── dapr-ext-langgraph/ # LangGraph checkpointer ← see ext/dapr-ext-langgraph/AGENTS.md |
| 32 | +├── dapr-ext-strands/ # Strands agent sessions ← see ext/dapr-ext-strands/AGENTS.md |
| 33 | +└── flask_dapr/ # Flask integration ← see ext/flask_dapr/AGENTS.md |
| 34 | +
|
| 35 | +tests/ # Unit tests (mirrors dapr/ package structure) |
| 36 | +examples/ # Integration test suite ← see examples/AGENTS.md |
| 37 | +docs/ # Sphinx documentation source |
| 38 | +tools/ # Build and release scripts |
| 39 | +``` |
| 40 | + |
| 41 | +## Key architectural patterns |
| 42 | + |
| 43 | +- **Namespace packages**: The `dapr` namespace is shared across the core SDK and extensions via `find_namespace_packages`. Extensions live in `ext/` but install into the `dapr.ext.*` namespace. Do not add `__init__.py` to namespace package roots in extensions. |
| 44 | +- **Client architecture**: `DaprGrpcClient` (primary, high-performance) and HTTP-based clients. Both implement shared interfaces. |
| 45 | +- **Actor model**: `Actor` base class, `ActorInterface` with `@actormethod` decorator, `ActorProxy`/`ActorProxyFactory` for client-side references, `ActorRuntime` for server-side hosting. |
| 46 | +- **Serialization**: Pluggable via `Serializer` base class. `DefaultJSONSerializer` is the default. |
| 47 | +- **Proto files**: Auto-generated from Dapr proto definitions. Never edit files under `dapr/proto/` directly. |
| 48 | + |
| 49 | +## Extension overview |
| 50 | + |
| 51 | +Each extension is a **separate PyPI package** with its own `setup.cfg`, `setup.py`, `tests/`, and `AGENTS.md`. |
| 52 | + |
| 53 | +| Extension | Package | Purpose | Active development | |
| 54 | +|-----------|---------|---------|-------------------| |
| 55 | +| `dapr-ext-workflow` | `dapr.ext.workflow` | Durable workflow orchestration via durabletask-dapr | **High** — major focus area | |
| 56 | +| `dapr-ext-grpc` | `dapr.ext.grpc` | gRPC server for Dapr callbacks (methods, pub/sub, bindings, jobs) | Moderate | |
| 57 | +| `dapr-ext-fastapi` | `dapr.ext.fastapi` | FastAPI integration for pub/sub and actors | Moderate | |
| 58 | +| `flask_dapr` | `flask_dapr` | Flask integration for pub/sub and actors | Low | |
| 59 | +| `dapr-ext-langgraph` | `dapr.ext.langgraph` | LangGraph checkpoint persistence to Dapr state store | Moderate | |
| 60 | +| `dapr-ext-strands` | `dapr.ext.strands` | Strands agent session management via Dapr state store | New | |
| 61 | + |
| 62 | +## Examples (integration test suite) |
| 63 | + |
| 64 | +The `examples/` directory serves as both user-facing documentation and the project's integration test suite. Examples are validated in CI using [mechanical-markdown](https://pypi.org/project/mechanical-markdown/), which executes bash code blocks from README files and asserts expected output. |
| 65 | + |
| 66 | +**See `examples/AGENTS.md`** for the full guide on example structure, validation, mechanical-markdown STEP blocks, and how to add new examples. |
| 67 | + |
| 68 | +Quick reference: |
| 69 | +```bash |
| 70 | +tox -e examples # Run all examples (needs Dapr runtime) |
| 71 | +tox -e example-component -- state_store # Run a single example |
| 72 | +cd examples && ./validate.sh state_store # Run directly |
| 73 | +``` |
| 74 | + |
| 75 | +## Python version support |
| 76 | + |
| 77 | +- **Minimum**: Python 3.10 |
| 78 | +- **Tested**: 3.10, 3.11, 3.12, 3.13, 3.14 |
| 79 | +- **Target version for tooling**: `py310` (ruff, mypy) |
| 80 | + |
| 81 | +## Development setup |
| 82 | + |
| 83 | +Install all packages in editable mode with dev dependencies: |
| 84 | + |
| 85 | +```bash |
| 86 | +pip install -r dev-requirements.txt \ |
| 87 | + -e . \ |
| 88 | + -e ext/dapr-ext-workflow/ \ |
| 89 | + -e ext/dapr-ext-grpc/ \ |
| 90 | + -e ext/dapr-ext-fastapi/ \ |
| 91 | + -e ext/dapr-ext-langgraph/ \ |
| 92 | + -e ext/dapr-ext-strands/ \ |
| 93 | + -e ext/flask_dapr/ |
| 94 | +``` |
| 95 | + |
| 96 | +## Running tests |
| 97 | + |
| 98 | +Tests use Python's built-in `unittest` framework with `coverage`. Run via tox: |
| 99 | + |
| 100 | +```bash |
| 101 | +# Run all unit tests (replace 311 with your Python version) |
| 102 | +tox -e py311 |
| 103 | + |
| 104 | +# Run linting and formatting |
| 105 | +tox -e ruff |
| 106 | + |
| 107 | +# Run type checking |
| 108 | +tox -e type |
| 109 | + |
| 110 | +# Validate examples (requires Dapr runtime) |
| 111 | +tox -e examples |
| 112 | +``` |
| 113 | + |
| 114 | +To run tests directly without tox: |
| 115 | + |
| 116 | +```bash |
| 117 | +# Core SDK tests |
| 118 | +python -m unittest discover -v ./tests |
| 119 | + |
| 120 | +# Extension tests (run each separately) |
| 121 | +python -m unittest discover -v ./ext/dapr-ext-workflow/tests |
| 122 | +python -m unittest discover -v ./ext/dapr-ext-grpc/tests |
| 123 | +python -m unittest discover -v ./ext/dapr-ext-fastapi/tests |
| 124 | +python -m unittest discover -v ./ext/dapr-ext-langgraph/tests |
| 125 | +python -m unittest discover -v ./ext/dapr-ext-strands/tests |
| 126 | +python -m unittest discover -v ./ext/flask_dapr/tests |
| 127 | +``` |
| 128 | + |
| 129 | +## Code style and linting |
| 130 | + |
| 131 | +**Formatter/Linter**: Ruff (v0.14.1) |
| 132 | + |
| 133 | +Key rules: |
| 134 | +- **Line length**: 100 characters (E501 is currently ignored, but respect the 100-char target) |
| 135 | +- **Quote style**: Single quotes |
| 136 | +- **Import sorting**: isort-compatible (ruff `I` rules) |
| 137 | +- **Target**: Python 3.10 |
| 138 | +- **Excluded from linting**: `.github/`, `dapr/proto/` |
| 139 | + |
| 140 | +Run formatting and lint fixes: |
| 141 | + |
| 142 | +```bash |
| 143 | +ruff check --fix |
| 144 | +ruff format |
| 145 | +``` |
| 146 | + |
| 147 | +**Type checking**: MyPy |
| 148 | + |
| 149 | +```bash |
| 150 | +mypy --config-file mypy.ini |
| 151 | +``` |
| 152 | + |
| 153 | +MyPy is configured to check: `dapr/actor/`, `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. |
| 154 | + |
| 155 | +## Commit and PR conventions |
| 156 | + |
| 157 | +- **DCO required**: Every commit must include a `Signed-off-by` line. Use `git commit -s` to add it automatically. |
| 158 | +- **CI checks**: Linting (ruff), unit tests (Python 3.10-3.14), type checking (mypy), and DCO verification run on all PRs. |
| 159 | +- **Branch targets**: PRs go to `main` or `release-*` branches. |
| 160 | +- **Tag-based releases**: Tags like `v*`, `workflow-v*`, `grpc-v*`, `fastapi-v*`, `flask-v*`, `langgraph-v*`, `strands-v*` trigger PyPI publishing for the corresponding package. |
| 161 | + |
| 162 | +## Agent task checklist |
| 163 | + |
| 164 | +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. |
| 165 | + |
| 166 | +### Before writing code |
| 167 | + |
| 168 | +- [ ] Read the relevant existing source files before making changes |
| 169 | +- [ ] Understand the existing patterns in the area you're modifying (naming, error handling, async vs sync) |
| 170 | +- [ ] Check if there's both a sync and async variant that needs updating (see `dapr/aio/` and extension `aio/` subdirectories) |
| 171 | +- [ ] Read the relevant extension's `AGENTS.md` for architecture and gotchas specific to that area |
| 172 | + |
| 173 | +### Implementation |
| 174 | + |
| 175 | +- [ ] Follow existing code style: single quotes, 100-char lines, Python 3.10+ syntax |
| 176 | +- [ ] Do not edit files under `dapr/proto/` — these are auto-generated |
| 177 | +- [ ] Do not add `__init__.py` files to namespace package roots in extensions |
| 178 | + |
| 179 | +### Unit tests |
| 180 | + |
| 181 | +- [ ] Add or update unit tests under `tests/` (core SDK) or `ext/*/tests/` (extensions) |
| 182 | +- [ ] Tests use `unittest` — follow the existing test patterns in the relevant directory |
| 183 | +- [ ] Verify tests pass: `python -m unittest discover -v ./tests` (or the relevant test directory) |
| 184 | + |
| 185 | +### Linting and type checking |
| 186 | + |
| 187 | +- [ ] Run `ruff check --fix && ruff format` and fix any remaining issues |
| 188 | +- [ ] Run `mypy --config-file mypy.ini` if you changed files covered by mypy (actor, clients, conf, serializers, ext-grpc, ext-fastapi, flask_dapr) |
| 189 | + |
| 190 | +### Examples (integration tests) |
| 191 | + |
| 192 | +- [ ] If you added a new user-facing feature or building block, add or update an example in `examples/` |
| 193 | +- [ ] Ensure the example README has `<!-- STEP -->` blocks with `expected_stdout_lines` so it is validated in CI |
| 194 | +- [ ] If you added a new example, register it in `tox.ini` under `[testenv:examples]` |
| 195 | +- [ ] If you changed output format of existing functionality, update `expected_stdout_lines` in affected example READMEs |
| 196 | +- [ ] See `examples/AGENTS.md` for full details on writing examples |
| 197 | + |
| 198 | +### Documentation |
| 199 | + |
| 200 | +- [ ] Update docstrings if you changed a public API's signature or behavior |
| 201 | +- [ ] Update the relevant example README if the usage pattern changed |
| 202 | + |
| 203 | +### Final verification |
| 204 | + |
| 205 | +- [ ] Run `tox -e ruff` — linting must be clean |
| 206 | +- [ ] Run `tox -e py311` (or your Python version) — all unit tests must pass |
| 207 | +- [ ] If you touched examples: `tox -e example-component -- <example-name>` to validate locally |
| 208 | +- [ ] Commits must be signed off for DCO: `git commit -s` |
| 209 | + |
| 210 | +## Important files |
| 211 | + |
| 212 | +| File | Purpose | |
| 213 | +|------|---------| |
| 214 | +| `setup.cfg` | Core package metadata and dependencies | |
| 215 | +| `setup.py` | Package build script (handles dev version suffixing) | |
| 216 | +| `pyproject.toml` | Ruff configuration | |
| 217 | +| `tox.ini` | Test environments and CI commands | |
| 218 | +| `mypy.ini` | Type checking configuration | |
| 219 | +| `dev-requirements.txt` | Development/test dependencies | |
| 220 | +| `dapr/version/__init__.py` | SDK version string | |
| 221 | +| `ext/*/setup.cfg` | Extension package metadata and dependencies | |
| 222 | +| `examples/validate.sh` | Entry point for mechanical-markdown example validation | |
| 223 | + |
| 224 | +## Gotchas |
| 225 | + |
| 226 | +- **Namespace packages**: Do not add `__init__.py` to the top-level `dapr/` directory in extensions — it will break namespace package resolution. |
| 227 | +- **Proto files**: Never manually edit anything under `dapr/proto/`. These are generated. |
| 228 | +- **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. |
| 229 | +- **DCO signoff**: PRs will be blocked by the DCO bot if commits lack `Signed-off-by`. Always use `git commit -s`. |
| 230 | +- **Ruff version pinned**: Dev requirements pin `ruff === 0.14.1`. Use this exact version to match CI. |
| 231 | +- **Examples are integration tests**: Changing output format (log messages, print statements) can break example validation. Always check `expected_stdout_lines` in example READMEs when modifying user-visible output. |
| 232 | +- **Background processes in examples**: Examples that start background services (servers, subscribers) must include a cleanup step to stop them, or CI will hang. |
| 233 | +- **Workflow is the most active area**: See `ext/dapr-ext-workflow/AGENTS.md` for workflow-specific architecture and constraints. |
0 commit comments