Privacy statement

Draft. This document has not been adopted and is not in force. It is published here so it can be read and reviewed before it is.

Also: Terms · Neutrality

Status: DRAFT. Not adopted. Drafted 2026-09-17 for MODEL-70, against the code as it stood at that date.

This describes what the service does today, not what it is planned to do. Every claim below names the file that makes it true, so it can be checked and so it fails visibly when the code changes. Where something is built but not yet switched on, it is marked not yet live and claims nothing.

The short version

We do not receive your prompts, because the API has no field for them. We do not proxy your model calls, so the content of your inference never reaches us. The rank endpoint keeps no store of any kind: it reads your request, computes an answer, returns it and forgets it. The one thing recorded about your call is recorded by Cloudflare, our infrastructure provider, as platform request logs.

What a request contains

POST https://api.modelspec.dev/v1/rank accepts a profile, not a prompt:

That is the whole surface (api/worker/src/rank_service.py). There is no field for prompt text, document text, user content or an identifier of your end user, so there is nothing of that kind for us to receive, log or store. Widening these fields toward prompt text would be a breach of the commitment in the terms, not a feature release.

A body is capped at 16 KB and larger ones are refused unread past that point.

What we store

Nothing from the content of your request. The endpoints compute each answer from your request, return it and forget the request: no body, no field of it and no answer is written anywhere.

The Worker binds two KV namespaces today (api/worker/wrangler.jsonc), and one Durable Object for prepaid credits that is yours in the sense below. DETERMINATIONS holds our own research — the licence and data-residency determinations the paid tier serves — and the Worker only ever reads from it. There is no code path that writes to it. No D1 database, R2 bucket, queue or analytics dataset is bound.

The API-key store

A second KV namespace, ACCESS, is bound for API keys (MODEL-69). Enforcement is still off: no key is required. Keys can be presented and are checked against the store; none are issued yet (issuance is MODEL-73), so a presented live key is unknown. It holds these kinds of record (api/worker/src/access_keys.py, access_limits.py, access_billing.py):

It holds no prompt, no request body, no field of a rank or policy-check request, no answer, no IP address and no user-agent: our code reads none of those into it. A request that presents no key, or a test_ sandbox key, writes nothing to it at all. Card data never reaches this store: Checkout is hosted on Stripe.

The credit ledger: bound, idle until a flag is on

A Durable Object class CreditsObject, bound as CREDITS (api/worker/wrangler.jsonc), holds prepaid credits (MODEL-75, MODEL-93). X402_ENABLED and BILLING_ENABLED both ship "false", so today no request is charged and nothing is written to it. When either flag is on, it holds these kinds of record (api/worker/src/credits.py):

It holds no prompt, no request body, no field of a request, no ranking or policy answer, no IP address and no user-agent: our code reads none of those into it. A request that does not pay, and a request while both X402_ENABLED and BILLING_ENABLED are off, writes nothing to it.

Workers KV is not this ledger. KV is eventually consistent and has no compare-and-set, so it cannot keep a balance non-negative when two requests race. The Durable Object is the serial mailbox that can.

The only other thing held between requests is a short-lived copy of our own published catalogue, which is public data and contains nothing of yours (api/worker/src/entry.py).

Our own code writes no log line about your request. There is no analytics call, no telemetry beacon and no third-party tag on the API path.

What Cloudflare records

The API and both sites run on Cloudflare, and Cloudflare records request metadata as any host does: the source IP address, timestamp, request method and path, response status, and user-agent. Cloudflare Workers observability is enabled on the rank endpoint (api/worker/wrangler.jsonc), which retains invocation logs — request metadata, outcome and any uncaught error — under Cloudflare's own retention. We use this to tell whether the service is working.

We do not export it, join it to anything else, or use it to build a profile of you. Cloudflare processes it under its own terms as our infrastructure provider.

The websites

modelspec.dev and benchgraph.dev are static pages on Cloudflare Pages.

Inference, and why there is nothing to say about it

We never sit between you and a model. We return a recommendation and hand off; your calls go to the provider, gateway or local runtime directly. We do not see your prompts, your completions, your token counts or your model traffic, and we do not meter, resell or bill any of it. This is an architectural boundary rather than a retention promise: there is no path by which that data could reach us.

The ModelSpec CLI, which runs on your machine, reads which provider API keys are present in your environment and never their values. The keys stay with you.

Not yet live

Named so that this statement can be checked against the code, and so that nothing below is read as describing the service today:

Your requests about your data

Since the service holds nothing that identifies you, there is generally nothing to access, correct, export or delete. If you believe we hold something about you, ask and we will look. Contact details to be filled in before adoption.

Changes

A change to what the service records is a change to this statement, and it is published here before the change ships. The version above is the one in force.