or build from source (any platform)

April 11, 2026 · View on GitHub

 ______          _       _____ _____
|___  /         | |     |  __ \_   _|
   / / ___ _ __ | |_ ___| |__) || |
  / / / _ \ '_ \| __/ _ \  _  / | |
 / /_|  __/ |_) | || (_) | | \ \ | |
/_____\___| .__/ \__\___/|_|  \_\___|
           | |
           |_|  durable agent runtime

Process supervisor and durable runtime for AI agents. Think systemd meets Temporal, purpose-built for LLM workloads. Supervise any agent binary with automatic restart, crash recovery, budget enforcement, and a tamper-evident audit trail.

License Tests Rust

┌──────────────────────────────────────────────────────┐
│  SUPERVISION    restart · backoff · recovery sweep   │
│  DURABILITY     journal · snapshots · effect replay  │
│  BUDGET         token limits · cost caps · per-agent │
│  AUDIT          SHA-256 hash chain · tamper-evident  │
│  POLICY         allow · deny · require-approval      │
│  OBSERVABILITY  live TUI · metrics · web dashboard   │
└──────────────────────────────────────────────────────┘


No Rust code required. Use the CLI to supervise any process — Python scripts, Node agents, Go binaries, anything.

Quick Start

# Install pre-built binary (pick your platform)
curl -fsSL https://github.com/qhkm/zeptort/releases/latest/download/zeptort-aarch64-apple-darwin -o zeptort     # macOS (Apple Silicon)
curl -fsSL https://github.com/qhkm/zeptort/releases/latest/download/zeptort-x86_64-unknown-linux-gnu -o zeptort  # Linux (x86_64)
curl -fsSL https://github.com/qhkm/zeptort/releases/latest/download/zeptort-aarch64-unknown-linux-gnu -o zeptort # Linux (ARM64 / Pi)
chmod +x zeptort && sudo mv zeptort /usr/local/bin/

# or build from source (any platform)
cargo install --git https://github.com/qhkm/zeptort --features cli

# Start the daemon
zeptort daemon &
# Launch a Python agent under supervision
$ zeptort run --name researcher --restart always --max-restarts 10 -- python agent.py
  [zeptort] started researcher
  [zeptort] pid: 4821
  [zeptort] log: ~/.zeptort/agents/researcher.log
# Check what's running
$ zeptort status
  Name: researcher
  State: running
  PID: 4821
  Command: python agent.py
  Restart policy: always (count 0/10)
  Uptime: 45s
# Kill it — the supervisor brings it back
$ kill -9 4821
$ zeptort status researcher
  State: running
  PID: 4955 new pid
  Restart policy: always (count 1/10)
  Uptime: 0s
# Verify the tamper-evident audit trail
$ zeptort audit
  Hash chain: intact
  Entries verified: 42
# Live dashboard
$ zeptort top --live
  zeptort agent runtime                    daemon alive
  ─────────────────────────────────────────────────────
  AGENT          PID    STATE     RESTARTS   UPTIME
  researcher     4955   running   1/10       2m34s
  worker         5012   running   0/5        1m12s
  ─────────────────────────────────────────────────────
  AUDIT: 42 entries / hash chain intact
# Done
$ zeptort halt researcher
  [zeptort] halt requested for researcher

The Problem

AI agents fail. They hallucinate commands, loop infinitely, exhaust budgets, panic on unexpected inputs. When one agent in a swarm fails, it often takes down the entire workflow. Worse: if a crash happens after an expensive LLM call, the call re-executes on restart — double cost, possibly different result. Nobody knows what the agent actually did.

The Solution

ZeptoRT treats failure as normal. When an agent crashes:

  1. The supervisor detects it within 100ms
  2. The agent restarts with exponential backoff
  3. Recorded LLM results replay from the journal — no re-execution, no double cost
  4. The budget gate prevents runaway spending
  5. Every event is logged in a tamper-evident SHA-256 hash chain

No 3 AM pages. No $500 surprise bills. No "what did the AI do?"

