# Pyrula > Durable agents and workflows for Python: record a run, rerun it with a change, keep it as a test. Every page below is served as Markdown. https://docs.pyrula.io/llms-full.txt holds them all in one file, except the API reference under Optional. ## Overview - [Pyrula](https://docs.pyrula.io/index.md): Durable agents and workflows for Python. Record a run, rerun it with a change, keep it as a test. ## Get started - [Choosing a store](https://docs.pyrula.io/getting-started/choosing-a-store.md): Memory, SQLite, Valkey, or Valkey with a Postgres archive: where runs live, how far each store goes and what it refuses. - [Connect to Pyrula Cloud](https://docs.pyrula.io/getting-started/cloud.md): Scaffold an app, export one key, run pyrula dev and open the run in Pyrula Cloud. - [Coming from another tool](https://docs.pyrula.io/getting-started/coming-from.md): Concept maps from Pydantic AI, LangGraph, Celery, Temporal and FastAPI to Pyrula, with a runnable example for each. - [Coming from Celery](https://docs.pyrula.io/getting-started/coming-from/celery.md): Move a Celery task module to Pyrula workflows and call it from sync code with the blocking client: a concept map, the scaffold and an executed example. - [Coming from FastAPI](https://docs.pyrula.io/getting-started/coming-from/fastapi.md): Move work out of FastAPI request handlers and background tasks into durable Pyrula runs, with the run endpoints mounted on your app: a concept map, the scaffold and an executed example. - [Coming from LangGraph](https://docs.pyrula.io/getting-started/coming-from/langgraph.md): Keep your LangGraph graph, swap the chat model for a durable one and run the graph inside a Pyrula agent: a concept map, the scaffold and an executed example. - [Coming from Pydantic AI](https://docs.pyrula.io/getting-started/coming-from/pydantic-ai.md): Keep your Pydantic AI agent and make it durable on Pyrula with PyrulaDurability: a concept map, the scaffold and an executed example. - [Coming from Temporal](https://docs.pyrula.io/getting-started/coming-from/temporal.md): Map Temporal workflows, activities, signals, queries, updates, child workflows, patching and schedules to Pyrula: a concept map and an executed example. - [Deploy a worker](https://docs.pyrula.io/getting-started/deploy-a-worker.md): Run a workflow or agent worker in a container with probes, a clean SIGTERM drain, and Compose, Kubernetes and Render recipes. - [Add one boundary to an existing app](https://docs.pyrula.io/getting-started/existing-app.md): Wrap one function you already have as a recorded step, run it under pyrula dev, and see it in Pyrula Cloud. - [Installation](https://docs.pyrula.io/getting-started/install.md): Install the core plus the workflow, agent, or Kafka packages you need. - [Known limitations](https://docs.pyrula.io/getting-started/known-limitations.md): What pyrula 0.1 doesn't support, and what 0.1.x upgrades keep. - [Managed Valkey and Redis](https://docs.pyrula.io/getting-started/managed-valkey.md): Set maxmemory-policy noeviction on each managed Valkey or Redis service, and check it before deploy. - [Send existing traces](https://docs.pyrula.io/getting-started/otel.md): Point an OpenTelemetry GenAI exporter at Pyrula Cloud with environment variables, without installing pyrula or changing code. - [Production checklist](https://docs.pyrula.io/getting-started/production-checklist.md): What to set up and verify before pyrula carries real work. - [Quickstart](https://docs.pyrula.io/getting-started/quickstart.md): Scaffold a durable workflow, run it, and watch it survive a suspend. - [Integration recipes](https://docs.pyrula.io/getting-started/recipes.md): How the stacks a small Python team already runs connect to Pyrula: model providers, Postgres without Redis, webhook-started runs, other tracing libraries, serverless, GitLab CI and OTLP backends. - [Replay checks outside GitHub](https://docs.pyrula.io/getting-started/recipes/ci-outside-github.md): Run pyrula ci run from a GitLab CI job or any shell, with the same inputs as the GitHub replay-check Action. - [Runs started by events](https://docs.pyrula.io/getting-started/recipes/event-triggered-starts.md): Start a durable run from a webhook, an S3 notification or an inbound email, with an idempotency key derived from the event so a redelivered event does not run twice. - [LLM providers](https://docs.pyrula.io/getting-started/recipes/llm-providers.md): Which Pyrula client to use for OpenAI, Azure OpenAI, Gemini, Bedrock, Ollama, vLLM, Groq, OpenRouter and LiteLLM, whether you keep your own SDK code or let an agent call the model, and what each path journals. - [Observe-only frameworks](https://docs.pyrula.io/getting-started/recipes/observe-only.md): Send traces from LlamaIndex, CrewAI or anything instrumented with OpenInference or OpenLLMetry to Pyrula Cloud over OTLP, and what you get and do not get without an adapter. - [Logfire and other OTLP backends](https://docs.pyrula.io/getting-started/recipes/otlp-backends.md): Export a Pyrula runtime's OpenTelemetry spans to Logfire or any backend that takes OTLP over HTTP, next to the Langfuse, LangSmith and Datadog shortcuts. - [Postgres, not Redis](https://docs.pyrula.io/getting-started/recipes/postgres-not-redis.md): What to run when you have Postgres and no Redis or Valkey: SQLite on one host, a managed Valkey, and what the Postgres archive is and is not. - [Serverless](https://docs.pyrula.io/getting-started/recipes/serverless.md): Why AWS Lambda and Cloud Functions cannot host a Pyrula worker, where a worker can run, and how a function can still start runs. - [Crash and resume](https://docs.pyrula.io/getting-started/restart.md): Kill a run midway on a durable store, rerun it, and watch the finished step replayed instead of repeated. - [Versioning & stability](https://docs.pyrula.io/getting-started/stability.md): What a release may change, how stored and wire formats are versioned, and what happens when a run resumes on changed code. - [Troubleshooting](https://docs.pyrula.io/getting-started/troubleshooting.md): What each pyrula dev check means and the fix it prints. - [What leaves your runtime](https://docs.pyrula.io/getting-started/what-leaves-your-runtime.md): What each capture level sends to Pyrula Cloud, how it is redacted, and where redaction does not reach. ## Primitives - [Primitives](https://docs.pyrula.io/primitives.md): Rust-backed core types: Either, Validated, Option, Try, immutable collections and serde. - [IList and IMap](https://docs.pyrula.io/primitives/collections.md): Immutable list and map. Every operation returns a new collection. - [Composition](https://docs.pyrula.io/primitives/composition.md): pipe, flow and partial for wiring functions left to right. - [Do Notation](https://docs.pyrula.io/primitives/do-notation.md): Chain Either, Option or Try with yield instead of nested flat_map calls. - [Duration](https://docs.pyrula.io/primitives/duration.md): A typed time span with arithmetic and timedelta interop. - [Either](https://docs.pyrula.io/primitives/either.md): A value or an error, as a return type instead of an exception. - [Examples](https://docs.pyrula.io/primitives/examples.md): Runnable examples that combine Pyrula's core types. - [ISet](https://docs.pyrula.io/primitives/immutable-set.md): A persistent immutable set backed by a hash-array mapped trie. - [IntSet](https://docs.pyrula.io/primitives/int-set.md): An immutable set of non-negative integers backed by a Roaring bitmap. - [JSON Form](https://docs.pyrula.io/primitives/json-form.md): How the core types and sealed cases are written as plain JSON. - [Modeling Types](https://docs.pyrula.io/primitives/modeling.md): newtype for distinct aliases, sealed and case for closed unions with pattern matching. - [NonEmptyList](https://docs.pyrula.io/primitives/non-empty-list.md): A list that is never empty, so head, last and reduce are total. - [Numeric Lists](https://docs.pyrula.io/primitives/numeric-lists.md): IntList and FloatList run vectorized math in Rust instead of Python loops. - [Option](https://docs.pyrula.io/primitives/option.md): Present or absent, without None checks. - [Parallel map](https://docs.pyrula.io/primitives/par-map.md): par_map runs a Python function over data in forked processes, with no pickling of inputs or closures. - [Serde](https://docs.pyrula.io/primitives/serde.md): Rust-backed JSON and Avro serialization that returns Either instead of raising. - [Try](https://docs.pyrula.io/primitives/try.md): Run something that might throw and get the outcome back as a value. - [Validated](https://docs.pyrula.io/primitives/validated.md): Like Either, but collects every error instead of stopping at the first. ## Workflows - [Workflows](https://docs.pyrula.io/workflows.md): Durable execution on append-only run streams. - [Deployment Modes](https://docs.pyrula.io/workflows/concepts/deployment-modes.md): embedded runs execution in-process. separate runs workers against a shared store. - [Determinism and Replay Safety](https://docs.pyrula.io/workflows/concepts/determinism.md): A workflow body re-runs on replay. Anything with a side effect goes through ctx. - [Replay and Recovery](https://docs.pyrula.io/workflows/concepts/replay-and-recovery.md): step:pending before a step, step:done after. A crash resumes from the first step without a step:done. - [Runs as Event Streams](https://docs.pyrula.io/workflows/concepts/runs-as-streams.md): One run is one append-only event stream, used both as the replay log and the client feed. - [Saved Cases](https://docs.pyrula.io/workflows/concepts/saved-cases.md): A content-addressed capture of a run's inputs, history up to a fork point, and recorded call results. - [Examples](https://docs.pyrula.io/workflows/examples.md): Small working patterns: checkpointed steps, Kafka, timers, approvals. - [Cancel and terminate](https://docs.pyrula.io/workflows/guides/cancel-and-terminate.md): Stop a run gracefully with cancel, or end it now with terminate when no worker can. - [Starting and talking to runs](https://docs.pyrula.io/workflows/guides/client.md): WorkflowClient: submit runs, signal, query, update, cancel and wait for results. - [Errors and retries](https://docs.pyrula.io/workflows/guides/errors-and-retries.md): Retry a step with RetryPolicy, and choose Transient, Poison or Fatal to say what a failure means. - [Flow control](https://docs.pyrula.io/workflows/guides/flow-control.md): Per-key concurrency limits, rate limits, and batching or debouncing events into runs. - [Serving over HTTP](https://docs.pyrula.io/workflows/guides/http.md): Expose durable runs over HTTP with RunRouter, and browse them with the run UI. - [Human-in-the-Loop](https://docs.pyrula.io/workflows/guides/human-in-the-loop.md): ctx.interrupt suspends a run for a decision and replays the answer on resume. - [Kafka Workflows](https://docs.pyrula.io/workflows/guides/kafka.md): Bind a durable workflow to Kafka topics: consume, run checkpointed steps, produce, with exactly-once processing. - [Kafka runtime guarantees](https://docs.pyrula.io/workflows/guides/kafka-guarantees.md): What @kafka_workflow and @kafka_agent guarantee in each delivery mode. - [Observability](https://docs.pyrula.io/workflows/guides/observability.md): OpenTelemetry spans, runner metrics, and worker instruments for the durable engine. - [Parallel steps and child runs](https://docs.pyrula.io/workflows/guides/parallel-and-children.md): Run steps concurrently with ctx.gather, and start other workflows with ctx.run_child. - [Record once, iterate free](https://docs.pyrula.io/workflows/guides/record-once-iterate-free.md): Keep the last pyrula dev run as a case, rerun it offline with a new prompt or model while its tool results replay from the recording, and check saved cases in CI with pytest. No Cloud account. - [Replay checks in CI](https://docs.pyrula.io/workflows/guides/replay-ci.md): Replay a suite of saved cases against a pull request's code with no model keys, and fail the build when the change stops reproducing them. - [Signals, queries and updates](https://docs.pyrula.io/workflows/guides/signals.md): Talk to a running workflow: wait for a signal, answer a query, accept an update. - [Streaming Sources](https://docs.pyrula.io/workflows/guides/sources.md): Consume an external source inside a workflow and record offsets for replay. - [Steps](https://docs.pyrula.io/workflows/guides/steps.md): Run application work as durable, replayable workflow steps. - [Surviving Worker Loss](https://docs.pyrula.io/workflows/guides/surviving-worker-loss.md): Kill a worker mid-run and watch a second one finish it without repeating completed steps. - [Durable Timers](https://docs.pyrula.io/workflows/guides/timers.md): ctx.sleep suspends a run and frees the worker. A timer loop re-queues it at the wake time. - [Versioning and deploys](https://docs.pyrula.io/workflows/guides/versioning.md): How a run is tied to the code that started it, and how to ship a change while runs are in flight. - [What-if runs](https://docs.pyrula.io/workflows/guides/what-if.md): Change an input, a step result, the model or the prompt of a finished run and rerun the rest on your worker, with writes stopped and a budget on. - [Production Worker](https://docs.pyrula.io/workflows/guides/worker.md): Run WorkflowWorker: loops, shards, schedules, health probes and shutdown. - [Quickstart](https://docs.pyrula.io/workflows/quickstart.md): Define a workflow, submit a run, execute it in-process. ## Agents - [Agents](https://docs.pyrula.io/agents.md): The @agent / @tool model, streaming and an HTTP surface. - [Agents](https://docs.pyrula.io/agents/authoring/agents.md): The @agent decorator: options, limits, spend caps and durable steps. - [Context compaction](https://docs.pyrula.io/agents/authoring/compaction.md): Context compaction in the agent loop: when it runs, what it records, how replay treats it, and how to write your own compactor. - [Context](https://docs.pyrula.io/agents/authoring/context.md): Durable primitives, sub-agents, memory and threads on AgentContext. - [Calling an LLM](https://docs.pyrula.io/agents/authoring/llm.md): ctx.llm runs the model and tool loop and records everything for replay. - [Tools](https://docs.pyrula.io/agents/authoring/tools.md): The @tool decorator: retries, timeouts, caching, approval, branches and idempotency. - [Examples](https://docs.pyrula.io/agents/examples.md): Examples combining agent authoring, serving and observability. - [Integrations](https://docs.pyrula.io/agents/integrations.md): Bring LangChain tools into a Pyrula turn, run a durable Pyrula workflow as a LangGraph node, make a Pydantic AI agent or an OpenAI Agents SDK run durable, and serve Pyrula tools to any MCP host. - [What's durable, and what isn't](https://docs.pyrula.io/agents/integrations/durable-vs-not.md): Where the journal draws the line between compatibility and durability, and how to move work across it. - [Adapter guarantee matrix](https://docs.pyrula.io/agents/integrations/guarantees.md): What each integration guarantees, capability by capability, and the SDK versions it is tested against. - [LangChain tools](https://docs.pyrula.io/agents/integrations/langchain.md): Use LangChain tools as Pyrula tools. - [LangGraph](https://docs.pyrula.io/agents/integrations/langgraph.md): Two ways to use LangGraph with Pyrula, what each journals, and what reruns after a restart. - [Calling MCP servers](https://docs.pyrula.io/agents/integrations/mcp.md): Call tools from remote MCP servers inside a Pyrula turn. - [Serving tools over MCP](https://docs.pyrula.io/agents/integrations/mcp-server.md): Expose Pyrula tools to Claude Code, Cursor or any MCP host with build_mcp_server, where each call is a durable run that finishes even if the host disconnects. - [OpenAI Agents SDK](https://docs.pyrula.io/agents/integrations/openai-agents-sdk.md): Make an OpenAI Agents SDK run durable by giving it the journaled AsyncOpenAI: its model calls replay after a restart, and a tool's side effect runs once when it is a Pyrula step. - [Pydantic AI](https://docs.pyrula.io/agents/integrations/pydantic-ai.md): Make a Pydantic AI agent durable with PyrulaDurability: its model and tool calls are journaled in a Pyrula run and replayed after a restart. - [Observability](https://docs.pyrula.io/agents/observability.md): OpenTelemetry tracing and metrics, plus a SQL read model for conversations and token usage. - [Quickstart](https://docs.pyrula.io/agents/quickstart.md): Define an agent, run it in-process, and see a crash resume without re-running work. - [Auth](https://docs.pyrula.io/agents/serving/auth.md): APIKeyAuth and JWTAuth for the agent HTTP server, with per-subject ownership. - [CLI](https://docs.pyrula.io/agents/serving/cli.md): The pyrula command: dev server, workers, store and turn management. - [Client](https://docs.pyrula.io/agents/serving/client.md): AgentClient is the async HTTP client for a served agent. - [HTTP](https://docs.pyrula.io/agents/serving/http.md): create_app serves your agents over HTTP and SSE. - [Kafka](https://docs.pyrula.io/agents/serving/kafka.md): Drive an agent from a Kafka topic with exactly-once processing. - [Schedules](https://docs.pyrula.io/agents/serving/schedules.md): Run an agent on a cron expression or fixed interval, with time zone, overlap and catch-up policy. - [Workers](https://docs.pyrula.io/agents/serving/workers.md): PyrulaWorker runs agent execution as its own tier, separate from the API. ## Kafka - [Kafka](https://docs.pyrula.io/kafka.md): A Rust-backed Kafka client that tracks confluent-kafka, with explicit timeouts and EOS. - [Admin](https://docs.pyrula.io/kafka/admin.md): KafkaAdminClient for topics, partitions, consumer groups, and configs. - [Authentication](https://docs.pyrula.io/kafka/authentication.md): SASL PLAIN, SCRAM, and OAUTHBEARER for managed Kafka: Confluent Cloud, AWS MSK, Azure Event Hubs. - [Benchmarks](https://docs.pyrula.io/kafka/benchmarks.md): pyrula-kafka throughput vs confluent-kafka, aiokafka, and kafka-python. - [Configuration](https://docs.pyrula.io/kafka/configuration.md): KafkaConfig and KafkaConsumerConfig fields, timeouts, and the typed error model. - [Migrating from confluent-kafka](https://docs.pyrula.io/kafka/confluent-compat.md): A drop-in Producer/Consumer shim that runs confluent-kafka code on pyrula. - [Confluent config keys](https://docs.pyrula.io/kafka/confluent-config-keys.md): Every librdkafka and confluent-kafka-python config key, and what the pyrula confluent shim does with it. - [Consumer](https://docs.pyrula.io/kafka/consumer.md): Poll batches, commit offsets, and manage assignment and position. - [Examples](https://docs.pyrula.io/kafka/examples.md): Admin, consumer group, transaction and Avro examples. - [Formats](https://docs.pyrula.io/kafka/formats.md): Produce bytes, JSON, or Avro, and frame for Confluent Schema Registry. - [Client guarantees](https://docs.pyrula.io/kafka/guarantees.md): What the Kafka client guarantees, capability by capability, and the brokers it supports. - [Producer](https://docs.pyrula.io/kafka/producer.md): Produce batches of bytes, JSON, or Avro, and control when you block for delivery. - [Quickstart](https://docs.pyrula.io/kafka/quickstart.md): Produce a batch, poll it back, and read the records. - [Transactions](https://docs.pyrula.io/kafka/transactions.md): Exactly-once across a consume/transform/produce cycle. ## Optional - [Agents](https://docs.pyrula.io/reference/agents.md): Agent runtime: decorators, context, LLM clients, serving, and the Kafka runtime. - [Local case runs](https://docs.pyrula.io/reference/case-local.md): Run a saved case locally with an in-memory run store. - [Case outcomes](https://docs.pyrula.io/reference/case-outcome.md): Summarize case-run events and represent started or refused outcomes. - [Case execution](https://docs.pyrula.io/reference/case-run.md): Start a saved-case run and create fixture-backed sessions. - [Case verification](https://docs.pyrula.io/reference/case-verify.md): Verify a saved case prefix and prepare a local or Cloud case run. - [Cases](https://docs.pyrula.io/reference/cases.md): Saved-case bundles, replay policy and provenance, the FixtureStore protocol, and stores. - [CLI reference: runs and workers](https://docs.pyrula.io/reference/cli.md): The pyrula commands that read or act on a run store and the workers that serve it. - [Core](https://docs.pyrula.io/reference/core.md): Public API of the pyrula core: sum types, collections, serde, functional helpers. - [Extension points](https://docs.pyrula.io/reference/extension-points.md): What you can implement (stores, LLM providers, memory backends, schedule backends), which methods are frozen, how optional capabilities are detected, and the change policy. - [Kafka](https://docs.pyrula.io/reference/kafka.md): Producers, consumers, admin, serdes, and config for pyrula.kafka. - [Parallel](https://docs.pyrula.io/reference/parallel.md): par_map and its errors: fork-based CPU parallelism for Python callbacks. - [Pricing](https://docs.pyrula.io/reference/pricing.md): Per-model token prices used by agent spend caps and case-run budgets. - [Redaction](https://docs.pyrula.io/reference/redaction.md): Secret redaction applied to everything that leaves the process, and its policy. - [Workflows](https://docs.pyrula.io/reference/workflows.md): Durable workflow engine: decorators, context, stores, and the Kafka runtime. - [Workflows (sync)](https://docs.pyrula.io/reference/workflows-sync.md): Blocking WorkflowClient and RunHandle for Django, Flask, Celery and RQ code.