Four families on one address. Two of them are implemented because they are
what every client is already written against; the third is implemented in its
own conventions so a client can be pointed here by changing a URL; the fourth
has no counterpart anywhere and is the point.
The four families
Both mainstream API families are implemented because those are the two every
client already speaks. Ollama's is implemented in its conventions,
not translated into OpenAI's.
OpenAI-compatible
Route
Notes
POST /v1/chat/completions
Streaming with "stream": true, as server-sent events. tools, tool_choice and response_format are all constrained rather than suggested. Tools.
POST /v1/completions
Plain completion.
POST /v1/embeddings
Needs -embed, or an encoder as -m. Supports the base64 encoding_format the official client asks for by default.
GET /v1/models
Every model this server could load, across llamay's store and Ollama's — the same set /api/tags reports. This is what a client populating a model picker reads.
POST /v1/rerank
Needs -rerank. Also at /rerank and /rerank/v1/rerank.
Anthropic-compatible
Route
Notes
POST /v1/messages
The Messages API shape, including tool_use blocks.
Ollama-compatible
Implemented in Ollama's own shapes — newline-delimited JSON rather than
server-sent events, streaming on by default, durations in nanoseconds — so a
client written against it works unchanged.
Route
Notes
POST /api/generate · /api/chat
Generation. format carrying a schema is enforced.
GET /api/tags · POST /api/show
What exists, and what one model is.
GET /api/ps · /api/version
What is resident, and which build this is.
POST /api/pull
Takes {"model": "<source>"} in any form llamay pull accepts, and streams progress in the shape Ollama's clients render. {"stream": false} collapses it to one object. A pulled model is nameable immediately.
POST /api/copy · DELETE /api/delete
Writes to the store. All three write routes are off under -pull=false.
POST /api/embed · /api/embeddings
Encoders.
Three routes are refused, by name, with the reason in the body
POST /api/push — publishing to a registry is a different trust decision from fetching from one.
POST /api/create and POST /api/blobs/{digest} — a Modelfile parser is a separate product from an inference engine, and half of one would misread files rather than refuse them.
llamay's own
Route
Notes
POST /v1/contexts
Create a context, optionally prefilled from prompt or messages. Answers {"id","tokens","pages"}.
GET /v1/contexts
List them.
POST /v1/contexts/{id}/fork?n=
Fork n ways, sharing pages.
GET /v1/contexts/{id}/snapshot
Download it.
POST /v1/contexts/restore
Restore one. Refuses a different model, a bad CRC, a truncated file, and a declared length beyond sixteen million positions — each by its own sentinel.
DELETE /v1/contexts/{id}
Release it.
Health, stats and metrics
Route
Notes
GET /healthz
{"status":"ok","model":…,"id":…} — identity, not just liveness, and the same three fields whether the server is holding a decoder, an encoder or a cross-encoder. model is a name a request can carry, not the display string inside the file. The one route an API key is not required on, because the thing reading it is usually a container probe with no way to carry a secret.
GET /v1/stats
The scheduler's counters as JSON.
GET /metrics
Prometheus.
llamay's extensions
Namespaced, so a client that does not know them is unaffected. They may be
set on any generation request in any of the three families.
Generate inside a named context rather than a fresh one.
llamay_format: "json"
Any valid JSON. The weaker guarantee.
llamay_schema
The full schema constraint, same machinery as response_format.
llamay_lexicon
Constrain decoding to a word list.
llamay_retain_prefix
Keep this prompt's prefix in the radix tree after the request ends.
Responses report llamay_cached_prompt_tokens alongside the usual
usage — the number that says whether the prefix cache is earning its memory.
Authentication and errors
LLAMAY_API_KEY, or -api-key, is required on every route but /healthz.
A full queue answers 429 immediately rather than accepting work it cannot hold.
A route that exists but has not been given the model it needs — /v1/embeddings with no encoder, say — refuses by name rather than answering 404.
A server with an empty store answers 503 on the generation routes, with the pull command in the body. A client that retries on 503 starts working the moment a model lands.
Traces join the caller's traceparent when -otlp is set.