ProblemZeptoRT
Agent crashes, loses all stateDurable journal — replay recorded results, no re-execution
Runaway LLM calls cost $500 overnightBudget gating — per-process token/cost limits, checked before every effect
No idea what agents did or whyHash-chained audit trail — tamper-evident log of every lifecycle event
One crash takes down the whole systemOTP supervision trees — OneForOne, OneForAll, RestForOne with backoff

CLI Reference

9 commands. All client commands accept --addr and --token (or ZEPTORT_ADDR / ZEPTORT_TOKEN env vars).

Daemon

zeptort daemon [--config FILE]    # Start the runtime daemon (default: ./zeptort.toml)
zeptort check [--config FILE]     # Validate config without starting

Process Supervision

# Supervise any command — Python, Node, Go, shell scripts, anything
zeptort run --name NAME [OPTIONS] -- COMMAND [ARGS...]

Options:
  --restart <POLICY>       never | on-failure | always  (default: on-failure)
  --max-restarts <N>       give up after N restarts      (default: 5)
  --cwd <DIR>              working directory for the child

# Examples
zeptort run --name researcher --restart always --max-restarts 20 -- python agent.py
zeptort run --name worker --restart on-failure -- node worker.js --port 3000
zeptort run --name batch --restart never -- ./run-pipeline.sh

Inspect & Monitor

zeptort status              # List all supervised agents
zeptort status NAME         # Detail view: state, PID, uptime, restart count, log path
zeptort top                 # One-shot dashboard (table format)
zeptort top --live          # Live-updating TUI dashboard (refreshes every 500ms)
zeptort top --json          # Machine-readable JSON output
zeptort ping                # Health check — "alive (version=0.1.0, uptime_ms=...)"

Control

zeptort halt NAME           # Graceful stop: SIGTERM → wait grace period → SIGKILL
                            # Terminal — even with --restart always, the agent stays down
zeptort kill --all          # SIGKILL every live agent immediately

Audit

zeptort audit               # Verify SHA-256 hash chain: "Hash chain: intact, Entries verified: 73"

Environment Variables

VariableDescriptionDefault
ZEPTORT_ADDRDaemon address (host:port)127.0.0.1:9090
ZEPTORT_TOKENBearer token for authnone
# Set once, skip --addr/--token on every command
export ZEPTORT_ADDR=10.0.0.5:9090
export ZEPTORT_TOKEN=my-secret-token
zeptort status    # just works

What happens when things go wrong

Agent crashes (SIGKILL, panic, OOM)
  → Supervisor detects within 100ms
  → Exponential backoff (100ms → 200ms → 400ms → ... capped at 30s)
  → Restart with preserved restart counter
  → Journal records every event

Daemon itself crashes
  → Recovery sweep finds orphaned agents in SQLite registry
  → Resurrects them with their restart policy intact
  → Hash-chained audit trail survives the crash

Config-Driven Daemon

No code needed — define agents in TOML:

# zeptort.toml
[daemon]
bind = "127.0.0.1:9090"
db_path = "~/.zeptort/zeptort.db"

[daemon.auth]
bearer_token = "your-secret-token"

[[agents]]
name = "researcher"
type = "llm"
provider = "anthropic"
model = "claude-sonnet-4"
system_prompt = "You are a research assistant."
tools = ["web_fetch"]
auto_start = true

[agents.budget]
token_limit = 100000
cost_limit_usd = 5.00

[external_agents]
default_restart_policy = "on-failure"
default_max_restarts = 5
default_backoff = "exponential"
log_dir = "~/.zeptort/agents"
zeptort daemon                      # start all agents
curl localhost:9090/ping            # health check
curl localhost:9090/agents/external # list supervised processes
curl localhost:9090/metrics         # runtime metrics (JSON)
curl localhost:9090/journal/verify  # audit chain status

Built-in agent types: llm, http_webhook, cron, pipeline.

REST API + MCP-compatible JSON-RPC at POST /mcp with SSE discovery at GET /mcp/sse.


HTTP API

