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 burrPros
- +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 Case | Why Burr |
|---|---|
| Production Agents | Built-in observability and state snapshots for reliability |
| Complex Workflows | Declarative state machine for clear, maintainable logic |
| Debugging Critical Systems | Time-travel debugging and replay analytics |
| RAG Pipelines | Clean state transitions for retrieval and generation steps |
Comparison with Alternatives
| Feature | Burr | LangGraph | CrewAI | AutoGen |
|---|---|---|---|---|
| Paradigm | Declarative state machine | Graph-based | Role-based | Conversation |
| State Snapshots | ✅ Built-in | ⚠️ Manual | ❌ No | ❌ No |
| Replay/Debug | ✅ Excellent | ⚠️ Limited | ❌ No | ❌ No |
| Production Ready | ✅ Yes | ✅ Yes | ⚠️ Medium | ⚠️ Medium |
| Learning Curve | Medium | Medium-High | Low | Medium |
| Best for | Production agents | Custom graphs | Role-based teams | Multi-agent chat |
Best Practices
- Design states carefully — Keep state dictionary minimal and focused
- Use condition functions — Enable dynamic routing based on state
- Enable tracking early — Configure
LocalTrackingClientfor debugging - Test transitions thoroughly — Verify all state transitions work correctly
- Leverage streaming — Use
app.stream()for real-time feedback
Troubleshooting
| Issue | Solution |
|---|---|
| State not updating | Check action returns new state dictionary |
| Transitions not firing | Verify condition functions return correct boolean |
| Missing snapshots | Configure tracking client before building app |
| Streaming not working | Use for event in app.stream() pattern correctly |
