______ ______ _______ _______ _______ ▄████▄ | __ \ __ \ _ |_ _| | | ▄██▄██▄██▄ | __ < < |_| |_| | ▀▀ ▀▀ |______/___|__|___|___|_______|__|____|
A minimal, distributed and extensible agent runtime
Docs · API Reference · Website · Official extensions · Roadmap · 中文
Note
Early preview. The API and functionality may change without backward compatibility or notice until we cut 1.0.0.
Brain is a minimal, distributed and extensible agent runtime. You compose an Agentloop, a Model, Tools and Environments through small public interfaces. One session can run Tools in several Environments while its transcript and history stay locally readable.
Brain supplies runtime mechanisms. Your application supplies product policy, scheduling, tenancy and infrastructure.
The core mechanism that bridges the LLM, controls context and dispatches tools. Write an agent loop.
- Pi
- Opencode
- Codex
The hands that let the LLM do work. A tool declares the resources it needs and how to act. Write a tool.
- Bash
- Inline function
- Web_search/Web_fetch
An environment provides the resources a tool needs to complete its tasks. Write an environment.
- Sandbox
- Browser
- Filesystem
Official extensions are written the same way you would write yours: aexhq/extensions.
Brain ships two Environments of its own. brainEnv runs Components in a fresh Wasmtime instance
per invocation, granted only what their needs name. hostEnv is your own process, for Tools that
are plain functions. Any other Environment is reached over HTTP.
- Kernel owns the session. It commits every effect to the append-only journal before dispatch, sends it once and never retries on its own. Status, transcript and Events rebuild from the journal after a restart.
- Sessions owns multi-session semantics and lifecycle calls.
brain-servercomposes it with Environment adapters and retains API credentials and request claims. - Brain env runs the Agentloop and native Tools as precompiled Wasmtime Components in multiple managed worker processes. Each invocation runs in a fresh capability sandbox and calls back into Brain for model and tool calls, so every effect is logged before it happens.
- One protocol reaches every Environment: the brain env inside the server, your app registered as a host, and any Environment over HTTP. Callers own lifecycle policy; Environments implement setup, execution, detach and teardown.
- Everything is observable. Model calls, Tool results and lifecycle changes are committed Events. The live feed adds token deltas; reconnecting resumes at a committed sequence.
Brain is a native Rust server on Tokio and Axum with HTTP and SSE. A local deployment needs no external store. The architecture decision records explain the design and its evolution.
The tool below is a plain function in your own process. The SDK registers your process as a host over SSE, so your app needs no open port.
Run a server:
docker run --rm -p 127.0.0.1:8080:8080 \
-e BRAIN_LISTEN=0.0.0.0:8080 -e BRAIN_API_TOKEN=quickstart \
-v brain-data:/var/lib/brain ghcr.io/aexhq/brain:latestnpm install @aexhq/brain @aexhq/agentloop-pi zodSave as order.mjs and run with node order.mjs:
import { Brain, brainEnv, hostEnv, tool } from "@aexhq/brain";
import { pi } from "@aexhq/agentloop-pi";
import { z } from "zod";
const orders = { "A-1001": { status: "shipped", eta: "Thursday" } };
const lookupOrder = tool({
name: "lookup_order",
description: "Look up an order's status by id.",
input: z.object({ id: z.string() }),
run: ({ id }) => orders[id] ?? { status: "unknown order" },
});
const brain = new Brain({ baseUrl: "http://127.0.0.1:8080", token: "quickstart" });
const session = await brain.sessions.create({
model: { provider: "openai", name: "gpt-5-mini", apiKey: process.env.OPENAI_API_KEY },
agentloop: pi({ env: brainEnv({ name: "brain" }) }),
tools: [lookupOrder({ env: hostEnv({ name: "app" }) })],
});
await session.send("Where is order A-1001?");
for await (const event of session.events()) console.log(event.sequence, event.type);
await session.end();
await session.delete();Session execution is released after each turn and history opens on demand. Compiled Components stay resident; each invocation gets fresh state. See BENCHMARKS.md and the benchmark guide.
For support and bug reports, open an issue or write to support@aex.dev. For collaboration and partnerships, write to admin@aex.dev.
