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.
import asynciofrom uuid import uuid4
from tantra import Agent, OpenAICompatible, Runtime, SQLiteStorefrom 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.