BU

Burr

1,200PythonAgent Framework

Python framework for building stateful, production-ready AI agents with built-in observability.

PythonState MachineObservabilityTestingProduction

Overview

Burr is a Python framework for building stateful, production-ready AI agents with built-in observability, testing, and deployment capabilities. It provides a simple, declarative API for defining agent state machines while automatically handling the complexity of state management, logging, and evaluation.

Features

  • State machine abstraction for clear agent design
  • Built-in observability with zero configuration
  • Testing framework for unit and integration tests
  • Evaluation suite with custom evaluators
  • A/B testing for comparing agent versions
  • LangChain integration
  • Type safety with full type hints

Installation

pip install burr

Pros

  • +Production-ready with built-in observability
  • +Simple, declarative API
  • +Excellent testing and evaluation tools
  • +Built-in A/B testing support
  • +Works with LangChain ecosystem
  • +Clear state machine model for debugging

Cons

  • Newer framework with smaller ecosystem
  • Python-only
  • Requires learning the Burr paradigm
  • Less flexibility than raw LangChain

Alternatives

Documentation

Burr

Overview

Burr is a declarative state machine framework for building production-ready AI agents. Unlike traditional imperative agent frameworks where you write sequential code, Burr uses a state machine paradigm where you define states, actions, and transitions declaratively. This approach provides better control over agent behavior, built-in observability, and production-grade reliability.

Developed by Tim Furrer and maintained by Dagworks, Burr has gained traction among teams building complex AI applications that require fine-grained control and full visibility into agent execution.

Features

  • Declarative State Machine Paradigm — Define states, actions, and transitions as declarative configurations rather than imperative code
  • Built-in State Snapshots — Automatically capture state at each transition for debugging and replay
  • Replay Analytics — Review past agent sessions, replay specific paths, and understand decision-making
  • Visual Debugging — Visualize state machine execution with interactive debugging tools
  • Streaming Support — Native support for streaming LLM responses
  • Async Operations — Full async/await support for concurrent agent operations
  • Multi-Provider Integration — Works with OpenAI, Anthropic, Google, and other LLM providers

Installation

pip install burr

Quick Start

from burr import ApplicationBuilder
from burr.tracking import LocalTrackingClient

# Define your state machine
def initial_state():
    return {"step": 0, "results": []}

def action_a(state):
    return {"step": 1, "results": state["results"] + ["action_a"]}

def action_b(state):
    return {"step": 2, "results": state["results"] + ["action_b"]}

def terminate(state):
    return {"step": 3, "results": state["results"]}

# Build and run
app = ApplicationBuilder()\
    .with_state(initial_state())\
    .with_actions(initial=initial_state, action_a=action_a, action_b=action_b, terminate=terminate)\
    .with_transitions(
        ("initial", "action_a"),
        ("action_a", "action_b"),
        ("action_b", "terminate"),
    )\
    .build()

result, final_state = app.run()

Core Concepts

State

The state is a dictionary that flows through your state machine. Each action receives the current state and returns an updated state.

Actions

Actions are functions that transform state. They can call LLMs, make API calls, or perform any computation.

Transitions

Transitions define which action comes next based on the current state. You can use condition functions for dynamic routing.

Hooks

Burr provides hooks for logging, tracking, and custom behavior at various points in execution.

Advanced Features

Conditional Transitions

def should_continue(state):
    return state["step"] < 5

app = ApplicationBuilder()\
    .with_transitions(
        ("step", "step", should_continue),
        ("step", "done"),
    )\
    .build()

Streaming

for event in app.stream():
    print(f"Event: {event}")

Evaluation

from burr.evaluate import evaluate

results = evaluate(app, test_cases)

Examples

Multi-Agent Coordination

# Define agents as state machines
research_agent = build_research_state_machine()
analysis_agent = build_analysis_state_machine()

# Coordinate through shared state
coordinator = ApplicationBuilder()\
    .with_actions(research=research_agent, analyze=analysis_agent)\
    .with_transitions(
        ("research", "analyze", lambda s: s["research_done"]),
        ("analyze", "done"),
    )\
    .build()

RAG Pipeline

def retrieve(state):
    results = vector_db.search(state["query"])
    return {"context": results, "query": state["query"]}

def generate(state):
    response = llm.generate(state["context"], state["query"])
    return {"response": response, "context": state["context"]}

rag_app = ApplicationBuilder()\
    .with_actions(retrieve=retrieve, generate=generate)\
    .with_transitions(
        ("retrieve", "generate"),
        ("generate", "done"),
    )\
    .build()

Pros

  • ✅ Declarative approach reduces cognitive complexity
  • ✅ Built-in debugging with state snapshots
  • ✅ Time-travel debugging through replay
  • ✅ Production-grade observability out of the box
  • ✅ Clean separation of concerns
  • ✅ Well-documented with practical examples
  • ✅ Works with any LLM provider

Cons

  • ❌ Newer framework with smaller community
  • ❌ Learning curve for state machine paradigm
  • ❌ Less ecosystem integration than LangChain
  • ❌ Python only, no TypeScript support yet
  • ❌ Smaller pool of pre-built integrations

When to Use

Burr is ideal for:

  • Building complex stateful agents with clear state transitions
  • Production applications requiring full observability
  • Teams that want fine-grained control over agent behavior
  • Applications where debugging and replay are critical
  • Projects that need to trace every decision made by the agent

Consider alternatives when:

  • You need a simple chatbot without complex state (use OpenAI Agents SDK or PydanticAI)
  • You want maximum ecosystem integrations (use LangChain)
  • You prefer imperative coding style (use CrewAI or AutoGen)

Use Cases

Use CaseWhy Burr
Production AgentsBuilt-in observability and state snapshots for reliability
Complex WorkflowsDeclarative state machine for clear, maintainable logic
Debugging Critical SystemsTime-travel debugging and replay analytics
RAG PipelinesClean state transitions for retrieval and generation steps

Comparison with Alternatives

FeatureBurrLangGraphCrewAIAutoGen
ParadigmDeclarative state machineGraph-basedRole-basedConversation
State Snapshots✅ Built-in⚠️ Manual❌ No❌ No
Replay/Debug✅ Excellent⚠️ Limited❌ No❌ No
Production Ready✅ Yes✅ Yes⚠️ Medium⚠️ Medium
Learning CurveMediumMedium-HighLowMedium
Best forProduction agentsCustom graphsRole-based teamsMulti-agent chat

Best Practices

  1. Design states carefully — Keep state dictionary minimal and focused
  2. Use condition functions — Enable dynamic routing based on state
  3. Enable tracking early — Configure LocalTrackingClient for debugging
  4. Test transitions thoroughly — Verify all state transitions work correctly
  5. Leverage streaming — Use app.stream() for real-time feedback

Troubleshooting

IssueSolution
State not updatingCheck action returns new state dictionary
Transitions not firingVerify condition functions return correct boolean
Missing snapshotsConfigure tracking client before building app
Streaming not workingUse for event in app.stream() pattern correctly

Resources