Compare

Kitaru vs DBOS: different layers, not competing runtimes

DBOS makes agent code durable in production, backed by Postgres. Kitaru records what those runs did and replays them as evals. Different questions — and they compose.

uv add "kitaru[cli,worker]" kitaru-pydantic-ai
Sign up freeRead the docs

DBOS is a polyglot durable workflow library on Postgres. Code crashes, and DBOS makes sure you don’t start over — workflow state sits alongside your OLTP data in the same database, and Conductor gives ops a UI for scheduled workflows and durable queues. It’s a serious answer to “how do I keep this running,” and it’s not trying to be anything else.

Kitaru isn’t trying to keep anything running. It answers a different question: once an agent run happened, can you re-run it? Kitaru records runs as sessions — through a framework adapter or by importing the traces you already collect — and replays them against your real code, so a model or prompt change gets tested against what actually happened in production.

The two stack cleanly. An agent that DBOS keeps alive in production can still be wrapped by a Kitaru adapter, or have its traces imported, and its sessions become the regression suite that catches the next bad deploy before it ships.

Kitaru

Use Kitaru if you are

  • Testing a model, prompt, or code change to a DBOS-run agent against real production sessions instead of a hunch
  • Recording agent runs via a framework adapter (PydanticAI, LangGraph, OpenAI Agents SDK, Mastra, Vercel AI SDK), or importing traces you already send to Langfuse, LangSmith, or Braintrust
  • Freezing the sessions that caught a regression into a cohort that gates every future change
  • Self-hosting the eval infrastructure so traces and credentials stay in your own systems
Alternative

Use DBOS if you are

  • Running durable workflows across Python, TypeScript, Go, and Java services with one contract
  • Leaning on durable queues, cron schedules, and the Conductor UI for ops
  • Needing DBOS Conductor's managed workflow console, and on paid plans, SOC 2 / HIPAA-compliant tooling
  • Already deep into Postgres and want durable state living in the same database as your app
DBOS makes sure your agent doesn't lose its place when it crashes. Kitaru makes sure you know whether the change you're about to ship is actually an improvement.

Recording, not instrumenting

In DBOS, an LLM call is something you make inside your own @DBOS.step, and instrumenting it — tokens, cost, model identity — is your code. Kitaru doesn’t change how DBOS runs your agent. It sits at the framework boundary: wrap the agent with a Kitaru adapter, or import the traces you already collect, and every model call and tool call lands as a node on a session automatically — model, tokens, latency, cost, no separate logging setup.

DBOS · @DBOS.step
openai.chat.completions.create(prompt=…)OTel traces via instrumentation — tokens, cost, and retries are your code.
Kitaru · session nodesession s_9f2a…
support.run_sync("Refund order #4821…")
model
gpt-5.4 · anthropic
recorded
model call + tool call, as nodes
tokens1,247
latency2.8s
cost$0.028
On replay, Kitaru answers the tool call from the recording — nothing touches real systems.

From one session to a regression suite

One replayed session answers a question about one run. Freeze the sessions that matter into a cohort, and an experiment replays that whole cohort with one thing changed — a model, a prompt — and compares the two runs side by side.

DBOS persists step input and output in Postgres so a workflow can resume where it left off. That’s state for a run in progress. A Kitaru session is a recording of a finished run, kept so it can be replayed later — different data, doing a different job.

experiment · pr-311gpt-5-mini
session s_8f2apass
refund-check
session s_71cdpass
refund-check
diffsame cohort
experiment · v1gpt-5.4
session s_8f2afail
refund-check
session s_71cdpass
refund-check
DBOS: persists workflow state in Postgres to resume a run. Kitaru: persists sessions to replay one — different data, different job.

Wrap it, don't rebuild it

DBOS is a library. You deploy the Python app however you already deploy Python apps, and durable state lives in whatever Postgres you point it at. That’s simple and portable, and Kitaru doesn’t change any of it.

DBOSLibrary embedded in your Python service
your_app.pyimport DBOS
deploy anywhere Python deploysyour container · your VM · your FaaS
your Postgres
KitaruOne wrapper, no rewrite
uv add kitaru-pydantic-aior the adapter for your framework
KitaruAgent(agent, agent_id=...)
PyPydanticAI
PyLangGraph
PyOpenAI Agents
TSMastra · Vercel AI
self-hosted server · FastAPI + Postgres
  • One wrapper, no rewrite: KitaruAgent(agent, agent_id=...) wraps the agent you already wrote in PydanticAI, LangGraph, or the OpenAI Agents SDK. run, run_sync, tools, and output types behave exactly as on the wrapped agent.
  • TypeScript too: Mastra and the Vercel AI SDK get native-signature adapters — KitaruAgent(existingAgent, options) and createKitaruGenerateText(...).
  • No adapter for your stack yet? Import the traces you already send to Langfuse, LangSmith, or Braintrust, or emit OTLP and import that. Either path lands as a session.
  • Self-hosted, Apache 2.0: one FastAPI + Postgres server on your infrastructure. Replays and evaluations execute on workers in your environment — traces and credentials don’t leave your systems.

