Hatchet is a developer platform and orchestration engine for AI agents, durable workflows, background tasks, and parallel workloads, with SDKs across Python, TypeScript, Go, and Ruby. Hatchet Cloud or self-hosted, with the full operational surface that comes with a real orchestration product — priority queues, concurrency strategies, rate limits, alerts, and OTEL export. If your durability problem is shaped like a polyglot task queue that also handles agents, Hatchet is a credible answer.
Kitaru doesn’t orchestrate anything — it’s a replay-based eval layer. It records a production run as a session — every model call, tool call, decision — and a session re-executes: unchanged, it reproduces the original as a faithful baseline; forked, it re-runs with one thing changed. Agents running on Hatchet are no exception. Wrap them with a first-class adapter (Pydantic AI, OpenAI Agents SDK, LangGraph, Mastra, Vercel AI SDK), or import the traces you already collect in Langfuse, LangSmith, Braintrust, or OTel, and every run becomes a session you can replay.
Use Kitaru if you are
- Running agents in production, on Hatchet or anywhere else, and want to test a change before it ships, not just watch logs after
- Recording production runs as sessions via an adapter (Pydantic AI, OpenAI Agents SDK, LangGraph, Mastra, Vercel AI SDK) or importing traces you already collect
- Turning the sessions that caught a failure into a cohort that gates every future change
- Comparing a model or prompt swap on the same frozen population instead of a vibe check
- Self-hosting eval infrastructure so traces and credentials stay in your own systems
Use Hatchet if you are
- Running a polyglot estate (Python, TypeScript, Go, Ruby) that needs one orchestration platform across all of it
- Building background tasks, durable workflows, parallel workloads, or queue replacement
- Leaning on the flow-control surface (priority queues, concurrency strategies, static and dynamic rate limits) as a first-class feature
- Fine adopting Hatchet Cloud's hosted tiers, or self-hosting the engine plus Postgres plus dashboard
Hatchet orchestrates the work. Kitaru replays it, so you can prove a change before it ships.
Different jobs, not a competing engine
Hatchet’s defaults are tasks, workers, queues, durable workflows, events, and schedules — a packaged orchestration platform. Kitaru’s defaults are record, replay, and improve: wrap or import a run as a session, re-execute it with the recording answering for the world, and compare cohorts before and after a change.
- Different problems, not competing solutions. Hatchet runs and retries your workloads. Kitaru makes your production history runnable as a test bench. Neither one does the other’s job.
- Composable by design. An agent task running inside a Hatchet workflow is exactly the kind of run Kitaru wants to record — wrap it with an adapter, or import the trace, and it’s a session like any other.
LLM calls as first-class session data
The LLM call is the unit of cost, latency, and failure in an agent. Hatchet has strong operational observability for tasks and workflows — a dashboard, alerts, metrics, and OpenTelemetry export to Datadog or Grafana. What it doesn’t ship is a place to see the prompt, response, tokens, and cost of a specific call, linked to the run it belongs to. Kitaru’s adapters capture exactly that on every recorded call.
- Recording, not glue code.
KitaruAgent(agent, agent_id=AGENT_ID)wraps a Pydantic AI agent once; every model call it makes lands as a node on the session with prompt, response, tokens, and cost. - Session graph, not a generic span. Hatchet has OTEL spans across tasks. Kitaru’s session graph is agent-shaped:
llm_call,tool_call, andsubagent_callnodes, each carrying the fields a replay needs to reproduce it. - Replay reads, not re-bills. Replaying a session answers tool calls from the recording by default, so the LLM calls you already paid for don’t get re-hit unless the input changed.
Replay reproduces. Experiments fork it.
Both products replay from durable state, but they’re answering different questions. Hatchet’s replay resumes production work — retry this run, restart from the event log. Kitaru’s replay reproduces a specific past run exactly, so you have a faithful baseline before you change anything. Then an experiment forks it: the same cohort, replayed again with one variable moved — model, prompt, or tool policy — and compared side by side.
- Mechanism:
experiment.run(cohort=cohort, version="v1")replays a cohort unchanged as the baseline;experiment.run(cohort=cohort, version="pr-311")replays it again against your working tree.client.compare(before, after)diffs the two. - Use case: The model swap you’re considering either helps on the ten sessions that caught last month’s regression, or it doesn’t — and you know before you ship it, not after.
- What’s cached: Nothing has to be re-run to check. Both experiment runs replay the full cohort against the recording, so tool calls never touch real systems.
What makes Kitaru unique
| Feature | Kitaru | Hatchet |
|---|---|---|
| Durable execution, retries, and workflow orchestration | Not supported | Yes |
| Priority queues, concurrency strategies, static and dynamic rate limits | Not supported | Yes |
| SDKs across Python, TypeScript, Go, and Ruby | Not supported | Yes |
| Managed cloud with published tiers (Developer/Team/Scale/Enterprise) | Not supported | Yes |
| Record production agent runs as replayable sessions | Yes | Not supported |
| Adapters for Pydantic AI, OpenAI Agents SDK, LangGraph, Mastra, Vercel AI SDK | Yes | Not supported |
| Import traces from Langfuse, LangSmith, Braintrust, or OTel | Yes | Not supported |
| Replay with tool calls answered from the recording — nothing touches real systems | Yes | Not supported |
| Cohorts: frozen, immutable session sets | Yes | Not supported |
| Experiments: same cohort, one variable moved, compared | Yes | Not supported |
| Deterministic and model-graded evaluators | Yes | Not supported |
| Permissively-licensed self-hosting (Kitaru: Apache 2.0; Hatchet: MIT) | Yes | Yes |
How the two surfaces map
| Concept | Hatchet | Kitaru |
|---|---|---|
| Layer | Orchestration platform (how the work runs) | Replay-based evals (how you test what it did) |
| Core unit | Task / workflow run | Session — recorded model and tool calls, re-executable |
| Composition | Workers register with the engine, triggered by tasks or events | Agent wrapped once by an adapter, or a trace imported |
| Tool calls in tests | Hit real systems, or you mock them by hand | Answered from the recording per tool policy |
| “Did my change help?” | Read the traces or dashboard, compare by eye | Two runs over the same cohort, diffed |
| Crash mid-run | Task retried by the engine | Partial session recorded — the evidence survives |
| Where it runs | Hatchet Cloud, or a self-hosted engine plus Postgres | Self-hosted FastAPI + Postgres server; workers replay in your environment |
Code comparison
from pydantic_ai import Agent
from kitaru_pydantic_ai import KitaruAgent
agent = Agent("openai:gpt-5.4", name="support-agent",
system_prompt="You resolve support tickets.")
support = KitaruAgent(agent, agent_id=AGENT_ID)
# Runs inside your Hatchet task exactly as before —
# and lands as a session.
result = support.run_sync(ticket_text)
# 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("cheap-model", model="gpt-5-mini")
before = experiment.run(cohort=cohort, version="v1")
after = experiment.run(cohort=cohort, version="pr-311")
client.compare(before, after)from hatchet_sdk import Hatchet, Context
hatchet = Hatchet()
async def call_llm(prompt: str) -> str:
...
support_flow = hatchet.workflow(name="SupportFlow")
@support_flow.task()
async def triage(input: dict, ctx: Context) -> dict:
return {"result": await call_llm(f"Triage: {input['ticket']}")}
def main() -> None:
worker = hatchet.worker("support-worker", workflows=[support_flow])
worker.start()
# Trigger: support_flow.run({"ticket": "..."})
# Workers register with the Hatchet engine; tasks execute there.A different layer, not a competing engine
If you want the full operational platform around durable workflows (hosted cloud, queues, rate limits, multi-language SDKs, alerts and dashboards), Hatchet is a strong pick, and I’d tell any team that.
For testing whether a change to your agent actually helped — replay the sessions that already happened, fork them with one variable moved, compare before and after — Kitaru is the layer that sits beside it.
We’ve spent five years building the MLOps-ready version of this problem space at ZenML. JetBrains runs their AI globally on it; Adeo runs across all their brands and geographies on it. Kitaru is that team two years into the agent version. Bet on us for agent infrastructure and you’re betting on the group that’s been doing this the whole time.
uv add "kitaru[cli,worker]" kitaru-pydantic-ai