Durable execution for AI agents that survive the real world.
Kestrion is an open-source Python framework for AI agents built around one idea: every step is recorded as an immutable event. That now includes multi-role approvals, approval deadlines, parallel tool calls, sub-agents, handoff, and MCP tools on top of crash recovery.
Prototyping an agent is easy. Running it in production is where things break.
Several frameworks can get a working agent loop running in an afternoon. The gap shows up after that — when the agent has to survive contact with a real environment.
Replayable state
Current state is derived from the event stream, so every decision has a trail.
Approval gates
Mutating tools can require one role, many roles, or expire after a deadline.
Crash recovery
Resume from persisted checkpoints in a new process after a restart or deploy.
Agentic patterns
Parallel tool calls, sub-agent delegation, and full handoff are built into Agent.
Everything that happens is an event. State is just a replay.
Every LLM call, tool call, and transition is recorded as an immutable event with its own timestamp and cost. The agent's current state is never mutated in place — it's derived by folding that event log. This is the single design decision underneath every other claim Kestrion makes about durability.
Plan the next step
The agent chooses a node or tool call while the engine owns the run state.
Record the event
Inputs, outputs, timestamps, and transition metadata are persisted.
Pause when required
Approval-required tools park the run without keeping a thread alive.
Replay and resume
A fresh process folds the log, rebuilds state, and continues from the checkpoint.
Made for agents that touch real systems, not just demos.
Kestrion is useful wherever an agent has to make progress over time, call tools with side effects, pause for review, and still leave a clean record of what happened.
Infrastructure copilots
Let an agent inspect Kubernetes, Terraform, or cloud state while requiring approval before it applies a manifest, scales a deployment, or changes production config.
Long-running workflows
Build workflows that wait on engineer and manager sign-off, then expire cleanly if nobody approves inside the allowed window.
Auditable automation
Record every transition, tool call, provider response, and cost signal so teams can inspect behavior after the run instead of guessing from logs.
Support and back-office agents
Route work to specialist agents, delegate sub-tasks, or fully hand off a conversation while keeping run IDs and approvals scoped correctly.
MCP-connected agents
Import tools from a real MCP server, apply Kestrion approval gates to selected MCP tools, or serve a full agent as one MCP tool.
Parallel tool batches
When a model requests multiple tools in one turn, Kestrion runs the safe batch concurrently and pauses the whole batch if any gated tool is unapproved.
Small primitives that make agent behavior easier to trust.
The framework is still pre-alpha, but the core design is intentionally narrow: record facts, derive state, and put risky tool execution behind engine-level controls.
What Kestrion gives you as defaults
Current proof points
Most frameworks are strong at authoring. Few make production behavior the default.
This is the honest version, including where Kestrion is not uniquely positioned. AWS Strands and Bedrock AgentCore make a similar production-grade pitch, backed by far more engineering capacity. The bet here is an independent, MCP-native alternative for teams that don't want cloud lock-in — not an unchallenged advantage.
| LangGraph | CrewAI | AWS Strands | Kestrion | |
|---|---|---|---|---|
| State model | Mutable, opt-in checkpoints | Mostly in-memory | Event-driven hooks | Event-sourced by default |
| Crash recovery | Possible, needs setup | Not native | Tracing, not full replay | Default, independently verified |
| Approval gates | Manual graph wiring | No native primitive | Hooks can cancel a call | Enforced by the engine itself |
| Storage backend | In-memory or custom | In-memory | Bedrock-default | Pluggable: SQLite to Postgres |
The next features that make Kestrion more useful in production.
The current build proves the core execution model. The next layer is about making that model easier to deploy, inspect, and connect to real tool ecosystems.
Approval API
A first-class Agent.approve() flow so paused runs can resume cleanly without manual scratch-state edits.
MCP tools
Connect agents to external MCP servers as tool providers, and expose Kestrion agents back out as MCP-compatible services.
Postgres store
Move beyond SQLite for multi-worker deployments while keeping the same checkpoint-store protocol.
Scheduler
Run many agent sessions concurrently with shared provider limits and durable work queues.
CLI and deploy
Project scaffolding, local inspection commands, and generated Kubernetes manifests for stateless workers.
Trace viewer
A lightweight UI for reading event timelines, approvals, tool calls, and provider cost data per run.
What's actually built, and what's still a plan.
Kestrion is pre-alpha at 0.2.1, published on PyPI. The claims above are backed by working code — 110 passing tests — where marked built below; everything else is designed but not yet implemented.
From first tool to production agent in four steps.
Kestrion is intentionally layered. You can start with a single decorated function and add approval gating, crash recovery, and sub-agents only when you need them.
Write a tool
Any Python function with @tool. Type hints become the JSON schema the model receives.
Create an agent
Agent(provider=..., tools=[...]) wires a model provider to your tools and a SQLite store.
Gate dangerous tools
Add requires_approval=True to any tool that writes, deletes, or modifies production state.
Resume from anywhere
A paused run stores everything in SQLite. agent.resume(run_id) works in a completely new process.
Step 1 — Simple tool
from kestrion.agent.decorators import tool @tool def get_server_status(server: str) -> dict: """Check the health of a server.""" return {"server": server, "status": "ok", "disk_pct": 45}Step 2 — Agent with store
from kestrion.agent.agent import Agent from kestrion.llm.anthropic_provider import AnthropicProvider agent = Agent( provider=AnthropicProvider(model="claude-sonnet-4-6"), tools=[get_server_status], store="sqlite:///runs.db", ) result = await agent.run("Check web-01 server status") print(result.status) # RunStatus.COMPLETEDStep 3 — Gated tool
@tool(requires_approval=True) def restart_server(server: str) -> dict: """Restart a server. Requires approval.""" return {"restarted": server} result = await agent.run("Restart web-01") print(result.status) # waiting_on_human # Nothing was restarted yet!Step 4 — Approve & resume
from kestrion.core.engine import Engine from kestrion.core.types import Checkpoint, new_id from datetime import datetime, timezone Engine.record_approval( result.state, "restart_server", role="__any__" ) await agent._store.save(Checkpoint( checkpoint_id=new_id("ckpt"), run_id=result.run_id, state=result.state, created_at=datetime.now(timezone.utc), event_seq=result.state.last_event_seq, )) final = await agent.resume(result.run_id) print(final.status) # RunStatus.COMPLETEDMulti-role approval chains
Require sign-off from multiple roles before a tool executes. The run stays paused until all roles have approved.
@tool(requires_approval=["engineer", "manager"], approval_timeout_seconds=3600.0) def deploy_to_prod() -> dict: """Deploy. Needs engineer + manager, within 1h.""" ... # record each role independently: Engine.record_approval(state, "deploy_to_prod", role="engineer") # still waiting for manager... Engine.record_approval(state, "deploy_to_prod", role="manager") # now it can proceed.Sub-agents & Handoff
Wrap any agent as a tool another agent can call. For full conversation transfer, use as_handoff_target().
# Sub-agent delegation: specialist = Agent(provider=..., tools=[cleanup]) cleaner = specialist.as_tool( "clean_disk", "Ask disk specialist to clean" ) parent = Agent(provider=..., tools=[cleaner]) # Multi-agent handoff: billing = Agent(provider=..., tools=[issue_refund]) handoff = billing.as_handoff_target( "transfer_to_billing", "Transfer conversation to billing" )Memory & context compaction
Long-running agents automatically summarize older conversation turns when thresholds are hit, preventing context overflow.
agent = Agent( provider=OllamaProvider(model="llama3.2"), tools=[my_tool], store="sqlite:///runs.db", # Summarize when history exceeds 20 turns max_history_turns=20, # Always keep the 4 most recent turns intact keep_turns=4, ) # When threshold is exceeded, older turns are # summarized by the LLM and replaced with a # compact context block automatically.MCP integration
Connect to real MCP servers as tool providers, or expose a Kestrion agent as an MCP-compatible service.
# Consume MCP tools (with approval gating): async with MCPClient.stdio( command="python3", args=["my_mcp_server.py"] ) as client: tools = await client.list_tools( requires_approval=["apply_manifest"] ) agent = Agent(provider=..., tools=tools) # Expose agent as an MCP server: mcp_server = serve_agent(agent, name="ops") mcp_server.run(transport="stdio")How to wire Kestrion into a real application.
Kestrion is a Python library, not a hosted service. Wiring it into an existing codebase means choosing a store, connecting your LLM provider credentials, and deciding which tools need gating. Here's the canonical path.
Commands built into kestrion — no extra tools needed.
Install Kestrion once. Get project scaffolding, run management, Kubernetes deployment generation, a terminal trace inspector, and a local web approval console out of the box.
kestrion init
Scaffold a new agent project with the correct directory layout, a starter agent script, and a Dockerfile — zero configuration required.
kestrion run
Run any agent script directly through the CLI with environment isolation and clean error reporting.
kestrion deploy
Generate a complete Kubernetes manifest set — Namespace, ConfigMap, Deployment, PVC, and Service — plus a production-ready Dockerfile.
kestrion trace
Print a colorized, chronological event timeline for any run directly in your terminal — token counts, tool calls, transitions, and pending approvals.
kestrion dashboard
Launch a local web dashboard to visually inspect runs, browse event payloads and costs, and approve pending gated tools through a clean UI.
MkDocs docs site
Full API reference documentation for the core engine, Agent API, providers, and store protocol — served locally or hosted via GitHub Pages.
The actual code you'd write.
Every line below maps to code that exists and is covered by the test suite — not aspirational API design.
Reference — install, resume, and develop locally.
Install
Each LLM provider is an optional extra. Install only what you use.
pip install kestrion[anthropic] pip install kestrion[openai] pip install kestrion[ollama] pip install kestrion[all] # every providerResuming a paused run
Works from a completely independent process — the actual crash-recovery guarantee, not just a convenience method.
Engine.record_approval( result.state, "apply_manifest", role="__any__" ) await agent._store.save(Checkpoint(...)) result = await agent.resume(run_id)Local development
Clone, install in editable mode with dev extras, run the suite.
git clone https://github.com/VinayakDubey07/kestrion.git cd kestrion python3 -m venv .venv source .venv/bin/activate pip install -e ".[dev]" pytest tests/ -v110 tests passing, 1 skipped.
Examples
examples/kubectl_agent — the original worked example, demonstrating pause-on-approval and resume-after-restart using the raw Engine/Node primitives directly, useful for understanding what Agent builds on top of.