# Host configuration (/brain/docs/reference/configuration)

Brain reads its host configuration from a JSON file passed with `-config` (defaults to `brain.json`). You can validate the configuration file and all referenced environment variables without starting the HTTP server by passing `-check`:

```sh tab="macOS / Linux"
go run ./cmd/brain -config brain.json -check
```

```powershell tab="Windows"
go run ./cmd/brain -config brain.json -check
```

Configuration files are limited to 4 MiB. Unknown JSON fields and trailing JSON data are rejected at startup. Relative paths (such as `data_dir` or `persistence.directory`) resolve from the working directory of the Brain process.

## Minimal example [#minimal-example]

```json
{
  "listen": "127.0.0.1:8080",
  "public_url": "http://127.0.0.1:8080",
  "data_dir": ".brain",
  "tokens": [
    { "token_env": "BRAIN_API_KEY", "tenant": "local", "manage": true }
  ],
  "harnesses": {
    "pi": { "command": ["node", "runners/pi/dist/main.js"] }
  },
  "providers": {
    "openai": { "api_key_env": "OPENAI_API_KEY" }
  },
  "tools": []
}
```

## Top-level fields [#top-level-fields]

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `listen` | `string` | `"127.0.0.1:8080"` | TCP `host:port` address to bind. Validated with `net.SplitHostPort`. |
| `public_url` | `string` | `"http://127.0.0.1:8080"` | Base `http` or `https` URL passed as `brain_url` to tools with `inspect_session: true`. Must not contain credentials, query parameters, or fragments. |
| `data_dir` | `string` | `".brain"` | Local directory for `metadata.sqlite` and per-session directories (`sessions/<id>/`). Must be non-empty. |
| `tokens` | `Token[]` | Required | Non-empty array of API token grants (see [`tokens`](#authentication-tokens-tokens)). |
| `harnesses` | `Record<string, Runner>` | Required | Map of harness name (`1`–`64` characters) to child process command (see [`harnesses`](#harnesses-harnesses)). At least one harness is required. |
| `providers` | `Record<string, Provider>` | `{}` | Map of model provider prefix to credentials and optional transport overrides (see [`providers`](#model-providers-providers)). |
| `tools` | `Binding[]` | `[]` | Array of external HTTP, SSE, or MCP tool bindings (see [`tools`](#external-tools-tools)). |
| `limits` | `Limits` | See below | In-memory, disk, queue, and SSE subscriber bounds (see [`limits`](#resource-limits-limits)). |
| `persistence` | `Settings` | `null` | Optional background checkpoint storage and session index settings (see [`persistence`](#external-persistence-persistence)). |
| `credential_keys` | `object` | `null` | Independent encryption key configuration for private session overrides. |

## Authentication tokens (`tokens`) [#authentication-tokens-tokens]

Each entry in `tokens` binds an environment variable containing a bearer secret to a tenant and permission scope. Duplicate token values across entries are rejected at startup. See [Authentication & tenants](/brain/docs/guides/authentication).

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `token_env` | `string` | Yes | — | Name of the environment variable holding the bearer token. The environment variable must be set at startup and contain at least 24 bytes. |
| `tenant` | `string` | Yes | — | Tenant identifier (`1`–`128` bytes). All operations using this token are isolated to this tenant. |
| `session` | `string` | No | `""` | Optional 32-character hex session ID. When set, the token can only access that single session and cannot create new sessions. |
| `manage` | `boolean` | No | `false` | Permits management operations (`POST /sessions`, `resume`, `close`, `flush`, and `restore`). |
| `read_only` | `boolean` | No | `false` | Restricts the credential to `GET` requests (`list`, `get`, `events`, `sync`, and `catalog`). |

## Harnesses (`harnesses`) [#harnesses-harnesses]

Each key in `harnesses` is the harness name clients pass in `POST /sessions` (for example, `"pi"`).

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `command` | `string[]` | Yes | Non-empty command and arguments used to spawn the harness child process (for example, `["node", "runners/pi/dist/main.js"]`). `command[0]` must be non-empty. |
| `max_shared` | `integer` | No | Session attachments per host; default `8`, range `1`–`1024`. |
| `max_active_turns` | `integer` | No | Simultaneous turns per host; defaults to `max_shared`, range `1`–`max_shared`. |
| `max_hosts` | `integer` | No | Maximum live hosts for this harness; default `16`, minimum `1`. |
| `max_starting` | `integer` | No | Concurrent session opens; default `4`, minimum `1`. |

Hosts use private working and home directories. Linux process guardians and Windows Job Objects own descendant lifetimes. Idle session eviction detaches only that session; the last detach closes the host. Global `limits.active` also bounds resident native session attachments.

## Private credential keys [#private-credential-keys]

```json
{"credential_keys":{"active":"key-2026","keys":{"key-2026":"BRAIN_CREDENTIAL_KEY"}}}
```

`active` selects a key ID from `keys`. Each value names an environment variable containing a base64-encoded 32-byte AES key. Every configured key must be available at startup. Keep retired keys available while retained checkpoints still reference them. Application code may instead supply `Options.Keys` implementing `CredentialKeys`.

Private overrides are authenticated encrypted SQL records, bound to tenant, session, and alias. Creation rejects overrides without configured keys. Public JSON never contains ciphertext or plaintext values. [Credential administration](/brain/docs/sdks/application#persist-private-overrides) covers rotation, revocation, and checkpoint retention.

## Model providers (`providers`) [#model-providers-providers]

Each key in `providers` matches the `provider` prefix in `config.model` (`provider/model`). Every configured provider must have its `api_key_env` environment variable set and non-empty when Brain starts. See [Models & providers](/brain/docs/reference/models).

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `api_key_env` | `string` | Yes | — | Environment variable containing the provider API key. Passed to the harness runner via stdio `open` options. |
| `base_url` | `string` | No | `""` | Optional `http` or `https` base URL override for proxies or compatible endpoints (must not include user credentials). |
| `api` | `string` | No | `""` | Optional transport override in the Pi model registry (for example, `"openai-completions"`). |

## External tools (`tools`) [#external-tools-tools]

Each element in `tools` registers one tool that sessions belonging to authorized `tenants` can enable in `config.tools`. See [External tools](/brain/docs/tools) and [MCP tools](/brain/docs/tools/mcp) for protocol and discovery details.

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `name` | `string` | Yes | — | Unique tool name matching `^[a-zA-Z][a-zA-Z0-9_]{0,63}$`. |
| `description` | `string` | Yes | — | Non-empty description shown to the model. |
| `input_schema` | `object` | Yes | — | JSON Schema for tool arguments. External `$ref` URLs are rejected. |
| `output_schema` | `object` | No | `null` | JSON Schema for successful `structured_content`. Error results bypass the success schema, while content and size limits still apply. |
| `url` | `string` | Yes | — | Target `http` or `https` endpoint URL (no credentials or URL fragments). |
| `tenants` | `string[]` | Yes | — | Non-empty list of tenant IDs permitted to see and enable this tool. |
| `token_env` | `string` | No | `""` | Optional environment variable holding the bearer token Brain sends in `Authorization: Bearer <token>`. Must be non-empty at startup when specified. |
| `transport` | `string` | No | `"http"`, or `"mcp"` when `mcp_tool` is set | Transport registered at startup. Unknown names fail config validation. Built-ins are `http` (JSON/SSE) and `mcp`. |
| `mcp_tool` | `string` | No | `""` | Remote MCP tool name. When set, Brain calls `url` using the MCP Streamable HTTP transport instead of the native HTTP/SSE tool protocol. |
| `timeout_seconds` | `integer` | No | `300` | Per-call deadline in seconds. Allowed range: `1`–`86400` (24 hours). |
| `max_output_bytes` | `integer` | No | `1048576` | Maximum response body size in bytes. Allowed range: `1`–`2097152` (2 MiB). |
| `inspect_session` | `boolean` | No | `false` | When `true`, Brain issues a short-lived, read-only session token (`inspection_token`) and `brain_url` for the duration of each call. Cannot be combined with `mcp_tool`. |

## Resource limits (`limits`) [#resource-limits-limits]

Every field is optional. Fields you omit keep the defaults below, so you can override only the limits you need. Brain validates the combined values at startup.

| Field | Type | Default | Allowed range | Description |
| --- | --- | ---: | --- | --- |
| `active` | `integer` | `16` | `>= 1` | Maximum concurrent running turns and resident native session attachments across the server. Hosts may share several attachments. |
| `loaded` | `integer` | `1024` | `>= active` | Maximum sessions held in memory at once. Idle unreferenced sessions are evicted when full. |
| `queue` | `integer` | `16` | `1`–`1024` | Maximum queued `user.message` inputs per session. |
| `input_bytes` | `integer` | `65536` | `1`–`1048576` (1 MiB) | Maximum byte length of `user.message` `text` or session `instructions`. |
| `session_bytes` | `integer` | `1073741824` | `>= 16777216` (16 MiB) | Maximum local event log (`events.jsonl`) and checkpoint artifact size per session (default 1 GiB). |
| `subscribers` | `integer` | `128` | `>= 1` | Maximum concurrent SSE connections across the server. |
| `subscriber_events` | `integer` | `128` | `>= 1` | Maximum buffered live events per SSE subscriber before Brain disconnects the slow client. |
| `subscriber_bytes` | `integer` | `2097152` | `>= 4096` | Maximum buffered live event bytes per SSE subscriber before disconnect (default 2 MiB; each event accounts for `len(data) + 256` bytes). |

## External persistence (`persistence`) [#external-persistence-persistence]

Configure `persistence` to upload immutable 64 KiB transcript blocks and native checkpoints in the background. See [Persistence & recovery](/brain/docs/guides/persistence) for provider setup and handoff steps.

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `provider` | `string` | Yes | — | Storage backend: `"filesystem"`, `"s3"`, `"r2"`, or `"gcs"`. |
| `directory` | `string` | When `filesystem` | `""` | Target directory on disk for `"filesystem"` checkpoints. |
| `bucket` | `string` | When `s3`, `r2`, or `gcs` | `""` | Object storage bucket name. |
| `region` | `string` | No | `"auto"` for `r2` | AWS/S3 region. Rejected when `provider` is `"gcs"`. |
| `endpoint` | `string` | When `r2` | `""` | Custom `http` or `https` S3/R2 endpoint URL (enables path-style addressing). Rejected when `provider` is `"gcs"`. |
| `prefix` | `string` | No | `""` | Optional relative object key prefix (must not start with `/`, contain `\`, or traverse `..`). |
| `access_key_env` | `string` | When `r2` | `""` | Environment variable holding the S3/R2 access key ID. Optional for `"s3"` (which falls back to the default AWS credential chain); rejected for `"gcs"`. Both `access_key_env` and `secret_key_env` must be set together. |
| `secret_key_env` | `string` | When `r2` | `""` | Environment variable holding the S3/R2 secret access key. Rejected for `"gcs"`. |
| `postgres_env` | `string` | No | `""` | Optional environment variable containing a PostgreSQL connection string (`postgres://...`) for cross-instance session discovery. Must be non-empty at startup when specified. |
| `interval_seconds` | `integer` | No | `5` | Background sync scan interval in seconds (`1`–`3600`). |
| `queue` | `integer` | No | `128` | Maximum pending dirty sessions in the background sync queue (`1`–`10000`). When full, Brain rejects new writes with `429 overloaded` and marks `/health/ready` as `503`. |
