Skip to main content

Durable Workflows for AI agents

Make your AI agents resilient to failure and outages

The diagrid package is an extension SDK for the open-source Dapr project to build durable, fault-tolerant AI agents. It integrates seamlessly with popular agent frameworks, wrapping them in Dapr Workflows to ensure agents can recover from failures, persist state across restarts, and scale effectively.

Get started with Diagrid Catalyst for free.

Community

Have questions, hit a bug, or want to share what you're building? Join the Diagrid Community Discord to connect with the team and other users.

Features

  • Multi-Framework Support: Native integrations for LangGraph, CrewAI, Google ADK, Strands, PydanticAI, OpenAI Agents, Claude Agent SDK, LangChain, Smolagents, LangChain Deep Agents, and HolmesGPT.
  • Durability: Agent state is automatically persisted in the database of your choice. If your process crashes, the agent resumes from the last successful step.
  • Fault Tolerance: Built-in retries and error handling powered by Dapr.
  • Observability: Deep insights into agent execution, tool calls, and state transitions.

Installation

Install the base package along with the extension for your chosen framework:

# For LangGraph
pip install "diagrid[langgraph]"

# For CrewAI
pip install "diagrid[crewai]"

# For Google ADK
pip install "diagrid[adk]"

# For Strands
pip install "diagrid[strands]"

# For Pydantic AI
pip install "diagrid[pydantic_ai]"

# For OpenAI Agents
pip install "diagrid[openai_agents]"

# For LangChain Deep Agents
pip install "diagrid[deepagents]"

# For Claude Agent SDK
pip install "diagrid[claude_agents]"

# For LangChain
pip install "diagrid[langchain]"

# For Smolagents
pip install "diagrid[smolagents]"

# For HolmesGPT (install in a dedicated environment — see note below)
pip install "diagrid[holmesgpt]"

Note: diagrid[holmesgpt] is intentionally not part of diagrid[all]. HolmesGPT ships strict pins on fastapi, uvicorn, cachetools, mcp, and httpx[socks] that conflict with the looser constraints used by the other agent extras. Install it in its own environment.

Verified identity

Catalyst signs the calling user's identity into an X-Diagrid-User-Token header on every inbound request. diagrid.identity verifies it before your handler runs, and puts it back on the calls your agent makes on the caller's behalf.

pip install "diagrid[identity]"

Two lines wire it up:

from diagrid.identity import OAuthConfig
from diagrid.identity.asgi import OAuthMiddleware

app.add_middleware(OAuthMiddleware, config=OAuthConfig(scopes={"agent.invoke"}))

Reading the verified caller

from fastapi import Request

from diagrid.identity.asgi import verified_user


@app.post("/invoke")
async def invoke(request: Request):
    user = verified_user(request)  # VerifiedUser | None
    return {
        "subject": user.subject,
        "tenant": user.tenant,
        "scopes": list(user.scopes),
        "admin": user.has_scope("admin.write"),
    }

VerifiedUser carries subject, tenant, scopes, claims and issuer_id, plus has_scope(scope). scopes keeps set semantics but iterates in sorted order, so a response that echoes it is stable across requests and across SDKs.

verified_user() returns None only when the request carried no token and require_auth=False allowed it through. A token that is present is always verified, and an invalid one never reaches the handler.

Outbound calls on behalf of the caller

The sidecar mints the token for the inbound request, so an outbound call has to carry it explicitly. Use the identity-aware client and it rides along:

from diagrid.identity.http import AsyncClient

client = AsyncClient()  # an httpx2.AsyncClient that sends the caller's token

The token is read from the inbound request context at send time, not baked in at construction, so one long-lived client is safe to share: concurrent requests each carry their own caller's token. The header is cleared before it is set, and it only ever travels to the origin the caller addressed — a redirect away from that origin drops it.

For a client you cannot replace, install the same behaviour as a request hook:

import httpx2

from diagrid.identity.http import attach_identity_headers_async

client = httpx2.AsyncClient(event_hooks={"request": [attach_identity_headers_async]})

attach_identity_headers is the synchronous counterpart. A call made with no inbound user context — a cron, pub/sub or scheduled trigger — proceeds unauthenticated with the header omitted rather than raising.

OAuthConfig

Field Type Default Meaning
scopes FrozenSet[str] frozenset() Scopes every caller must carry; a token short of one gets 403.
issuer Optional[str] None Expected iss. Discovered when unset.
audience Optional[str] None Expected aud. Discovered when unset.
jwks_uri Optional[str] None JWKS endpoint. Discovered when unset.
require_auth bool True Reject a request that carries no token. The default is fail-closed, and so is OAuthConfig().
allow_insecure_jwks bool False Opt in to a plaintext JWKS URI on a non-loopback host. The key set is the root of trust, so https is otherwise required; loopback is exempt because that is where the local sidecar serves. It relaxes the rule to plain http only — a file:// JWKS URI, or any other scheme, stays refused.

