Configure an embedding provider
Four lines of a specification decide where your corpus goes. This page is what each of them means, and how to find out whether they are right before anything is sent.
The four lines
Section titled “The four lines”model: provider: openai-compatible endpoint_class: local # local | hosted | gateway endpoint: http://localhost:11434/v1 identifier: bge-small-en revision: "sha256:..." # where the provider exposes one credential: env:PTAH_EMBED_TOKEN reported_dimension: 384 normalization: noneprovider names the adapter, and there is one: openai-compatible, meaning a
POST /v1/embeddings that answers in the OpenAI shape. An endpoint that speaks
something else needs a gateway in front of it.
endpoint_class is your statement, not a measurement. Ptah cannot tell from
an address who operates it. The class is carried into the plan and into the
generation identity, so moving a corpus from a local endpoint to a hosted one is
a different generation rather than a quiet change of who has your text.
identifier and revision are the model. Where the provider exposes an
immutable revision, name it: without one the generation is reported as
partially reproducible, with the reason, because asking the same provider
again may answer with different vectors and Ptah cannot see that it did.
A local endpoint is a first-class case
Section titled “A local endpoint is a first-class case”Nothing here needs a hosted provider, a Ptah account, or an outbound connection.
An endpoint on localhost with no credential is a complete configuration, and
it is the one to reach for when the text must not leave the machine.
Leave credential out entirely in that case. An empty reference means no
Authorization header rather than an empty one.
The credential is a reference
Section titled “The credential is a reference”credential: env:PTAH_EMBED_TOKEN # an environment variablecredential: file:/run/secrets/token # a file, read at the moment of useTwo schemes: env and file. Either names where the value is, and the value
is read at the moment of each request and not kept. What Ptah records — in the
plan, in the run’s own tables, in published evidence, in what an agent can see —
is the reference.
That is what makes a specification a file you can commit.
A file: reference is refused when the filesystem lets anyone but the owner read
it, where the platform can answer that question. A token in a world-readable
file is a token every process on the host has.
Measure it before you send anything
Section titled “Measure it before you send anything”ptah inference probe --spec spec.yamlbge-small-en at localhost:11434, declared local - ok reachable: the endpoint at localhost:11434 answered - ok authorized: no credential was sent, and the endpoint asked for none - ok embeds: model bge-small-en answered an embedding request - ok shape: one vector of 384 finite values for one input - ok dimension: 384 dimensions, as declared - ok batch: 2 inputs answered with 2 vectors - ok cancellation: a canceled request stopped rather than answering - ok error shape: a refused request arrived as a classified error the engine can act onTwo fixed strings go out and nothing from your database does, so this is runnable — and its output shareable — before anybody has decided to send a corpus anywhere. It opens no database either, which is what lets a CI job run it against a specification somebody is still writing.
It returns 1 when a check fails.
A check the probe could not make is reported as unmeasured rather than as a pass. That distinction is the whole value of the verb: a credential that does not resolve — an unset variable, a missing file, one the filesystem lets other users read — is refused before a single byte leaves the process, so the probe says the credential could not be used and that reachability was not measured:
bge-small-en at api.example.com, declared hosted - fail authorized: the credential from env:PTAH_EMBED_TOKEN could not be used: credential reference resolves to nothing: environment variable PTAH_EMBED_TOKEN is unset or empty - not measured: whether the endpoint at api.example.com is reachable, and everything after it, because no request was sentNothing was asked of the endpoint, so nothing is claimed about it.
What each answer is for
Section titled “What each answer is for”dimension is the one that used to be found late. Every fact a plan states
about a provider is configured rather than measured, so before this verb the
first thing that compared reported_dimension with what the endpoint answers was
the backfill — which had already sent rows by then.
cancellation decides what an interrupted backfill costs. A provider that
answers a canceled request turns your Ctrl-C into a wait, and the bill keeps
running.
error shape is what the engine acts on. Retry, stop, fail the batch: every
one of those decisions reads a classified error, and a refusal that arrives as
whatever the endpoint wrote is one the engine cannot act on correctly.
A check that could not run is named rather than reported as passing. An unreachable endpoint reports the reachability check and says everything after it was not measured.
There is no fallback
Section titled “There is no fallback”If the endpoint you named fails, Ptah does not try another one. It could not do so safely: a different provider is a different generation identity and a different privacy boundary, and choosing one for you would send your text somewhere you did not authorize while producing vectors that are not comparable with the ones already stored.
A failed backfill stops and resumes from its checkpoint when the endpoint is back.
What Ptah cannot tell you
Section titled “What Ptah cannot tell you”Whether the provider retains what you send it. That is a contract question with them, and nothing here claims an answer.
See Security and data boundaries for what leaves the database, and Plan provider capacity for sizing the run against rate limits and cost.