tantra 2.0 — now speaking ACP

Agents that survive the crash.

A durable actor runtime for Python agents. Every agent gets an inbox, a journal and one turn at a time. If a worker dies mid-turn, the journal survives and nothing runs twice; with PostgreSQL, another worker can take over its queue. Drop the connection and the client resumes from its cursor. Serve it to any ACP client.

$pip install tantra-harness
Read the docsGitHub
researcher.py
import asyncio
from uuid import uuid4
from tantra import Agent, OpenAICompatible, Runtime, SQLiteStore
from tantra.extratools.web import web_search
class Researcher(Agent):
model = "gpt-5"
prompt = "Answer with current, sourced information."
tools = [web_search(api_key=BRAVE_API_KEY)]
async def main() -> None:
store = SQLiteStore("sessions.db")
await store.setup()
runtime = Runtime(
OpenAICompatible("https://api.openai.com/v1", OPENAI_API_KEY),
store,
[Researcher],
)
root_id = await runtime.create(Researcher)
async with runtime.connect(root_id, writable=True) as connection:
result = await connection.prompt(
"What changed in Python 3.13?", command_id=uuid4()
)
print(result.text)
await runtime.aclose()
asyncio.run(main())

Connection.prompt(...) accepts one durable UUID command and returns its terminal result. Use send(...) plus event iteration when you need streaming.

Why

Any client, over ACP

tantra.acp serves a Runtime over stdio or WebSocket with an ACP v2–inspired protocol and the tantra profile. Each root has one fenced writer and many readers, and a reconnecting client replays each session from its cursor. tantra-acp-client is the TypeScript client.

The loop is the library

The Runtime activates actors. Tools, hooks, skills and memory plug into it. You write an Agent — values and function references — not an orchestration layer.

Durable actor journals

Every agent has a FIFO inbox and independent scalar cursor. Live asks suspend one actor; crashes interrupt in-flight work without repeating model calls or tools.

One engine, many drivers

A CLI, an HTTP server and a background worker share one Runtime. Readers never own execution, and a newer writable connection replaces the previous writer.

Declarative, FastAPI-style

Tools are built by factories — web_search(api_key=...) — in your own module. Keys are per-agent and a misconfiguration fails at construction, not mid-turn. The library never reads the environment.

Tools ship as extras

The base install is pydantic, httpx, openai — plus stdlib bash and ShellGuard. [web] adds web_search and web_fetch; [doc] adds read_doc; [postgres] adds the driver PostgresStore needs. Nothing you did not ask for is imported.