> ## Documentation Index
> Fetch the complete documentation index at: https://internal.september.wtf/llms.txt
> Use this file to discover all available pages before exploring further.

# BAP Engine

> The orchestrator that runs and manages a fleet of Engine instances per user.

The Engine is single-tenant by design — one process, one brain, one
user. Real products serve thousands of users. Something has to stand
between the product and the Engine fleet to provision instances,
route traffic, monitor health, rotate keys, and clean up after
sleeping users. That something is **bap-engine**.

bap-engine is the orchestrator we use to run the public Engine
product. It lives in [`septemberai/bap-engine`](https://github.com/septemberai/bap-engine).

## What it does

A product (like our `bap-backend`) talks to bap-engine, not directly to
Engine instances. bap-engine handles:

* **Provisioning** — creating a fresh Engine for a new user.
* **Discovery** — looking up which Engine belongs to which user.
* **Admission** — rate-limit + quota checks before letting a request
  through.
* **Lifecycle** — start, stop, sleep, wake, destroy, key-rotate.
* **Health** — periodic probes; auto-restart on failure with backoff.
* **Audit** — every lifecycle action logged to Postgres.
* **Fleet metrics** — aggregate state for ops dashboards.

The product never touches Docker, never holds engine API keys
long-term, never decides whether to provision. bap-engine owns all of
that.

## How it fits

```mermaid theme={null}
flowchart TB
    Internet["Internet"]
    BAP["bap-backend<br/>(NestJS, public)"]
    Orch["bap-engine orchestrator<br/>(FastAPI :8000)"]
    PG[("PostgreSQL<br/>orchestrator state")]
    E1["Engine container<br/>(user A, :9001)"]
    E2["Engine container<br/>(user B, :9002)"]
    E3["Engine container<br/>(user C, :9003)"]
    Brain1[("brain_a.sqlite")]
    Brain2[("brain_b.sqlite")]
    Brain3[("brain_c.sqlite")]
    LLM["Upstream LLM provider"]

    Internet --> BAP
    BAP -->|X-Platform-Key| Orch
    Orch --> PG
    Orch -->|Docker API| E1
    Orch -->|Docker API| E2
    Orch -->|Docker API| E3
    BAP -->|X-Engine-Key, /execute| E1
    BAP -->|X-Engine-Key, /execute| E2
    BAP -->|X-Engine-Key, /execute| E3
    E1 --> Brain1
    E2 --> Brain2
    E3 --> Brain3
    E1 --> LLM
    E2 --> LLM
    E3 --> LLM

    classDef public fill:#fee2e2,stroke:#991b1b
    classDef internal fill:#dbeafe,stroke:#1d4ed8
    classDef store fill:#fef3c7,stroke:#a16207
    classDef external fill:#f4f4f5,stroke:#71717a
    class Internet,BAP public
    class Orch,E1,E2,E3 internal
    class PG,Brain1,Brain2,Brain3 store
    class LLM external
```

The orchestrator stays out of the data path. Once `POST /admit`
returns an Engine URL and key, the product talks to the Engine
directly for `/execute` — including SSE streaming. bap-engine
coordinates; it does not proxy.

## Why a separate service

bap-engine could in principle live inside the Engine. It used to —
the orchestrator was extracted from `engine` into bap-engine in
v2.3.0. We split because:

1. **Different lifecycles.** The Engine ships when its agent loop or
   memory layer changes. The orchestrator ships when fleet management
   changes. Coupling them slows both.
2. **Different runtimes.** The Engine runs as one container per user
   with the user's brain mounted. The orchestrator runs once and
   talks to many Engines via the Docker API.
3. **Different blast radius.** A bug in the Engine affects one user;
   a bug in the orchestrator affects the whole fleet. Different
   review thresholds.
4. **Different surface.** The Engine's API is for agents
   (`/execute`, `/hitl`, `/memory`). The orchestrator's API is for
   fleet ops (`/engines/provision`, `/admit`). They don't share
   callers.

## What it isn't

* **Not a load balancer.** Each user has their own Engine; there's no
  routing across users.
* **Not a proxy.** The orchestrator hands the product an Engine URL
  and stays out of the call.
* **Not a cache.** It writes state to Postgres and reads on every
  request.
* **Not multi-product-shared.** Each product has its own product ID
  and its own slice of the fleet. Users are unique within a product,
  not across products.

## Where to start

<CardGroup cols={3}>
  <Card title="Quickstart" icon="rocket" href="./quickstart">
    Run bap-engine locally with the orchestrator + Postgres in Docker.
  </Card>

  <Card title="Architecture" icon="diagram-project" href="./architecture">
    The orchestrator's internals — registry, lifecycle, health, backends.
  </Card>

  <Card title="API reference" icon="book" href="./api-reference/overview">
    Every endpoint, every parameter.
  </Card>
</CardGroup>

If you're integrating an existing product, the
[engine contract](./engine-contract) is the relevant page — it spells
out what you call, what you get back, and how the keys flow.
