Quickstart
Run an agent that looks up an order and tells you whether it has shipped.
Connect an AI model to an order lookup function in your app. You need Docker, Node.js 22 or newer and an OpenAI API key. Your provider bills model calls separately. Prefer hosting? Use the Aex quickstart.
1. Start Brain
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:latestLeave this terminal running. The volume keeps saved sessions between restarts. The example token is for local use; see deployment before exposing a server. The commands below use Bash; in PowerShell, put multiline shell commands on one line.
2. Install the client
In another terminal:
mkdir brain-example
cd brain-example
npm init -y
npm pkg set type=module
npm install @aexhq/brain@0.38.0 @aexhq/agentloop-pi@9.0.0 zod@4.4.3Install the compiler and runner:
npm install --save-dev typescript@5.9.2 tsx@4 @types/node@22Set your model key in this terminal:
export OPENAI_API_KEY="your-key"In PowerShell, use $env:OPENAI_API_KEY = "your-key". Keep keys out of source control.
3. Add a tool and send a message
Save as order.ts. This is the complete order example;
its source also runs unchanged as JavaScript. The input schema supplies the tool's argument types.
import { Brain, tool } from "@aexhq/brain";
import { pi } from "@aexhq/agentloop-pi";
import { z } from "zod";
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) throw new Error("OPENAI_API_KEY is required");
const lookupOrder = tool({
name: "lookup_order",
description: "Look up an order by id.",
input: z.object({ id: z.string() }),
run: ({ id }, ctx) => ctx.finish({ id, status: "shipped" }),
});
const brain = new Brain({ baseUrl: "http://127.0.0.1:8080", token: "quickstart" });
brain.sessions.create({
model: { provider: "openai", name: "gpt-5-mini", apiKey },
agentloop: pi(),
tools: [lookupOrder()],
}).then(async session => {
const after = session.state.lastSequence;
await session.send("Look up order A-1001. Has it shipped?");
for await (const event of session.events(after)) {
if (event.type === "turn_failed") throw new Error(JSON.stringify(event.data));
}
console.log(JSON.stringify(await session.transcript(), null, 2));
console.log("Session:", session.id);
}).catch(error => {
console.error(error);
process.exitCode = 1;
});4. Run it
npx tsc --noEmit --strict --module NodeNext --target ES2023 order.ts
npx tsx order.tsThe transcript includes a lookup_order result and an answer saying order A-1001 has shipped.
The wording depends on the model. Replace the sample return value with your own backend lookup.
Pi runs on the Brain server by default; the lookup runs in this application's process.
ctx.finish(value) returns a tool result and completes the call. After five idle seconds,
the client releases its tool connection so this script can exit. The session and history remain.
Add another send() in the callback to keep chatting. A later send through the same live client
reconnects before starting work.
Use connectionIdleTimeoutMs: 0 on new Brain(...) when other callers or future autonomous
events must reach these tools. Event subscriptions stay open until you stop them.
Explicit brain.close() permanently disposes of the client; session.end() finishes the
conversation and session.delete() removes its history. See sessions.
Next steps
- Sessions: stream output, retrieve outcomes and reconnect.
- Write a tool: connect your application or package an extension.
- Choose a loop: customize agent behavior.
- Operate Brain: deploy, back up and upgrade your server.