Discovery precedence

Coordinates come from four sources, in this order:

  1. Explicit config — whatever of issuer, audience and jwks_uri you set on OAuthConfig.
  2. The local sidecarGET http://127.0.0.1:$DAPR_HTTP_PORT/v1.0/metadata (CATALYST_DAPR_HTTP_PORT wins if both are set). Local is tried before remote so a deployed in-cluster app keeps using the loopback call rather than a network round trip.
  3. The remote sidecarGET $DAPR_HTTP_ENDPOINT/v1.0/metadata, which is the diagrid dev run shape: the app runs on your machine against a Catalyst-hosted sidecar, so nothing is listening on 127.0.0.1. DAPR_API_TOKEN is sent as the dapr-api-token header when it is set.
  4. Environment variablesDIAGRID_DP_SENTRY_ISSUER and DIAGRID_DP_SENTRY_AUDIENCE.

jwks_uri resolves explicit first, then the value the sidecar advertises — adopted only when the discovered issuer is the issuer being verified, so a pinned issuer is never checked against a foreign issuer's keys — and otherwise issuer + /jwks.json. If nothing resolves, a token-carrying request is answered 503 oauth.not_configured rather than let through.

Tokens are accepted for RS256 and ES256 only, must carry exp, iss and sub, are allowed 120s of clock skew, and the key set is cached for 300s.

Supplying the verifier yourself

OAuthMiddleware builds its own verifier from the coordinates above. Pass one instead — a pre-built JWKSVerifier, or any object satisfying the TokenVerifier protocol — when the app resolves coordinates its own way, or to stand a double in during a test:

app.add_middleware(OAuthMiddleware, config=OAuthConfig(), verifier=my_verifier)

The seam is on the middleware, not on OAuthConfig, which stays pure policy.

Rejections

Every rejection is {"error": "<code>"} with Cache-Control: no-store. The codes are constants on OAuthErrorCodes.

Status Code When
401 oauth.missing_token No X-Diagrid-User-Token, and require_auth=True.
401 oauth.expired exp is in the past, beyond the skew allowance.
401 oauth.invalid_issuer iss is not the expected issuer.
401 oauth.invalid_audience aud is not the expected audience.
401 oauth.invalid_signature Signature does not verify against the key set.
401 oauth.decode_error The token is malformed.
401 oauth.invalid_token Any other claim validation failure.
403 oauth.missing_scope Verified, but short of OAuthConfig.scopes.
503 oauth.not_configured No identity coordinates could be resolved.
503 oauth.verifier_unavailable Key material has not loaded yet.

Prerequisites

  • Python: 3.11 or higher

Examples & Quickstarts

Two paths to your first running agent:

Getting Started with Diagrid Catalyst

Diagrid Catalyst is a fully managed workflow engine for AI agents, built on the open-source CNCF Dapr Workflow project. It's the easiest way to test the different agentic integrations for free.

See quickstarts to get started in less than 5 minutes.

How It Works

This SDK leverages Dapr Workflows to orchestrate agent execution.

  1. Orchestration: The agent's control loop is modeled as a workflow.
  2. Activities: Each tool execution or LLM call is modeled as a durable activity.
  3. State Store: Dapr saves the workflow state to a configured state store (e.g., Redis, CosmosDB) after every step.

Your code can run anywhere (local machine, Kubernetes, EC2, etc.) while the fully managed workflow engine takes care of the agent's execution state, making it crash-proof and resilient to any outage or failure.

Release files for diagrid 0.4.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diagrid 0.4.7
File Size Uploaded
diagrid-0.4.7.tar.gz 185.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for diagrid 0.4.7
File Interpreter ABI Platform
diagrid-0.4.7-py3-none-any.whl Python 3 none any Details

Total release size: 426.3 kB

Release files / diagrid-0.4.7.tar.gz

Download URL diagrid-0.4.7.tar.gz
Size 185.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b854eb467cefb10aee14353a3e7da3802f1ed42d0a69ebc32a3793cf5cdc83a0
BLAKE2b-256 checksum
How to use checksums
d918052ab103b87327969eafb8bd32d90c6e54cdd6b9386e9ab1d6a61e2cbf2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release files / diagrid-0.4.7-py3-none-any.whl

Download URL diagrid-0.4.7-py3-none-any.whl
Size 241.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5487d88524bb3e10766e313bf2e41914f849ba0d1557c261bff25afde7c37a97
BLAKE2b-256 checksum
How to use checksums
8eaad8537068a394462b9a272cb4e9463c431f636179f9afacc175e3065a7916
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

This release

0.4.7 This release

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page