Every payload that crosses the worker-protocol boundary is codec-tagged.
Durable Workflow 2.0 has one public payload codec:
avro.
The Python SDK rejects JSON-tagged, unknown, and untagged durable payloads
instead of selecting another decoder. See the
Avro Value protocol.
### Avro support is built in
The pinned 2.0 SDK artifact pulls in `fastavro` as a runtime dependency, so
every outgoing surface (`start_workflow`, `signal_workflow`, `query_workflow`,
`update_workflow`, activity result encoding, schedule actions) emits
Avro-tagged payloads through the optimized production path. There is no
optional codec extra to install.
### Fixed typed values
The SDK explicitly selects named branches in the shared
`durable_workflow.protocol.Value` schema. It does not JSON-encode the value
inside Avro. Integers and doubles, strings and bytes, booleans and integers,
and lists and maps therefore remain distinct across SDKs. The wire uses Avro
single-object framing and the schema fingerprint; unknown fingerprints fail
with `unsupported_payload_schema`.
Every client and worker surface works end-to-end on the Avro default:
- **Client starts, signals, queries, updates** — `start_workflow`, `signal_workflow`, `query_workflow`, and `update_workflow` emit `payload_codec = "avro"` payloads through the fixed Value schema. A Python client can therefore drive workflows that PHP and other polyglot SDKs will replay, and vice-versa.
- **Activity worker** — Avro-tagged activity arguments decode transparently. The worker encodes activity results as Avro so PHP, Python, and future SDK workers share one payload boundary.
- **Activity failures** — `fail_activity_task(..., details=...)` sends `failure.details` as a `{codec, blob}` envelope. The server records the blob plus `details_payload_codec`, so diagnostic failure data from Python workers remains language-neutral in history exports and observability views.
- **Workflow worker history replay** — Avro-tagged start input and activity result events are decoded during replay, so a Python workflow can participate in an Avro-coded run.
- **Workflow query tasks** — Server-routed query tasks carry Avro-tagged workflow arguments, query arguments, and replay history. The worker returns the query result as an Avro envelope.
### Running a Python activity worker against a v2 run
No codec configuration is needed. The SDK validates `payload_codec` before
decoding every claim, accepts only `avro`, runs the activity, and returns an
Avro-tagged result. Any other tag fails closed with
`unsupported_payload_codec`; the worker never sniffs or guesses the format.
### Types that round-trip cleanly across Python and PHP
| Python type | Avro Value branch | PHP type |
|-------------|------|----------|
| `str` | `StringValue` | `string` |
| `bytes` | `BytesValue` | `AvroBinaryValue` |
| `int` | `LongValue` | `int` |
| `float` | `DoubleValue` | `float` |
| `bool` | `BooleanValue` | `bool` |
| `None` | `null` | `null` |
| `list` | `ArrayValue` | `array` (list) |
| `dict[str, ...]` | `MapValue` | `array` (string-keyed map) |
Adapt Python-specific types such as dataclasses, sets, tuples, and datetime
objects to canonical strings, integers, maps, or lists before using them as
workflow or activity values.
## Running Against a Shared Server
The [Quickstart](#quickstart) above shows how to bring up a local server with
the published Docker image. In a team environment you usually point the Python
worker at an existing server (staging, production, or a shared dev instance):
```python
from durable_workflow import Client
client = Client(
"https://workflow.example.internal",
control_token="team-orders-operator-token",
worker_token="team-orders-worker-token",
namespace="team-orders",
)
```
Set the `namespace` argument to whichever tenant namespace the shared server has
provisioned for your team, and use the credentials issued for that namespace.
The Server operator manages namespace creation; see the
[Server guide](/docs/polyglot/server) for details.
The same constructor supports a Cloud managed runtime. Use the namespace's
Cloud-provided runtime URL and namespace value, set `control_token` to the
client runtime credential, and set `worker_token` to the worker runtime
credential. Cloud provisions the namespace; do not substitute a self-hosted
Server address. See
[Cloud Managed Runtime](/docs/polyglot/cloud-control-plane).
# Rust Cloud Quickstart
:::caution Controlled early access
Durable Workflow Cloud is available through controlled early access. Use this
guide only after Cloud has provisioned a namespace and two role-scoped runtime
credentials. The generally available Rust journey does not require Cloud; start
with the [Rust SDK guide](./rust.md) or run `scripts/playground rust` against
the playground's default local runtime.
:::
The Sample App exposes one symmetric playground for PHP, Python, and Rust. This
page selects Rust and changes only the runtime target. The corresponding
[PHP](./php.md) and [Python](./python.md) SDK paths use the same command with
`php` or `python`; the [Sample App playground
contract](https://github.com/durable-workflow/sample-app/blob/main/README.md#symmetric-sdk-playground)
documents all three choices.
The playground resolves the current stable artifact versions from the Sample
App's machine-owned metadata. Use those generated versions instead of copying
version numbers into these commands or adding a separate SDK installation step.
## 1. Open the prepared Sample App
[Create a Codespace from the Sample App `main`
branch](https://codespaces.new/durable-workflow/sample-app?quickstart=1&ref=main),
wait for setup to finish, and open a terminal at the repository root. The
prepared image contains the SDK toolchains and `dw` required by the shared
playground.
Cloud provides the runtime URL, runtime namespace, and two role credentials.
Choose an application task queue, then export these placeholders only after
replacing them with the corresponding values:
```bash
export DURABLE_WORKFLOW_RUNTIME_URL='