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

# Reference Deployment

> Deploy the Gateway with SQLite, scoped bearer auth, and a reverse proxy.

The reference deployment runs one Gateway process, one SQLite database file, and a TLS reverse proxy: use it when self-hosting without the managed control plane.

For multi-tenant hosted deployments, pair the Gateway with [Control Plane](/deployment/control-plane): orgs, projects, teams, billing account records, usage events, secret references, and audit export.

## Docker Compose

From the repo root:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose -f deploy/reference/docker-compose.yml up
```

The Gateway listens on `7331` inside the compose network; Caddy exposes HTTP/TLS. The compose file mounts a SQLite volume at `/data` and reads short-lived bearer grants from `/data/tokens.json`; absent that file, the Gateway starts with an empty in-memory token set and denies token auth until you mount or write a token store.

Issue a local token grant: by default it returns a scoped action handle and writes the bearer-keyed grant to the local token store without printing the bearer; use `--reveal-token` only for manual operator workflows that need the raw bearer.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
bunx smithers-orchestrator token issue --scopes run:read,run:write,approval:submit --ttl 1h --action-id gateway
```

Copy the resulting grant-store entry into the deployment's token store; revoking the bearer token also revokes its action handles and records the revocation in the audit trail:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
bunx smithers-orchestrator token revoke <token>
```

Automation can hand a broker handle to an action without exposing the bearer in model-visible context: resolve it locally and inject the bearer only into the child-process environment.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
bunx smithers-orchestrator token exec --handle <action-handle> --action-id gateway --scopes run:read --command 'curl -H "Authorization: Bearer $SMITHERS_API_KEY" http://localhost:7331/v1/runs'
```

## Single Host

Use `deploy/reference/systemd/smithers-gateway.service` for the Gateway process and `deploy/reference/systemd/smithers-caddy.service` for Caddy; copy `smithers-gateway.env.example` to `/etc/smithers/gateway.env`, then set:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
SMITHERS_DB_PATH=/var/lib/smithers/smithers.db
SMITHERS_TOKEN_STORE=/etc/smithers/tokens.json
SMITHERS_GATEWAY_MODULE=/etc/smithers/gateway.mjs
HINDSIGHT_URL=http://127.0.0.1:8888
HINDSIGHT_API_KEY=replace-me
HINDSIGHT_BANK_PREFIX=production-
SMITHERS_GATEWAY_HEADERS_TIMEOUT_MS=30000
SMITHERS_GATEWAY_REQUEST_TIMEOUT_MS=60000
```

`SMITHERS_GATEWAY_MODULE` can export `register(gateway)` or a default function; register workflows there.

## Gateway Environment

| Variable                              | Default                  | Purpose                                                                                      |
| ------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------- |
| `PORT`                                | `7331`                   | Gateway listen port inside the container or host.                                            |
| `SMITHERS_DB_PATH`                    | `/data/smithers.db`      | SQLite database path made available to the gateway module for workflow storage.              |
| `SMITHERS_TOKEN_STORE`                | `/data/tokens.json`      | JSON token-grant store for token auth.                                                       |
| `SMITHERS_GATEWAY_MODULE`             | `/workspace/gateway.mjs` | Module that registers workflows on startup.                                                  |
| `HINDSIGHT_URL`                       | unset                    | Enables the Hindsight memory service; unset preserves local SQLite facts and keyword recall. |
| `HINDSIGHT_API_KEY`                   | unset                    | Optional Hindsight bearer token; store it as a secret.                                       |
| `HINDSIGHT_BANK_PREFIX`               | unset                    | Optional prefix for configured Hindsight bank ids.                                           |
| `SMITHERS_GATEWAY_HEARTBEAT_MS`       | `15000`                  | WebSocket heartbeat interval.                                                                |
| `SMITHERS_GATEWAY_EVENT_WINDOW`       | `10000`                  | Per-run replay window size (number of events) for `streamRunEvents`.                         |
| `SMITHERS_GATEWAY_HEADERS_TIMEOUT_MS` | `30000`                  | Maximum time to receive complete HTTP headers.                                               |
| `SMITHERS_GATEWAY_REQUEST_TIMEOUT_MS` | `60000`                  | Maximum time to receive and parse a complete HTTP request, including body.                   |

## Kubernetes

The minimal manifests in `deploy/reference/k8s/` create:

* a `smithers` namespace
* a single Gateway `Deployment`
* a `ConfigMap` (`smithers-gateway-config`) supplying Gateway environment variables
* an empty Hindsight URL and bank prefix in the `ConfigMap`, with the optional API key in the Secret
* a SQLite `PersistentVolumeClaim`
* a token `Secret`
* a `Service` and `Ingress`

The reference directory doesn't deploy Hindsight, so `HINDSIGHT_URL` is empty and the Gateway keeps the local SQLite fallback; set it only after deploying a reachable Hindsight service backed by Postgres and pgvector (cloud signup or self-host steps: [Set Up Semantic Memory](/guide/setup/semantic-memory)).

Edit `deploy/reference/k8s/secret.example.yaml` to set the bearer token and update the host in `deploy/reference/k8s/ingress.yaml` before applying:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
kubectl apply -f deploy/reference/k8s/
```

## Event Stream Reconnection

Pass `afterSeq` with the last seen sequence number when reconnecting to a stream; the Gateway then:

* Replays any missed events still within the bounded per-run window.
* Emits a `GapResync` frame (fields: `fromSeq`, `toSeq`, run snapshot) if the window has truncated, then resumes with available events.
* Sends `Heartbeat` frames on a separate interval; these do not carry run events.

All HTTP responses include `X-Smithers-API-Version: v1`.
