Deployment
Operations guide for running the PRIOR engine in production. PRIOR ships as a single immutable
container with a native Rust serving path: no Python, no Node, and no external calls at
inference time. Default port 8089.
This supersedes any older "Python gateway on port 8000" material. Production is the native engine.
1. The container model
The image bakes everything needed to enforce policy except the generation weights (which are large and shared, so you mount them):
| Baked into the image | Supplied at run time |
|---|---|
The prior Rust binary + patched llama libraries |
The generation GGUF (mounted read-only) |
| The MiniLM encoder GGUF (the gate's embedder) | A license.bin node-locked to your host |
The default policy packs (harm_veto, codeops_minilm, …) |
Env configuration (below) |
The model steering registry (model_params.json) |
A writable state volume at /app/state |
Writable state (the license identity record, the SQLite governance DB, and live re-calibration
output) lives under /app/state, the only directory the non-root prior user owns. Mount a
volume there. It is not optional on a node-locked tier: the identity record is what binds this
license to this node, and a container that starts from an empty state volume derives a fresh node
identity, which seat enforcement reads as a second node. The activation is then denied and the
engine degrades to unsteered passthrough. You also lose your admin keys and audit log.
Minimal run (docker compose)
MODELS_DIR=/srv/models MODEL=Llama-3.2-3B-Instruct-Q4_K_M.gguf \
docker compose up -d
Minimal run (docker run)
docker run -d --name prior \
-p 127.0.0.1:8089:8089 \
-e PRIOR_NATIVE_MODEL=/models/Llama-3.2-3B-Instruct-Q4_K_M.gguf \
-v /srv/models:/models:ro \
-v prior-state:/app/state \
ghcr.io/eagle-logic/prior:slim-cpu
GPU
Use the CUDA image and offload layers to the GPU:
docker run -d --name prior --gpus all \
-p 127.0.0.1:8089:8089 \
-e PRIOR_NATIVE_MODEL=/models/Llama-3.2-3B-Instruct-Q4_K_M.gguf \
-e PRIOR_NATIVE_NGL=99 \
-v /srv/models:/models:ro -v prior-state:/app/state \
ghcr.io/eagle-logic/prior:slim
The reference 7–8B model at 4-bit needs ~6 GB VRAM; run one model per GPU.
2. Network exposure & auth
The published port is loopback-only by default. docker-compose.yml publishes to
127.0.0.1:8089, which is reachable for local testing but not on the network. This is intentional:
the /v1 endpoint is unauthenticated by default.
To expose the engine on a LAN or the internet, do both:
- Publish on a routable interface:
PRIOR_PUBLISH_ADDR=0.0.0.0. - Require a key on
/v1:PRIOR_REQUIRE_AUTH=1(then create keys via/admin/keys).
Put TLS termination (a reverse proxy / load balancer) in front for anything internet-facing.
3. Licensing (node-locked)
The engine verifies an ED25519-signed license bound to the host's hardware fingerprint before
enabling steering. Eagle Logic's public key is baked into the published image, so it verifies
locally and never calls home in the inference path, and you do not supply a key. (Connected
tiers make a periodic background license check-in; the air-gapped tier makes none and runs fully
offline (see Licensing).) You only mount your license.bin:
docker run -d --name prior --gpus all \
-p 127.0.0.1:8089:8089 \
-e PRIOR_NATIVE_MODEL=/models/model.gguf \
-v /srv/models:/models:ro \
-v /path/to/license.bin:/app/license.bin:ro \
-v prior-state:/app/state \
ghcr.io/eagle-logic/prior:slim
- Without a valid license, PRIOR degrades to plain inference with no gate actuation
(
x-prior-steering: disabled) rather than failing to boot. - There is no bypass. A license verifies or it does not load, local development included.
- A license binds customer id, hardware id, tier, expiry, and capabilities. Expired, tampered, or wrong-host licenses are rejected. Full details in Licensing.
4. Environment variable reference
Everything is optional except where noted. Defaults shown are the container defaults.
Server & network
| Variable | Default | Purpose |
|---|---|---|
PRIOR_PORT |
8089 |
HTTP port. |
PRIOR_BIND_HOST |
127.0.0.1 |
Interface the server binds inside the container. The default is the container's own loopback, which no -p mapping can reach — set 0.0.0.0 under docker run or the engine starts fine and refuses every connection. Compose sets it for you. |
PRIOR_PUBLISH_ADDR |
127.0.0.1 |
Host interface the port is published on (compose). Set 0.0.0.0 to expose. |
PRIOR_ALLOWED_ORIGINS |
* |
CORS allowed origins (comma-separated). Restrict in production. |
Model & engine
| Variable | Default | Purpose |
|---|---|---|
PRIOR_POLICY |
on |
Master policy switch. on = the shipped detect+steer policy (harmful requests and destructive ops refused); off = byte-for-byte passthrough. Detection and steering always move together. |
PRIOR_NATIVE_MODEL |
(none) | Path to the generation GGUF (required). |
PRIOR_NATIVE_ENCODER |
baked MiniLM | Path to the gate's encoder GGUF. |
PRIOR_NATIVE_ARBITERS |
harm_veto, codeops_minilm, injection.byteppm |
Comma-separated arbiter pack paths to load at boot. The image sets all three; override to load your own. |
PRIOR_NATIVE_NGL |
0 |
GPU layers to offload for generation (99 = all; 0 = CPU). |
PRIOR_NATIVE_ENCODER_NGL |
0 |
GPU layers for the encoder. |
PRIOR_MAX_CONTEXT |
8192 |
Max context window. |
PRIOR_MODEL_REGISTRY |
/app/state/model_params.json |
Per-model steering registry (golden layer + alpha). |
PRIOR_SPAN_SCORING |
1 |
Span-score padding defense on/off. |
PRIOR_SPAN_K |
12 |
Span-scoring neighbor count. |
PRIOR_GRAD_MAX_ANCHOR |
256 |
Max anchor length for the steering gradient. |
Auth & license
| Variable | Default | Purpose |
|---|---|---|
PRIOR_REQUIRE_AUTH |
0 |
Require a Bearer key on /v1 (live-toggleable via /admin/runtime). |
PRIOR_API_KEY |
(none) | Seed an Admin key at startup (env-only, not persisted). |
PRIOR_LICENSE_PUBLIC_KEY |
removed | No longer read. The verification key is compiled into the engine; it was an env var until it became clear a published image could be pointed at any key. Setting it has no effect. |
PRIOR_LICENSE_FILE |
auto-search | Path to license.bin. |
PRIOR_LICENSE_REFRESH_URL |
(none) | Optional connected-tier license auto-refresh endpoint. |
PRIOR_LICENSE_REFRESH_TICK_SECS |
3600 |
Refresh poll interval. |
PRIOR_LICENSE_REFRESH_THRESHOLD_DAYS |
7 |
Days before expiry to trigger a refresh. |
Storage & state
| Variable | Default | Purpose |
|---|---|---|
PRIOR_STATE_DIR |
/app/state |
Writable state directory (owned by the non-root user). |
PRIOR_DB_PATH |
/app/state/ssa_oracle.db |
Governance SQLite DB (keys, audit). :memory: for ephemeral. |
Observability & safety
| Variable | Default | Purpose |
|---|---|---|
PRIOR_LOG_LEVEL / RUST_LOG |
info |
Log verbosity. |
PRIOR_JSON_LOGS |
(none) | Emit structured JSON logs (set to enable). |
PRIOR_YELLOW_MODE |
inline |
YELLOW confirm delivery: inline (append to content) or header only. |
PRIOR_SAFETY_AUDIT_RETAIN |
1000 |
Rows retained in the durable safety audit. |
PRIOR_DIAG_TOKEN |
(none) | Optional token for privileged diagnostics. |
Policy ingest (extractor)
Only needed to use POST /admin/packs/ingest. Unconfigured ⇒ a clear 400, never a silent dial.
| Variable | Purpose |
|---|---|
PRIOR_EXTRACTOR_URL |
Extraction LLM endpoint (llama.cpp /completion or OpenAI-compatible). |
PRIOR_EXTRACTOR_ENDPOINT / _CHAT |
API path / chat-style toggle. |
PRIOR_EXTRACTOR_TEMPERATURE / _MAX_TOKENS / _TIMEOUT |
Sampling + limits. |
5. Health, readiness & Kubernetes
| Probe | Endpoint | Behavior |
|---|---|---|
| Liveness | GET /health |
Answers as soon as the HTTP server is up (the model loads lazily). |
| Readiness | GET /health |
Use the same endpoint; back it with a startupProbe budget generous enough for a cold model load/download. |
livenessProbe:
httpGet: { path: /health, port: 8089 }
periodSeconds: 10
startupProbe:
httpGet: { path: /health, port: 8089 }
failureThreshold: 120 # tolerate a cold-node model load
periodSeconds: 5
Because the engine is stateless per request, scale horizontally by running more replicas behind a load balancer; each replica needs its own node-locked license (or a cluster license; see Licensing).
6. Observability
- Metrics.
GET /metricsis Prometheus exposition: zone distribution (GREEN/YELLOW/RED), refusal counts, and latency / token / injection histograms. Scrape it directly. - Structured logs. Set
PRIOR_JSON_LOGSfor one JSON object per line on stdout, ready for Datadog / Splunk / ELK. Routing decisions and steering-apply events are structured fields. - Safety audit.
GET /admin/audit/safetyis the durable, queryable trail of every gate decision (prompt hashes only, never text or completions). Pairx-prior-decision-idfrom a response with the matching audit row for end-to-end traceability.
7. Upgrades
The container is the atomic unit. To upgrade, pull the new image and replace the container; mount the
same /app/state volume and the same license.bin. Policy packs authored through ingest live under
your state/packs volume, so persist that volume and your custom policies survive replacement.
See also: Getting Started · API Reference · Licensing.