TTTPS Proof-of-Time ASGI middleware for vLLM: cryptographic audit-trail timestamps for OpenAI-compatible completions via the public KPP Provenance API
Project description
vllm-openttt
TTTPS Proof-of-Time ASGI middleware for vLLM.
Attaches a cryptographic audit-trail timestamp (a signed Proof-of-Time receipt) to
every non-streaming /v1/chat/completions and /v1/completions response served by
vLLM's OpenAI-compatible server, sealed against the public self-serve
KPP Provenance API.
This attaches a cryptographic audit-trail timestamp and integrity hash. It does not certify legal or regulatory compliance (EU AI Act, FDA, and so on). Treat it as an audit-trail timestamp, not a compliance claim.
Install
pip install vllm-openttt
vLLM itself is not a dependency of this package. The middleware only needs the ASGI contract, so it installs next to whatever vLLM version you already run.
Usage
Mint a free key with POST https://kpp.kenosian.com/v1/keys, export it, and pass
the middleware to vllm serve:
export KPP_API_KEY=...
vllm serve Qwen/Qwen2.5-0.5B-Instruct \
--middleware vllm_openttt.TTTPSMiddleware
vLLM imports the dotted path and, because it resolves to a class, registers it with
app.add_middleware(). Every sealed response then carries two extra headers:
X-TTTPS-Status: ok
X-TTTPS-Receipt: {"status":"ok","backend":"kpp","content_hash":"sha256:...",
"receipt_id":"...","receipt":"...","time":"...",
"time_source":"...","verify_url":"https://kpp.kenosian.com/v1/verify?receipt_id=...",
"overhead_ms":...}
Reading the receipt from a client:
import json, requests
r = requests.post(
"http://127.0.0.1:8000/v1/chat/completions",
json={"model": "Qwen/Qwen2.5-0.5B-Instruct",
"messages": [{"role": "user", "content": "hi"}]},
)
receipt = json.loads(r.headers["X-TTTPS-Receipt"])
print(receipt["receipt_id"], receipt["verify_url"])
A receipt can be re-checked at any time via POST https://kpp.kenosian.com/v1/verify
with {"receipt_id": ...}.
Configuration
| Variable | Default | Meaning |
|---|---|---|
KPP_API_KEY |
empty | Provenance key from POST /v1/keys |
KPP_BASE |
https://kpp.kenosian.com |
Provenance API base URL |
TTTPS_TIMEOUT_S |
1.0 |
Fail-open deadline for the anchor call |
TTTPS_BACKEND |
kpp |
kpp, or openttt for a self-hosted server |
TTTPS_POT_BASE |
empty | Base URL of your OpenTTT server, when TTTPS_BACKEND=openttt |
TTTPS_API_KEY |
empty | API key for that OpenTTT server |
Self-hosted backend
Setting TTTPS_BACKEND=openttt mints receipts on your own
OpenTTT server instead of the public
API, which additionally chains each event into that server's hash chain and keeps
every anchor inside your own infrastructure.
OpenTelemetry
If a request carries a W3C traceparent header, the trace and span ids are parsed
and echoed back in the receipt, so a trace and a receipt point at each other. On the
self-hosted backend the ids are also written into the signed Proof-of-Time hash
preimage and into the server's queryable event description.
receipt_to_span_attributes() maps a receipt onto span attribute names:
from vllm_openttt import receipt_to_span_attributes
span.set_attributes(receipt_to_span_attributes(receipt))
# {"tttps.receipt_id": "...", "tttps.content_hash": "...", "tttps.trace_id": "...", ...}
Parsing prefers vLLM's own vllm.tracing.extract_trace_context() when running inside
a vLLM process, and falls back to a dependency-free W3C parser otherwise. No extra
dependency is added either way.
Fail-open
A missing key, an unreachable or slow backend, a malformed traceparent, or any
unexpected error degrades the receipt to {"status": "degraded", "reason": ...}.
The response body, status code and media type are never altered, and no exception
ever escapes the middleware.
Scope
Streaming responses (stream: true, server-sent events) are passed through
untouched. Sealing a live event stream needs a different approach and is not
attempted here.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vllm_openttt-0.1.0.tar.gz.
File metadata
- Download URL: vllm_openttt-0.1.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
edd037b1e0723fbddf213452dedc6a9b8db2d8e2ab81e76d28606cd8811a7e0a
|
|
| MD5 |
70d778469e8ba77d0df0849770cc3337
|
|
| BLAKE2b-256 |
79bc836c4b9623d322b468527455fa1c513831eeb31c7e968c980de5c5e33602
|
File details
Details for the file vllm_openttt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: vllm_openttt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0ffa6958f3a076a3293d689d4abef9967b00e2101f40d577f92f15f7d28a8d5
|
|
| MD5 |
73a50d5fe33f53a619306b3d85b6c7bf
|
|
| BLAKE2b-256 |
c4a320379f8e49e3ccb30e8ffc92ba6d442414b4b7f0fc14fd18837d17ec7784
|