Aex Brain
Customize and operate

Embed the runtime

Run sessions inside a Rust service you already own.

Run the server when you want a process to talk to. Embed the crate when another Rust service already owns startup, configuration and deployment, and you want sessions inside it.

Each Session is one conversation, and your service can run many sessions on one shared runtime. This Rust excerpt assumes you've already configured the session directory, telemetry and the loop, model and tool executors described below:

use std::sync::Arc;

let limits = brain::Limits::default();
let writer = brain::Writer::spawn_with(&limits);
let feed = Arc::new(brain::Feed::with_limits(telemetry.clone(), &limits));

let runtime = Arc::new(brain::SessionRuntime {
    environment_control: None,
    tool_executions: Arc::default(),
    limits: limits.clone(),
    harness,
    model_executor,
    tool_executor,
    live: feed.clone(),
    telemetry,
});

let store = brain::LocalSessionStore::create(
    &sessions_dir.join(session_id.as_str()),
    session_id,
    &serde_json::to_value(&config)?,
    writer.clone(),
    feed.clone(),
)?;
let creating = brain::Session::begin(store.clone(), runtime.clone(), &config, &opening_transcript)?;
let session = creating.complete(config)?;

session
    .message(brain_protocol::MessageRequest {
        input: "Explain the current changes.".into(),
    })
    .await?;

Open only the session you need. When it needs explicit activation, call interrupt_unfinished_turn, then Session::open. LocalSessionStore::open on its own allows transcript and Event reads without an actor. To speed up the next open, call checkpoint() at a quiescent boundary before dropping execution; the projection it writes is disposable. Keep one live store and sequencer per session and serialize mutations to it. The stock server handles that coordination for you.

Hold a filesystem lock on the local data directory for the life of the process before opening mutable stores. When embedding the stock server's composition, brain_server::data_layout::lock provides that lock. Brain supports one local writer; cross-server ownership belongs to your host platform.

You supply the ports

Provide harness, model_executor and tool_executor implementations for your deployment. Set environment_control if your host supports resource operations; None leaves them unavailable.

  • Harness: an Arc<dyn brain::AgentHarness> selected at startup. It receives the session identity, activation input, and TurnServices. The stock server uses brain_sessions::StdioHarness; an embedding can implement the same Rust trait in-process. The implementation owns native state, compaction, and recovery policy.
  • Model executor: receives the session id and resolves the credential it sealed for it.
  • Tool executor: receives the Tool and its Environment entry.

A custom SessionStore can build asynchronous append completions with CommitHandle::from_completion. Returning success must mean the canonical records have committed.

What the runtime guarantees

Journal commits still land synchronously before effects, and recovery still rebuilds every projection from the same canonical journal. Embedding doesn't loosen admission: Session::begin and complete hold configuration to the same contract as the server.

What stays yours

Which sessions exist, which are running, what happens to them after a restart and when to forget them. Where environments live and how they're found. Credentials, and how HTTP retries are answered. All product policy. The runtime has opinions about correctness, not about your architecture.

Telemetry delivery

The telemetry channel is bounded and never holds up a turn. A worker drains queued records into ordered batches and retries a rejected batch for up to 30 seconds, so a sink may see the same batch more than once and must handle duplicates safely. When deliveries are exhausted, they're counted and reported through telemetry_delivery_dropped records if the queue still has room.

Telemetry is best effort. For resumable event forwarding, consume the session event endpoint, save its sequence cursor once the destination acknowledges a batch, and reconnect from that cursor. The session's canonical journal, not the telemetry queue, is the durable record.

On this page