Two ways in: adapters and imports

DBOS gives you scheduled workflows and durable queues with concurrency limits and deduplication — the operational shape of keeping an app running. Kitaru’s shape is different: getting a run recorded in the first place.

DBOSQueue + schedule shape
@DBOS.scheduled("0 * * * *")cron on the workflow
Queue("work", concurrency=8)concurrency + dedup
workflow_id = uuid4()you assign it; app code starts the run
KitaruTwo ways in: wrap it, or import it
adapters5 shipped
PydanticAILangGraph+3 more
Or import existing traces
LangfuseLangSmithBraintrustOTel
Both land as sessions — replay and evaluators work the same either way.
  • Wrap it: shipped adapters cover PydanticAI, LangGraph, the OpenAI Agents SDK, Mastra, and the Vercel AI SDK. One wrapper, no rewrite, every run lands as a session.
  • Or import it: already tracing to Langfuse, LangSmith, or Braintrust? Import those traces directly. No adapter, no code change.
  • Same downstream either way: once a session exists, replay, cohorts, experiments, and evaluators work identically whether it arrived through an adapter or an import.

What makes Kitaru unique

FeatureKitaruDBOS
Durable execution with checkpoint / step replayNot supportedYes
Durable queues, cron scheduling, and dedupNot supportedYes
Polyglot SDKs (Python, TypeScript, Go, Java)Not supportedYes
SOC 2 / HIPAA compliant managed control plane (Conductor, paid plans)Not supportedYes
Records agent runs as replayable sessions (adapter or trace import)YesNot supported
Replays a session against real code, tool calls answered from the recordingYesNot supported
Cohorts: frozen session sets as regression suitesYesNot supported
Experiments: same cohort, one variable moved, comparedYesNot supported
Deterministic + model-graded evaluatorsYesNot supported
Imports Langfuse / LangSmith / Braintrust / OTel tracesYesNot supported
Self-hosted, open source (Kitaru: Apache 2.0)YesYes

How the two surfaces map

ConceptDBOSKitaru
LayerDurable execution (keeps the agent alive in prod)Replay-based evals (tests a change to the agent)
Core unitWorkflow / stepSession — recorded run, re-executable
State backendPostgres, alongside your OLTP dataSelf-hosted server (Postgres) plus your own workers
RecordingN/A — DBOS orchestrates, doesn’t record for evalA framework adapter wraps the agent, or traces are imported
“Did my change help?”Not what DBOS answersTwo runs over the same cohort, diffed
DeploymentLibrary embedded in whatever Python app you already shipAdapter wraps the agent; server + workers self-hosted

Code comparison

DBOS + KitaruRecommended
from pydantic_ai import Agent
from kitaru_pydantic_ai import KitaruAgent

reviewer = KitaruAgent(
  Agent("openai:gpt-5.4", system_prompt="You're a compliance reviewer."),
  agent_id=AGENT_ID,
)

# DBOS keeps this durable in production.
# Every run also lands as a Kitaru session.
result = reviewer.run_sync(case)

# Later: freeze the sessions that matter, test a change.
import kitaru

client = kitaru.KitaruClient()
cohort = client.cohorts.create("hard-cases", sessions=session_ids)
experiment = client.experiments.create(
  "cheaper-model",
  model="gpt-5-mini",
  tool_policy=History(scope="cohort", on_miss="fail"),
)

before = experiment.run(cohort=cohort, version="v1")
after = experiment.run(cohort=cohort, version="pr-311")
client.compare(before, after)
DBOS alone
from dbos import DBOS
import openai

client = openai.OpenAI()

@DBOS.step()
def research(topic: str) -> str:
  resp = client.chat.completions.create(
      model="gpt-4o-mini",
      messages=[{"role": "user",
                 "content": f"Research: {topic}"}],
  )
  return resp.choices[0].message.content

@DBOS.step()
def draft(brief: str) -> str:
  resp = client.chat.completions.create(
      model="gpt-4o",
      messages=[{"role": "user",
                 "content": f"Write a draft:\n{brief}"}],
  )
  return resp.choices[0].message.content

@DBOS.workflow()
def review_flow(topic: str) -> str:
  brief = research(topic)
  text = draft(brief)

  # Human approval via DBOS.send / recv messaging.
  approved = DBOS.recv(timeout_seconds=86400)
  return text if approved else "Rejected"

# Plus: start the DBOS runtime, send approval
# from another process via DBOS.send.

Put replay-based evals under your DBOS-run agents

If your durability problem is polyglot services against Postgres with a SOC 2 or HIPAA control plane on day one, DBOS is better-shaped for that workload — be honest about which side you’re on. If the question is whether the change you’re about to ship to a DBOS-run agent actually helps, Kitaru replays the sessions that already happened — record them once, via an adapter or an import, and every future change gets tested against real production behavior instead of a guess.

uv add "kitaru[cli,worker]" kitaru-pydantic-ai
Sign up free