---
title: Standalone (one binary, one file)
path: deployment/standalone
status: published
---

# Standalone (one binary, one file)

Standalone mode runs the entire ScaiLog system as a single process writing to a
single directory of SQLite files. The server embeds the agent role: it opens the
local Unix socket itself, skips the batch-shipping hop, and writes entries
straight into `scailog.db`. This is a first-class supported deployment (design
invariant P6) — the right shape for a dev laptop, a single host, or a small
appliance.

## Install

Standalone is the server component, so install the `server` extra:

```bash
python3 -m venv .venv && . .venv/bin/activate
pip install 'scailog[server]'
```

This pulls FastAPI, uvicorn, `cryptography`, PyYAML, `zstandard`, and `httpx` —
everything the server needs. No other Scai* service is required: key management
and authentication are built in (design invariant P1).

## Initialize and get the bootstrap key

Run `--init` once against a fresh data directory. It creates the databases and
key material and mints the bootstrap API key, printing it a single time. Store it
now — it is not recoverable.

```bash
scailog-server --init --data-dir ./data
```

The bootstrap key is a `dpo`-role key (the full-capability operator role). Use it
to mint narrower keys for services and readers — see
[Authentication & API keys](/docs/scailog/deployment/auth-and-keys). If keys
already exist, `--init` prints `(keys already exist; no bootstrap key minted)`
and mints nothing.

## Run the server

Start the server in standalone mode. Two environment variables matter:

- `SCAILOG_KEYSTORE_PASSPHRASE` unlocks the file keystore that protects the root
  key (`KRoot`). Set it however your host manages secrets; the example uses a dev
  value.
- `SCAILOG_STANDALONE=true` (equivalently the `--standalone` flag) turns on the
  embedded agent, so the process opens the local socket and ingests directly.

```bash
SCAILOG_KEYSTORE_PASSPHRASE=dev SCAILOG_STANDALONE=true \
  scailog-server --standalone --data-dir ./data --port 8080
```

Flags accepted by `scailog-server`:

| Flag | Default | Meaning |
| --- | --- | --- |
| `--standalone` | off | Embed the agent role (open the local socket, ingest directly). |
| `--data-dir` | `./scailog-data` | Directory for all SQLite files and key material. |
| `--host` | `127.0.0.1` | Bind address for the HTTP API. |
| `--port` | `8080` | Bind port for the HTTP API. |
| `--init` | — | Initialize, print the bootstrap key, and exit. |

The data directory and socket path can also come from the environment:
`SCAILOG_DATA_DIR`, `SCAILOG_STANDALONE`, `SCAILOG_KEYSTORE_PASSPHRASE`, and
`SCAILOG_SOCKET` (the local socket, default `/run/scailog/agent.sock`).

## The embedded agent

In standalone mode the server opens the Unix domain socket on startup and handles
each `emit` frame in-process. Rather than encrypting, caching, and batch-shipping
(the distributed agent's job), the embedded agent applies the policy engine and
encrypts PI inline with the server's own `KeyManager`, then inserts straight into
`scailog.db`. PI is encrypted exactly as on the direct HTTP ingest path — the
same per-subject DEKs, the same field packing — so a log written through the
socket is indistinguishable at rest from one posted to `/v1/ingest`.

Your SDK talks to this socket exactly as it would to a standalone agent. Point it
at the same socket path (`SCAILOG_SOCKET`) and emit; on any socket failure the
SDK falls back to stderr with PI values redacted (see
[SDKs](/docs/scailog/sdk)).

## Files created in the data directory

The `--data-dir` holds a small set of SQLite files and key material. The keymap
is deliberately a **separate** database (design invariant P5) so its backup
retention can be kept short — destroying a subject's key is how erasure works.

| File | Contents |
| --- | --- |
| `scailog.db` | Entries, call sites, policies, API keys, audit findings, FTS5 index. |
| `keymap.db` | Per-subject key wrapping (the DEKs whose destruction erases a subject). Separate file, short backup retention. |
| `scailog-root.key` | The passphrase-protected file keystore holding `KRoot`. |
| `report-keyring.json` | The Ed25519 report-signing keyring (active + retired keys) for DSAR reports and erasure receipts. |

A legacy single `report.key`, if present, is imported into the keyring as the
initial active key. The FTS5 index inside `scailog.db` covers only the free-text
`message` and plaintext `fields` — encrypted `pi_fields` never enter it, which is
the structural guarantee that PI cannot leak through search.

## Growing beyond one file

Standalone is not a dead end. Because both tiers use the same SQLite+FTS5 engine,
you scale by changing the deployment, not the code: replicate the database with
Litestream or rqlite, shard tenants across files, or split into a central server
with per-host agents. See [Deployment](/docs/scailog/deployment) and
[Agent + server](/docs/scailog/deployment/agent-and-server).
