Provenance

Self-hosted sidecar (Enterprise)

If your model runs on your own GPUs, you don't have to route prompts through ours. Run the trace worker beside your model; it reads the canary neurons locally, signs the readings with a key you hold, and sends Provenance only the readings and a prompt hash. Your canary policies then read them with canary_source: "sidecar".

1. Generate a key — keep the private half

openssl ecparam -name prime256v1 -genkey -noout -out sidecar.key.pem
openssl ec -in sidecar.key.pem -pubout -out sidecar.pub.pem

2. Register the public half

curl $API/v1/trace/worker-keys -H "Authorization: Bearer $PRV_ENTERPRISE_KEY" -H "Content-Type: application/json" \
  -d "{\"name\":\"gpu-pod-eu-1\",\"public_key_pem\":$(jq -Rs . sidecar.pub.pem)}"
# → 201 {"worker_key_id":"wk_…", …}

Only EC P-256 public keys are accepted (400 otherwise). Revoke with DELETE /v1/trace/worker-keys/wk_… — readings signed by a revoked key are rejected from then on. The dashboard's Trace → Sidecar keys page does the same.

3. Run the worker in sidecar mode

TRACE_WORKER_BACKEND=hf TRACE_MODEL=<your HF model> \
TRACE_SIDECAR=1 TRACE_SIGNING_KEY_PEM="$(cat sidecar.key.pem)" TRACE_SIGNING_KEY_ID=wk_… \
PROVENANCE_API_URL=$API TRACE_WORKER_TOKEN=… \
  provenance-trace-worker serve --port 8090

Your agent (or gateway) calls the worker before acting:

curl localhost:8090/v1/sidecar/read -H "Authorization: Bearer $TRACE_WORKER_TOKEN" -H "Content-Type: application/json" \
  -d '{"model_version_id":"…","messages":[…],"canary_sets":[…]}'
# → {"trace_id":"trc_…","readings":{…},"posted":{"canary_hash":"…"}}

then passes that trace_id to POST /v1/intent/verify (or authorize). The model must be registered — a registry build of your model, with your canary sets.

Stop your model during generation

Add kill_switch (and the generation settings) to /v1/sidecar/read, and the worker generates the completion itself, checking the canaries on every token. Your model stops on the step a family reaches its threshold, on your hardware.

curl localhost:8090/v1/sidecar/read -H "Authorization: Bearer $TRACE_WORKER_TOKEN" -H "Content-Type: application/json" \
  -d '{"model_version_id":"…","messages":[…],"canary_sets":[…],
       "kill_switch":{"mode":"block","thresholds":{"prompt_injection":0.8}},"max_tokens":256,"temperature":0}'
# → {"trace_id":"trc_…","completion":"…","finish_reason":"canary_tripped","completion_tokens":31,
#    "trip":{"family":"prompt_injection","phase":"generation","token_index":30,"score":0.84},
#    "readings":{…},"generation_readings":{…},"posted":{"canary_hash":"…","trip":{…}}}

The completion stays with you. The signed reading adds a trip claim when a family tripped, and Provenance stores it with the signed token. flag records the trip point and lets the model finish. See Stop during generation for the fields.

The reading format

POST /v1/trace/readings {"token": "<JWS>"} — no API key; the signature authenticates it.

| Header | Claims | | --- | --- | | alg: ES256, typ: provenance-trace-reading+jwt, kid: wk_… | trace_id (trc_ + 32 hex, yours to mint), model_version_id, prompt_hash (sha256 of canonical {model, messages}), readings ({family: {score, tripped, threshold}}), iat, and trip ({family, phase, token_index, score}) only when the in-model kill switch fired |

What a sidecar reading proves

That a key you registered signed these readings for this prompt hash at about this time. It cannot prove which hardware or which weights produced them — that trust is yours, by construction, because you run the model. Prompts and completions never reach Provenance.