Agent Substrate
An async-first Python framework for building production AI agents that call tools, remember across sessions, pause for human approval, survive crashes, and scale from a single process to a Kubernetes fleet — without changing your agent code.
Most "agent" libraries help you wrap a model call in a loop. Agent Substrate is built for the part that comes after the demo: durability, supervision, governance, memory, and multi-agent orchestration — the things you need when an agent has to run unattended, handle real users, and not lose state when a worker dies.
Understand the framework · The agent model
What you can build
RAG-backed chatbots with streaming responses, persistent memory, and human-in-the-loop approval cards. The substrate-ui template deploys as a ready-made chat shell.
Coordinate fleets of specialised agents — a researcher hands off to an analyst hands off to a writer — with OrchestratorAgent, sub-agent spawning, and supervision budgets.
Long-running agents that browse the web, run code in a sandbox, query databases, and call MCP tools — checkpointed so they resume exactly where they left off after a crash.
Extract invoices, analyse documents, ingest knowledge bases with RAGPipeline / GraphRAGPipeline, and run scheduled or webhook-triggered batch jobs.
Why Agent Substrate
| Capability | What it means for you |
|---|---|
| Actor-model agents | Every agent has an address (AgentId). You send messages to an address, the runtime delivers them. The call site is identical whether the agent runs in-process, on another node, or in a pod. |
| Durable runtime | Every step is journaled to an event log. If a worker crashes mid-run, another worker replays from the log with at-most-once effect guarantees — no double charges, no lost work. |
| Human-in-the-loop | Pause an agent on a risky tool call, surface an approval card to a human, and resume hours later. The wait survives a restart. |
| Tools + MCP | JSON-schema-validated tools with risk tiers and approval gating. Connect any MCP server and its tools appear to the agent automatically. |
| Memory that scales | Pluggable history providers plus advanced vector, graph, and paged strategies, so agents recall context beyond the window. |
| Governance & guardrails | Spawn budgets, token caps, content guardrails, and middleware pipelines enforce safety and cost limits at the runtime level. |
| One codebase, two deploy modes | Run as a single FastAPI monolith for development, or split into 12 independent microservices for production — the same agent package powers both. |
Your first agent
import asyncio
from substrate.config import settings
from substrate.agents import ReActAgent, Runtime
from substrate.agents.context import ContextConfig, InMemoryHistoryProvider
from substrate.integrations.llm import LLMFactory
from substrate.capabilities.tools import CalculatorTool
async def main() -> None:
# 1. Build an LLM client (provider auto-detected from the model name)
model = LLMFactory(settings.CHAT_MODEL, settings.OPENAI_API_KEY).build()
# 2. Construct an agent with tools and memory
agent = ReActAgent(
"helper",
model=model,
tools=[CalculatorTool()],
context=ContextConfig(InMemoryHistoryProvider()),
system_instructions="You are a helpful assistant.",
)
# 3. Start the runtime, register the agent, talk to it
async with Runtime() as rt:
await rt.register(agent)
from substrate.console import Console
console = Console(agent, runtime=rt)
await console.interactive(stream=True)
if __name__ == "__main__":
asyncio.run(main())The shape never changes. Adding tools, guardrails, streaming, HITL approvals, or swapping the in-process runtime for a Postgres-backed durable one is all configuration — the call site stays the same. See The Agent Model for why.
Installation
Add it to a project like any other package:
uv add agent-substrate --prerelease=allowThe durable runtime's scheduler needs apscheduler v4's native async
AsyncScheduler — v3 doesn't have it. apscheduler has no stable v4
release yet (latest overall is v3.11.x; v4 is still alpha), so this flag
is required and not a temporary workaround. With plain pip, the
equivalent is pip install --pre agent-substrate.
That's enough to import the agent loop into your own code — see Your first agent above. Running the full server (the same FastAPI app, durable runtime, and observability stack this site's dashboard talks to) needs Postgres and Redis reachable via DATABASE_URL / REDIS_URL, plus OPENAI_API_KEY and JWT_SECRET:
uv run startIf you don't already have Postgres/Redis running somewhere, cloning the repo gets you a docker-compose stack for local infra, plus the notebooks and test suite:
git clone https://github.com/Ravikumarchavva/agent-substrate.git
cd agent-substrate
uv sync
make infra-up # Postgres, Redis, MCP server, observability
uv run startOptional extras when cloning from source:
uv sync --group notebooks # Jupyter notebook examples
uv sync --group browser # Browser automation (WebSurferTool)
uv sync --group storage # S3 / object storageHow it's built
Agent Substrate is organised into four strictly-layered modules plus three orthogonal concerns. Each layer imports only from the layers below it — enforced in CI by uv run lint-imports.
integrations (LLM providers, MCP, connectors), infrastructure (Postgres, Redis, MinIO, durable runtime), and serving (the monolith + 12 microservices) sit orthogonal to the stack — they implement kernel Protocols and wire everything together at startup.
Start here
Agents as addresses, the three identities, and the ReAct loop. The foundation everything builds on.
Examples
The examples/ folder has runnable notebooks covering foundations, memory, MCP tools, safety, the durable runtime, and observability — from a single-tool agent to a Kubernetes deployment.