MethodPathDescription
GET/pingHealth check
GET/metricsRuntime metrics
GET/agents/externalList all supervised processes
GET/agents/external/{name}Process detail + recent log lines
POST/agents/externalSpawn a new supervised process
POST/agents/external/{name}/haltGraceful halt
GET/journal/verifyAudit chain verification
GET/processesList kernel processes
POST/mcpMCP JSON-RPC endpoint
GET/mcp/sseMCP SSE discovery

Optional bearer token auth — all endpoints except /ping and /health.


Architecture

┌─────────────────────────────────────────────────────────────────┐
│                       ZEPTORT DAEMON                             │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              EXTERNAL PROCESS SUPERVISOR                  │    │
│  │                                                           │    │
│  │  zeptort run ──→ Supervisor ──→ Agent Process             │    │
│  │                      │              │                     │    │
│  │                      │         crash / exit               │    │
│  │                      │              │                     │    │
│  │                      ↓              ↓                     │    │
│  │                  Backoff ────→ Auto-restart                │    │
│  │               (100ms..30s)     (count: 1/10)              │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              KERNEL RUNTIME (Rust library)                │    │
│  │                                                           │    │
│  │  StepBehavior ──→ Scheduler ──→ Reactor (async I/O)       │    │
│  │       │                             │                     │    │
│  │       │  declare effect             │  dispatch + record  │    │
│  │       ↓                             ↓                     │    │
│  │  Budget Gate ──→ Policy ──→ Journal ──→ Snapshot           │    │
│  │  (tokens/$)      (allow/    (23 entry   (periodic         │    │
│  │                   deny)      types)      checkpoints)     │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  SQLite: journal + snapshots + registry                   │    │
│  │  SHA-256 hash chain ──→ tamper-evident audit trail         │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  HTTP/REST API + MCP JSON-RPC + SSE                       │    │
│  │  /agents/external  /metrics  /journal/verify  /mcp        │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

Two modes — pick what fits:

  • CLI supervisor (no Rust needed) — zeptort run wraps any binary with restart policies, backoff, and audit logging
  • Rust library (full control) — durable execution with declared effects, journaling, and crash recovery

Features

Supervision

  • Restart policies: always, on-failure, never
  • Exponential backoff (100ms base, 30s cap)
  • OTP-style supervision trees: OneForOne, OneForAll, RestForOne
  • Halt is terminal regardless of restart policy
  • Recovery sweep on daemon restart (orphaned agents resurrected from SQLite)

Durability

  • SQLite journal with 23 entry types
  • SHA-256 hash-chained audit trail (tamper-evident)
  • Periodic snapshots with pruning
  • Crash recovery replays recorded results (no re-execution)
  • Idempotency keys for effect deduplication

Budget & Policy

  • Per-process token and cost limits
  • Per-effect-kind policy (allow/deny/require-approval)
  • Human approval gateway with HTTP endpoints
  • Budget checked before every effect dispatch

Observability

  • zeptort top --live — real-time TUI dashboard
  • zeptort audit — journal integrity verification
  • /metrics endpoint with atomic counters
  • Structured logging via tracing crate
  • Web dashboard with live agent cards (deploy/dashboard/)

Rust Library (Optional)

For full control, embed ZeptoRT as a Rust library:

cargo add zeptort
use zeptort::core::behavior::{StepBehavior, BehaviorMeta};
use zeptort::core::message::{Envelope, EnvelopePayload, Payload};
use zeptort::core::step_result::StepResult;
use zeptort::core::effect::{EffectRequest, EffectKind};
use zeptort::core::turn_context::TurnContext;
use zeptort::error::Reason;

struct MyAgent { state: String }

impl StepBehavior for MyAgent {
    fn init(&mut self, _checkpoint: Option<Vec<u8>>) -> StepResult {
        StepResult::Continue
    }

    fn handle(&mut self, msg: Envelope, ctx: &mut TurnContext) -> StepResult {
        match &msg.payload {
            EnvelopePayload::User(Payload::Text(text)) => {
                StepResult::Suspend(EffectRequest::new(
                    EffectKind::LlmCall,
                    serde_json::json!({ "prompt": text, "model": "claude-sonnet-4" }),
                ))
            }
            EnvelopePayload::Effect(result) => {
                if let Some(output) = &result.output {
                    self.state = output.to_string();
                }
                StepResult::Continue
            }
            _ => StepResult::Continue,
        }
    }

