Get started
CLI
The dashboard, SDK and CLI use the same Aex HTTP API.
npm install -g @aexhq/cli@0.44.0
aex login
aex keys create "My application"
aex keys list
aex keys rename KEY_ID "New name"
aex keys revoke KEY_ID
aex account
aex billing
aex usage
aex docs
aex logoutLogin opens your browser for sign-in or registration. Authorize the CLI on the same computer, then return to your terminal. Results are JSON. Account sessions expire after seven days; API key secrets are shown only at creation.
SDK
Create an API key in your dashboard, then install the SDK and a compatible Agentloop.
npm install @aexhq/sdk@0.77.0 @aexhq/agentloop-pi@6.2.1 zod@4Set AEX_API_KEY and your provider's OPENAI_API_KEY in your application environment. Keep both on your server.
import { Aex, brainEnv, hostEnv, tool } from "@aexhq/sdk";
import { pi } from "@aexhq/agentloop-pi";
import { z } from "zod";
const aex = new Aex({ apiKey: process.env.AEX_API_KEY });
const lookup = tool({
name: "lookup", description: "Look up an item",
input: z.object({ id: z.string() }),
run: async ({ id }) => ({ id, name: "Example item" }),
});
try {
const session = await aex.sessions.create({
agentloop: pi({ env: brainEnv({ name: "brain" }) }),
model: {
provider: "openai", name: "gpt-4.1-mini",
apiKey: process.env.OPENAI_API_KEY,
},
tools: [lookup({ env: hostEnv({ name: "app" }) })],
});
await session.send("Look up item 42.");
for await (const event of session.events()) console.log(event);
await session.end();
// History remains until retention expires or session.delete().
} finally {
await aex.close();
}
SDK 0.77 uses Brain SDK 0.27 with Pi and Codex 6.2.1 and Tools 6.1.5. Upgrade the matching packages together; existing sessions retain their admitted loop and tool schemas.
await aex.models() returns Brain's full supported model catalogue and known capabilities. Aex passes model discovery and validation through to Brain. For DeepSeek, select provider: "deepseek", name: "deepseek-flash" with your DeepSeek API key. See the model contract for supported protocols and media.
Session and client lifetime
session.interrupt() stops the current turn while keeping the session available. session.end() finishes the conversation and keeps history. session.delete() removes an ended or failed session. SDK interrupt() replaces cancel().
await aex.close() releases client connections and local handlers. It is safe to repeat and leaves stored sessions available. The shared host connection stays open until close, including after failed creation, so creation belongs inside the try/finally scope. The official loops explain unanswered calls after interruption without automatically replaying them.
Tool outcomes
A host Tool can return ordinary output or an Outcome directly. Structured errors preserve code, message, retryable and details. Tool deadlines produce timeout; explicit cancellation produces cancelled. Use unknown when a dispatched operation has no reliable result. All three are failed Tool results, and timeout or cancellation does not promise rollback.
The top-level status values ok, error, timeout, cancelled and unknown declare outcomes. Malformed outcomes fail validation. Only successful values pass through the output schema. Read the return-value contract and example.
Structured output
For hosted execution, configure a JSON Schema on Pi or Codex when creating the session. Validation and bounded corrections run in the hosted Agentloop, within one turn. Correction attempts cannot run additional tools.
const agentloop = pi({
env: brainEnv({ name: "brain" }),
output: {
schema: {
type: "object", properties: { answer: { type: "string" } },
required: ["answer"], additionalProperties: false,
},
maxCorrections: 2,
},
});Only a validated final answer is emitted. Provider refusal, truncation, cancellation and uncertain execution fail without a formatting retry. The terminal event contains the parsed result.
Client validation
Request a typed answer on an individual send by supplying a Zod schema.
const person = await session.send("Ada is 37 years old. Extract her details.", {
output: {
type: z.object({ name: z.string(), age: z.number() }),
maxRetries: 2,
},
});
// person: { name: string; age: number }The SDK prompts for JSON and validates it locally. Two additional correction turns are allowed by default; zero disables retries. Exhaustion throws StructuredOutputError. No terminal Tool is required. Ordinary sends keep returning session state; idle alone does not establish turn success.
Corrections run in your client and use the session's existing Agentloop and tools. Use one caller for sends during the operation. Raw attempts remain visible in history and streams. Read the full structured-output contract.
Where code runs
The Agentloop runs in hosted Brain. This example's lookup function runs in your application through hostEnv. To host a Tool, supply a precompiled Brain-compatible Wasm Component and place it in brainEnv.
Hosted Components have bounded memory and execution time, and no access to server secrets, host files or native network grants. Aex also offers managed Modal profiles granted explicitly to your account; arbitrary HTTP drivers and images are rejected.
Prepare application Tool dependencies before registering hostEnv. Extensions do not declare dependency strings; each Environment owns preparation and resource access. Hosted brainEnv configuration must be empty.
Defaulted Tool arguments are optional in the model schema; Zod applies defaults and transforms before calling the handler. Ordinary objects strip extra fields and strict objects reject them. Pi dispatches in parallel; Tools and their Environments coordinate shared resources.
Server Actions and managed tools
Keep Aex and model keys in your server environment, including Vercel Server Actions. Select a profile and fixed command from your account's catalog, then submit a durable turn.
import { modal } from "@aexhq/env-modal";
const catalog = await aex.environments.list();
const workspace = modal({
url: catalog.driver_url,
name: "analysis", profile: "python-v1", lifetimeMs: 300_000,
});
const calculate = tool({
name: "calculate", description: "Calculate a result",
input: z.object({ value: z.number() }),
implementation: { type: "modal_command", name: "calculate" },
});
// Create with tools: [calculate({ env: workspace })].
const sequence = await session.submit("Calculate for 42.", {
idempotencyKey: "turn-once",
});
// session.id identifies the conversation; sequence identifies this turn.
await aex.close();The example profile is illustrative; use an ID and command your catalog publishes. Managed compute requires accepted prices, prepaid credits and a per-operation cost ceiling. Set maxCostMicroUsd on the Aex client.
submit() returns the saved turn's event sequence. Closing the client leaves the turn running. Load session.transcript() when opening a conversation, then read updates with session.events(after) or session.stream(after), passing the last event sequence. Reuse the original idempotency key when a response is lost. Tools placed in hostEnv still require your host process to remain connected.
A prepared image contains Python, data and dependencies. One binding shares temporary files and has a fixed lifetime of at most five minutes. Commands receive JSON on stdin and return JSON on stdout. Store business data and durable files in your application database or object storage. Database administrator and provider keys stay outside the sandbox. Managed environment contract.
A Modal profile can set terminateAfterTurn: true. The extension registers its cleanup method with Brain, which saves the answer before calling it. Cleanup and its outcome appear in session events; the conversation and transcript remain available. Each Environment extension owns its provider configuration and deployment.
Images and PDFs
Publish bytes through aex.attachments.upload() and send the returned media as native model input. For Tool output, use the same media in the official loop envelope:
const attachment = await aex.attachments.upload(session.id, pngBytes, {
contentType: "image/png", idempotencyKey: "chart-once",
});
await session.send({ message: "Explain this chart", media: [attachment.media] });
// Inside a Tool handler, publish using context.sessionId and return:
return { type: "aex_tool_output", version: 1, content: "Chart ready", media: [attachment.media] };Images and PDFs use HTTPS URLs; JSON/base64 remains ordinary data. Tool-result media keeps its call ID and source order, including parallel batches with failed siblings. Keep attachments available while later turns need them; deleting or expiring one revokes future reads. See the complete image Tool example and attachment limits and lifetime.
Official extensions
@aexhq/env-modal also runs independently of Aex hosting. Pass your own createModalClient({ tokenId, tokenSecret }) to its controller and connect standalone Brain through the public Environment protocol. Modal credentials stay on the controller; the Environment connection token is separate. Aex admission, credits and managed keys are optional product integrations.
@aexhq/tools-mcp connects selected MCP Tools through your application's hostEnv. It preserves structured failures and original JSON Schemas, including conditional schemas and local references accepted by the validators. Invalid input fails before a remote call; unresolved external references fail during setup.
For standalone Brain, @aexhq/env-local supplies a Docker workspace with retained files and prepared Python projects, and @aexhq/env-browser supplies browser actions and screenshots. These HTTP Environments need an operator deployment. MCP, Docker and browser extensions are version 0.3; Pi and Codex present their media results to the model.
Loop authors can run npm run test:logic:watch -w packages/loop-pi in the extensions checkout for quick policy edits. Full Component tests and compiled journeys still gate release.
Events and storage
Brain retains committed session history. Subscribe with session.stream(), reconnect from a committed sequence, and store application data wherever you choose. Account storage figures include active reservations.
This preview uses customer model keys and one serving node. Maintenance interrupts live work. PostgreSQL holds account and ownership data; Brain retains its journal on persistent disk. By default, idle session execution and the guest heap are released; shared workers, caches, connections and Environment resources can remain alive.
Credits and spending
The initial resource offer uses 1.5 times published provider resource prices. A 1-core, 1-GiB Modal Sandbox in the broad US region is approximately $0.00477 per minute, including Modal's regional multiplier. Aex attachment storage is $0.0345 per GiB per 30 days and reads are $0.147 per GiB, including the proxied network path. Orchestration and request overhead come out of the markup; there is no additional active-turn charge in this offer. Models remain BYOK.
These are fixed resource prices based on the Sandbox list prices and AWS us-east-1 storage and network rates. They do not track provider free credits or invoice discounts. The dashboard shows the exact offered pricebook before you accept it.
The dashboard shows your offered prices, available credits, reservations, usage and ledger. Existing accounts stay in free preview until they accept a pricebook. Where Checkout is enabled, manual topups use Stripe; payment status and receipt links are available in the dashboard. Unused credits can be refunded to their original payment method.
Prepaid operations reserve their maximum charge before dispatch. Your monthly limit includes charged usage and outstanding holds. Sandbox waiting time counts after allocation; Aex attachment storage and reads have separate meters. These limits do not cap your model provider bill. No automatic topups are performed. Billing API and recovery.