API Reference
The PRIOR engine is a single native Rust server. It exposes an OpenAI-compatible inference
endpoint with the Tri-State WHEN gate + golden-layer steering applied in-process, plus a
governance surface under /admin, plus system endpoints. Default port 8089 (PRIOR_PORT).
One request path for proprietary controls. All PRIOR-specific per-request options ride a single
prior_optionsobject onPOST /v1/chat/completions. A vanilla OpenAI client that never sendsprior_optionsis unaffected (the gate still applies).
Base URL: http://<host>:8089
Auth: Authorization: Bearer <api-key>. /v1 user-auth is off by default and toggleable
live (PATCH /admin/runtime or PRIOR_REQUIRE_AUTH); /admin always requires an
Operator/Admin key.
Inference
POST /v1/chat/completions
OpenAI-compatible chat completion. messages are chat-templated server-side using the model's
own template. The WHEN gate routes on the combined system+user intent (so a jailbreak in the system
prompt is gated too), and steering is applied per the routing decision.
Request. Standard OpenAI fields plus the optional prior_options extension:
{
"model": "prior",
"messages": [
{"role": "system", "content": "You are our support assistant."},
{"role": "user", "content": "What port does our SSH service listen on?"}
],
"max_tokens": 256,
"stream": false,
"prior_options": {
"ephemeral_memory": {
"target": "6022",
"pin_phrase": "Our SSH service listens on port 6022"
}
}
}
| Field | Type | Notes |
|---|---|---|
model |
string? | Tolerated/ignored; one model per container. |
messages |
array | {role, content} where role is system / user / assistant. |
max_tokens |
integer | Default 256. |
temperature |
number? | Accepted for compatibility; decoding is greedy/deterministic. |
stream |
bool? | SSE (chat.completion.chunk) when true. |
prior_options |
object? | PRIOR controls (see below). |
Response. A standard OpenAI chat.completion object (or an SSE stream when stream: true).
PRIOR telemetry is returned in response headers (additive; OpenAI clients ignore them).
On a YELLOW route the pack's confirm notice is also prepended to the message content (unless
PRIOR_YELLOW_MODE=header), so header-blind UIs still surface it.
prior_options
| Field | Type | Effect |
|---|---|---|
ephemeral_memory |
{target, pin_phrase} |
Stateless fact injection. Steers the golden-layer residual toward target while teacher-forcing pin_phrase, so the model recalls a fact it otherwise wouldn't know. The client owns RAG / user state, so re-send each turn. Injected only on a GREEN route; any YELLOW/RED flag suppresses it (safety > memory). |
signals |
{name: float} |
Scores from your own detectors. A pack declaring external_signal: "<name>" is scored from this map instead of from an embedding, then composes through the ordinary precedence lattice — so an in-house or third-party classifier drives PRIOR's enforcement, not just a label. See Bring your own detector. |
engage_override |
bool? | true = force a refusal even on GREEN/YELLOW; false = suppress steering (vanilla passthrough even on RED); omit / null = use the gate decision. |
steer |
object? | Explicit low-level steering override (gate bypassed). For calibration / efficacy harnesses. Licensed-only. Fields below. |
steer object (advanced; you rarely need this, since the gate does it for you):
| Field | Meaning |
|---|---|
engage |
apply steering this request |
target |
steering target token/phrase (e.g. "cannot") |
alpha |
steering strength |
golden |
golden-layer index override |
onset_n |
number of onset tokens hard-pinned |
tau |
maintenance threshold |
recompute_every |
re-projection cadence (0 = onset-only) |
pin_n, pin_phrase |
teacher-forced pin length + phrase |
reactive_repin, repin_markers |
reactive re-pin on marker tokens |
logits_only |
force the backward-free steering path for this request (see below) |
steer.logits_only is one-way. A request may opt into logits-only, but it can never opt
out of it: if the engine selected logits-only for this model (because the architecture has no
usable backward pass, or VRAM is tight), a request asking for L2LM is ignored rather than crashing.
Set it globally with PRIOR_LOGITS_ONLY=1 or live via PATCH /admin/runtime.
Bring your own detector
PRIOR's cosine gate is a reference detector, not the product. If you have a classifier that knows your traffic better — an in-house model trained on your own data, a commercial safety classifier, a regex, a deny-list — you can drive PRIOR's enforcement from it directly.
Declare a pack with external_signal, then pass that detector's score on each request:
// the pack
{ "pack": "house_classifier", "external_signal": "house", "on_missing": "red",
"tristate": { "t_low": 0.55, "t_high": 0.80 }, "enforcement": "hard", … }
// the request — you score first, then call
{ "model": "prior", "messages": [ … ],
"prior_options": { "signals": { "house": 0.87 } } }
Three properties worth knowing:
- PRIOR never calls out. You score first and pass the result inline. There is no round-trip in the serving path, no second service to keep up, and no new failure mode between the request and the answer.
- The score is on your scale. A foreign score is not a zone. Calibrate the consuming pack's
t_low/t_highagainst your detector's benign distribution, exactly as a cosine pack is calibrated against ours. PRIOR stores and enforces what you declare; it will not re-derive your thresholds, because re-deriving them from exemplars the pack does not have would replace your policy with a meaningless number. - It composes. An external pack sits in the same precedence lattice as a cosine pack, so a classifier verdict and a membership boundary can both be live, and the more restrictive one wins.
on_missing decides what happens when the named signal is absent from a request — "red" fails
closed, which is what you want if the detector going down should stop traffic rather than open the
door.
Trust model: the /v1 caller is the operator's authenticated application, not the end user. A
signals value is a statement by your backend, so treat the endpoint accordingly (PRIOR_REQUIRE_AUTH=1
whenever it is reachable beyond localhost).
Response headers (x-prior-*)
Emitted on /v1/chat/completions:
| Header | Meaning |
|---|---|
x-prior-zone |
GREEN / YELLOW / RED; the WHEN-gate decision. |
x-prior-pack |
The winning policy pack. |
x-prior-injections |
Golden-layer steering steps applied (0 = bit-for-bit vanilla). |
x-prior-steering |
enabled / disabled (the license gate). |
x-prior-decision-id |
Correlation id; matches the row in the durable safety audit. |
x-prior-memory |
injected / suppressed / preempted / disabled; set only when ephemeral_memory was sent. suppressed means the call succeeded and the answer does not contain the fact you supplied — branch on it if your application depends on that fact being present. |
The response exposes the decision (zone, winning pack, whether steering engaged) but not the underlying match scores. Raw scores are deliberately kept off the caller-facing surface: exposing them would let a caller probe the exact boundary and map the detection and steering. Scores are retained only in the admin-gated safety audit, for operators tuning their own policies.
POST /v1/completions
Legacy (non-chat) OpenAI completion endpoint, kept for compatibility. New integrations should use
/v1/chat/completions.
System
| Method · Path | Purpose |
|---|---|
GET /health |
Liveness (answers immediately; the model loads lazily). |
GET /v1/models |
The loaded model id. |
GET /metrics |
Prometheus exposition: zone distribution, refusal counts, latency / token / injection histograms. |
Governance: /admin/*
All /admin routes require an Operator or Admin key (an Observer key gets 403). See
Authentication & roles.
Packs & policy
| Method · Path | Purpose |
|---|---|
GET /admin/packs/native |
List loaded native arbiter packs, reporting name, encoder, tier, priority, thresholds, exemplar count, enabled. (Exemplars themselves are never served.) |
POST /admin/packs/reload |
Hot-swap all packs from disk, with no restart. |
PATCH /admin/packs/{pack}/enabled |
Mute / unmute a pack instantly (body: {"enabled": bool}). |
PATCH /admin/packs/{pack}/priority |
Set a pack's arbitration priority (which pack wins when several match). |
POST /admin/packs/ingest |
Prose → calibrated pack. Submit a governance document; PRIOR extracts intents, generates exemplars, calibrates thresholds, and hot-reloads. See Policy & Packs. |
POST /admin/packs/import |
Load a pre-built arbiter pack verbatim, skipping ingest and calibration. For packs you built elsewhere or version-control yourself. |
GET /admin/packs |
List on-disk packs (metadata only). |
Pack authoring (1.1.0)
Author and refine a pack against real evidence instead of guessing at thresholds. These are the API behind the WebUI's pack editor.
| Method · Path | Purpose |
|---|---|
GET / PUT /admin/packs/{pack} |
Read a pack's editable definition (goal, rules, transitions, thresholds) and write it back. |
GET /admin/packs/{pack}/coverage |
Coverage drill-down. Per-probe results: which positives the pack missed and which negatives it fired on — the two lists you actually iterate against. Reports per-rule coverage where rules are defined. |
POST /admin/packs/{pack}/rules/{rule_id}/expand |
Expand one rule into additional exemplars, to lift that rule's coverage without disturbing the others. |
GET / POST /admin/packs/{pack}/examples |
Read and add the pack's exemplars. |
GET / POST /admin/packs/{pack}/dataset |
Manage the pack's test dataset and score the pack against it. |
POST /admin/packs/route-probe |
Score an arbitrary prompt through the live gate and see how it routes, and which pack claims it, without generating a completion. The fastest way to answer "why did this get through?" |
GET /admin/detector |
Detector state: active encoder(s) and their fingerprints. |
A pack's transitions are typed —
refuse,sever,format,ground— so a pack declares what should happen on a match, not just that it matched.
Model & calibration
| Method · Path | Purpose |
|---|---|
GET /admin/model |
Resolved steering params (golden layer, alpha) + tier (certified / beta) + calibration status. |
GET /admin/models/available |
GGUF models present on disk (with sizes). |
POST /admin/calibrate |
Full steering calibration: golden-layer sweep + alpha (GPU). |
POST /admin/calibrate/alpha |
Alpha-only calibration (golden layer fixed). |
POST /admin/calibrate/share |
Optionally submit the calibration payload to the Eagle Logic model registry. |
POST /admin/model/reload |
Hot-reload the model. |
Keys, license, config, runtime
| Method · Path | Purpose |
|---|---|
GET /admin/keys |
List keys (prefix + role + label; never the secret). |
POST /admin/keys |
Create a key; body {"role": "OBSERVER|OPERATOR|ADMIN", "label"?}. Raw key returned once. |
DELETE /admin/keys/{key} |
Revoke a key. |
GET /admin/license/status |
License variant, tier, capabilities, expiry, customer id. |
POST /admin/license/upload |
Upload a license.bin (hot-applied, no restart). |
POST /admin/license/clear |
Remove the active license. |
GET / PATCH /admin/config |
Read / update engine config. |
GET / PATCH /admin/runtime |
Live toggles (no restart): require_auth on /v1, log_level, json_logs, and logits_only (global backward-free steering mode — the path that runs on MoE). GET also reports diagnostics_available. |
GET /admin/logs?tail=N&level=LEVEL |
Tail the in-memory log buffer. |
GET /admin/whoami |
The calling key's role and label — useful for a UI deciding which controls to show. |
GET /admin/stats |
Aggregate engine counters. |
GET /admin/usage |
Per-key usage accounting: request and token tallies by API key. |
GET /admin/activity |
Recent request activity. Prompt and response content is included only when the flag-gated log_content toggle is on — off by default, and it is the one surface that can carry prompt text, so treat it as sensitive. |
Audit
| Method · Path | Purpose |
|---|---|
GET /admin/audit |
Control-plane action log covering config/keys/license/model mutations, with actor + role. |
GET /admin/audit/safety?tail=N&zone=RED&pack=harm_veto |
Durable per-request gate decisions, capturing decision id, zone, pack, score, steered flag, model, prompt hash. Survives restarts. |
There is also a set of low-level triple-store routes (
/admin/triples/*) and an/admin/ui/*static-dashboard mount. The triple editor is a Admin-only advanced/legacy tool; native inference does not read those triples. Most operators drive PRIOR through packs (above) and the separate WebUI.
Authentication & roles
API keys are SHA-256-hashed at rest; the raw secret is shown once at creation and never
stored or re-served. Present a key as Authorization: Bearer <key>. Keys may carry a label and an
optional expiry.
| Role | /v1 inference |
/admin governance |
Typical holder |
|---|---|---|---|
| Observer | ✅ | ❌ (read dashboards only where exposed) | monitoring, dashboards |
| Operator | ✅ | ✅ except global config write / model reload / oracle flush | day-to-day policy ops |
| Admin | ✅ | ✅ full: config write, licensing, calibration, lifecycle | the account owner |
/v1auth is off by default; a fresh engine answers inference without a key. Turn it on withPRIOR_REQUIRE_AUTH=1or live viaPATCH /admin/runtime. Always enable it before exposing the engine off loopback./adminis always authenticated and requires Operator or Admin.- Seed a first Admin key at boot with
PRIOR_API_KEY(env-only, not persisted), then create scoped keys through/admin/keys.
Errors & status codes
| Code | When |
|---|---|
200 |
Success. |
400 |
Malformed request, or a feature used without its prerequisite (e.g. ingest with no extractor configured, which returns a clear message and never a silent localhost dial). |
401 / 403 |
Missing/invalid key, or an Observer key hitting /admin. |
429 |
Per-caller rate limit exceeded on /v1 (token bucket, per API key). |
503 |
Engine still loading the model (readiness). |
Statelessness
The server holds no conversation sessions and no server-side user store. The client re-sends the
full message history (and any ephemeral_memory) each turn. This is what makes horizontal scaling
and air-gap deployment straightforward: any replica can serve any request.
CORS (browser clients)
To call the engine from a browser (e.g. the WebUI on a different origin), set
PRIOR_ALLOWED_ORIGINS to your UI's origin(s). The engine lists Authorization + Content-Type
explicitly in Access-Control-Allow-Headers (a * wildcard does not cover Authorization per
the Fetch spec, so the Bearer key would otherwise be dropped). Restrict origins in production.
See also: Concepts · Policy & Packs · Deployment.