    fn terminate(&mut self, _reason: &Reason) {}

    fn snapshot(&self) -> Option<Vec<u8>> {
        Some(self.state.as_bytes().to_vec())
    }

    fn restore(&mut self, state: &[u8]) -> Result<(), String> {
        self.state = String::from_utf8_lossy(state).into();
        Ok(())
    }

    fn meta(&self) -> Option<BehaviorMeta> {
        Some(BehaviorMeta { module: "my_agent".into(), version: "1.0.0".into() })
    }
}

16 effect kinds: LlmCall, Http, DbQuery, HumanApproval, ObjectFetch, VectorSearch, CliExec, SandboxExec, Custom, and more. See docs/GUIDE.md for the full walkthrough.


Status

662 tests passing. 17 of 18 spec sections implemented. Single-node, production-ready.

FeatureStatus
External process supervision (restart, backoff, recovery)Done
SQLite journal with 23 entry typesDone
SHA-256 hash-chained audit trailDone
OTP supervision trees (OneForOne, OneForAll, RestForOne)Done
Budget gating (token + cost limits per process)Done
Effect pipeline (16 kinds: LlmCall, Http, DbQuery, ...)Done
Crash recovery (snapshot + journal replay)Done
CLI tools (daemon, run, halt, status, top, audit, ping)Done
HTTP/REST API with bearer authDone
MCP JSON-RPC + SSEDone
Content security scanning (optional shield feature)Done
Live TUI dashboard (zeptort top --live)Done
Web dashboard with chaos-monkey demoDone
Multi-node clusteringNot yet

Background

ZeptoRT didn't start here. It took three iterations to find the right architecture.

Attempt 1: Replicate Erlang/BEAM in Rust (ZeptoBeam) — We built a full BEAM replica: reduction-counting scheduler, supervision trees, ETS/DETS tables, hot code upgrades, durable mailboxes, MCP integration. 46,000 lines of Rust, 343 tests, built in 5 days. It hit a wall: the sync scheduler can't await, so every LLM call required two thread hops and correlation IDs. Reduction counting models CPU — but AI agents don't consume CPU, they consume tokens and dollars.

Attempt 2: Just make it async — Rewrote with tokio tasks, await directly in handlers. 4x smaller codebase, natural to write. But the runtime went blind — it couldn't see what effects cost, whether policy allowed them, or how to replay them on crash. If an agent crashed after an LLM call, the call re-executed. No journaling, no replay, no budget enforcement.

Attempt 3: Declare, don't execute (ZeptoRT) — Agents don't execute effects. They describe them as intents. The runtime journals, budget-checks, policy-checks, dispatches, records, and delivers. On crash, recorded results replay — no re-execution. This is the Temporal pattern adapted for AI: deterministic shell + nondeterministic effects, with budget gating and OTP supervision that Temporal doesn't have.

The right abstraction for AI agents isn't "processes that run code" — it's "processes that declare intent and let the runtime handle the rest."

Read the full story: docs/BACKGROUND.md


Influences

Erlang/OTP — "Let it crash." The BEAM VM runs WhatsApp (2B+ users) and Discord with nine nines of uptime. ZeptoRT brings OTP's supervision trees, process isolation, and fault-tolerance to AI agents.

Temporal — Durable execution pioneer. ZeptoRT uses Temporal's core pattern but adds budget gating, content policy, and OTP-style supervision.

Ray — Budget-aware scheduling. ZeptoRT adapts Ray's resource model from GPU compute to LLM tokens and API cost.


Principles

  1. Supervise > Defend — let supervisors handle restarts, not application code
  2. Journal > Repeat — replay recorded results, don't re-execute expensive effects
  3. Declare > Execute — describe effects as intents; the runtime decides if/when/how
  4. Crash > Corrupt — restart clean rather than recover from undefined state

Docs


License

Apache 2.0 — see LICENSE

For commercial licensing, enterprise support, or managed hosting inquiries: qaiyyum@aisar.ai