Files
llmgw/docs/admin-api.openapi.json
T
Ilker ManapandClaude Opus 5.5 d41104a452 Merge C21 quality suites and gating
Conflicts: docs.go (manual, OpenAPI and suites all kept), modelserve Job
(trace and eval both kept). The eval routes are added to the OpenAPI route
table, update and promote documented with their optional body, and the
document regenerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 00:08:33 +02:00

6723 lines
197 KiB
JSON

{
"openapi": "3.1.0",
"info": {
"title": "llmgw admin API",
"version": "v1",
"description": "The control plane's management API: what `llmgw ctl` and the console use.\n\nIt is served on the admin listener (admin_listen, 127.0.0.1:9090 by default), which stays on loopback unless admin_remote is set: reach it from elsewhere through an SSH tunnel. Every path under /api needs the admin token as a bearer token.\n\nThe listener also refuses, before the token is looked at: a Host header that is a name rather than an address or localhost; a request another site's page sent; and any method but GET and HEAD whose Content-Type is not application/json, even one with no body.\n\nDurations in bodies are integer nanoseconds, as Go encodes them. Generated from the route table in internal/control/adminapi; see docs/admin-api.md."
},
"servers": [
{
"url": "http://127.0.0.1:9090",
"description": "The admin listener at its default address, admin_listen."
}
],
"security": [
{
"adminToken": []
}
],
"tags": [
{
"name": "audit"
},
{
"name": "canaries"
},
{
"name": "capacity"
},
{
"name": "eval"
},
{
"name": "explain-placement"
},
{
"name": "fabric-test"
},
{
"name": "fabrics"
},
{
"name": "guard"
},
{
"name": "jobs"
},
{
"name": "metrics"
},
{
"name": "models"
},
{
"name": "nodes"
},
{
"name": "notify"
},
{
"name": "nvlink"
},
{
"name": "openapi"
},
{
"name": "plan"
},
{
"name": "quotas"
},
{
"name": "replicas"
},
{
"name": "requests"
},
{
"name": "restart"
},
{
"name": "summary"
},
{
"name": "updates"
},
{
"name": "usage"
},
{
"name": "weights"
}
],
"paths": {
"/api/v1/audit": {
"get": {
"operationId": "getAudit",
"summary": "Changes made, newest first",
"tags": [
"audit"
],
"parameters": [
{
"name": "since",
"in": "query",
"description": "How far back: 90m, 24h, 7d; 7d when absent.",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "The most events to answer with.",
"schema": {
"type": "integer"
}
},
{
"name": "actor",
"in": "query",
"description": "Only changes by this actor.",
"schema": {
"type": "string"
}
},
{
"name": "contains",
"in": "query",
"description": "Only events whose action or target contains this.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/store.AuditEvent"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/canaries": {
"get": {
"operationId": "getCanaries",
"summary": "Every canary, and how its two sides serve",
"tags": [
"canaries"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.CanaryView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/capacity": {
"get": {
"operationId": "getCapacity",
"summary": "Every recorded measurement",
"tags": [
"capacity"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CapacityView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/eval/runs": {
"get": {
"operationId": "getEvalRuns",
"summary": "Quality runs, the newest first",
"tags": [
"eval"
],
"parameters": [
{
"name": "model",
"in": "query",
"description": "Only this model's runs.",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "How many; a sensible number when absent.",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/eval.Live"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/eval/runs/{id}": {
"get": {
"operationId": "getEvalRunsId",
"summary": "One quality run, with each case",
"tags": [
"eval"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The quality run's ID, as starting it answered.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/eval.Live"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/eval/suites": {
"get": {
"operationId": "getEvalSuites",
"summary": "The quality suites the control plane can run by name",
"tags": [
"eval"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/eval.SuiteInfo"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/explain-placement": {
"get": {
"operationId": "getExplainPlacement",
"summary": "Why a model could not be placed",
"tags": [
"explain-placement"
],
"parameters": [
{
"name": "model",
"in": "query",
"required": true,
"description": "The model's name or an alias.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExplainView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/fabric-test": {
"post": {
"operationId": "postFabricTest",
"summary": "Measure bandwidth between two nodes, rail by rail",
"tags": [
"fabric-test"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FabricTestRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FabricTestView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/fabrics": {
"get": {
"operationId": "getFabrics",
"summary": "The physical fabrics and the names nodes give them",
"tags": [
"fabrics"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/fabrics.Report"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/fabrics/{id}/topology": {
"get": {
"operationId": "getFabricsIdTopology",
"summary": "One fabric's map, with the cluster's adapters live on it",
"tags": [
"fabrics"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The physical fabric's ID, as GET /api/v1/fabrics lists it.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TopologyView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/guard": {
"get": {
"operationId": "getGuard",
"summary": "The guardrail policies and where they are attached",
"tags": [
"guard"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GuardView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/guard/attachments": {
"post": {
"operationId": "postGuardAttachments",
"summary": "Attach a guardrail policy",
"tags": [
"guard"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GuardAttachmentRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/guard.Attachment"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"delete": {
"operationId": "deleteGuardAttachments",
"summary": "Detach a guardrail policy",
"tags": [
"guard"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GuardAttachmentRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/guard.Attachment"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/jobs": {
"get": {
"operationId": "getJobs",
"summary": "Every job since the control plane started",
"tags": [
"jobs"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/jobs/{id}": {
"get": {
"operationId": "getJobsId",
"summary": "One job",
"tags": [
"jobs"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The job's ID, as starting it answered.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/metrics/range": {
"post": {
"operationId": "postMetricsRange",
"summary": "Several Prometheus range queries at once",
"description": "Read from the Prometheus monitoring.prometheus names; configured is false without one.",
"tags": [
"metrics"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MetricsRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MetricsResult"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models": {
"get": {
"operationId": "getModels",
"summary": "Every model, with its replicas and state",
"tags": [
"models"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ModelView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"post": {
"operationId": "postModels",
"summary": "Add a model to the catalog",
"description": "Kept in the store across restarts. Refused when the name is taken, a model in configuration has it, or the definition would make the catalog invalid.",
"tags": [
"models"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/catalog.Model"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModelAdded"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/serve": {
"post": {
"operationId": "postModelsServe",
"summary": "Fetch a registry repository and serve it",
"tags": [
"models"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Request"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}": {
"get": {
"operationId": "getModelsName",
"summary": "One model's definition, as it is in force",
"description": "With the defaults the catalog filled in. By its name only, not an alias.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/catalog.Model"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"delete": {
"operationId": "deleteModelsName",
"summary": "Remove a model added at runtime",
"description": "A model declared in configuration is refused: it would come back on the next restart.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Removed"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/adapters": {
"post": {
"operationId": "postModelsNameAdapters",
"summary": "Replace a model's LoRA adapters",
"description": "Each new file is read first, to check it is an adapter for the model's architecture.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdaptersRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdaptersRequest"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/canary": {
"post": {
"operationId": "postModelsNameCanary",
"summary": "Start a canary of a model's newer weights",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/catalog.Canary"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"put": {
"operationId": "putModelsNameCanary",
"summary": "Change the share of requests a canary takes",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CanaryPercentRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Result"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"delete": {
"operationId": "deleteModelsNameCanary",
"summary": "Take a canary out: its share first, then the candidate",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Result"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/capacity": {
"put": {
"operationId": "putModelsNameCapacity",
"summary": "Record what a replica was measured to serve",
"description": "Replaces an earlier measurement of the same model on the same profile.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/bench.Capacity"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/bench.Capacity"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/class": {
"post": {
"operationId": "postModelsNameClass",
"summary": "Set a model's capacity class",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ClassRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ClassView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/eval": {
"post": {
"operationId": "postModelsNameEval",
"summary": "Ask a model a quality suite",
"description": "Started at once and answered with the run, to be followed at /api/v1/eval/runs/{id}.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/eval.Request"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/eval.Live"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/eval-gate": {
"put": {
"operationId": "putModelsNameEvalGate",
"summary": "Hold a model's updates and promotions to a quality suite",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EvalGateRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EvalGateView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"delete": {
"operationId": "deleteModelsNameEvalGate",
"summary": "Stop holding a model's updates to a suite",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EvalGateView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/headroom": {
"get": {
"operationId": "getModelsNameHeadroom",
"summary": "How many more replicas of a model fit now, and where",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "The most to try placing; 16 when absent or past 64.",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HeadroomView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/origin": {
"post": {
"operationId": "postModelsNameOrigin",
"summary": "Record the repository a model's weights came from",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OriginRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OriginView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/owner": {
"post": {
"operationId": "postModelsNameOwner",
"summary": "Set the part of the tenancy tree a model's capacity counts against",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OwnerRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OwnerView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/promote": {
"post": {
"operationId": "postModelsNamePromote",
"summary": "Make a canary's weights the model's",
"description": "With a quality suite, or the model's standing gate, the canary is asked it first and kept below the score.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Change"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/resources": {
"post": {
"operationId": "postModelsNameResources",
"summary": "Set what a model's profiles reserve of a node",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResourcesRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/catalog.Model"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/retry": {
"post": {
"operationId": "postModelsNameRetry",
"summary": "Try a parked model again",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RetryView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/rollback": {
"post": {
"operationId": "postModelsNameRollback",
"summary": "Go back to the weights the last update replaced",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Result"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/scale": {
"post": {
"operationId": "postModelsNameScale",
"summary": "Set how many replicas a model runs",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ScaleRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ScaleResponse"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/target": {
"get": {
"operationId": "getModelsNameTarget",
"summary": "How many replicas a throughput needs, and whether they fit",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"name": "tokens_per_sec",
"in": "query",
"required": true,
"description": "The output tokens a second wanted of the model.",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TargetView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/models/{name}/update": {
"post": {
"operationId": "postModelsNameUpdate",
"summary": "Move a model to its repository's newer weights",
"description": "With a quality suite, or the model's standing gate, the new weights are asked it first as a hidden canary.",
"tags": [
"models"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "The model's name in the catalog.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Change"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Job"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes": {
"get": {
"operationId": "getNodes",
"summary": "Every node, with its cards, load and fabrics",
"tags": [
"nodes"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/NodeView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes/{id}": {
"delete": {
"operationId": "deleteNodesId",
"summary": "Forget a node that has gone",
"description": "Only a node that is lost, or unreachable with nothing on it; its certificate is revoked.",
"tags": [
"nodes"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The node's ID, as `llmgw ctl nodes` lists it.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeRemoved"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes/{id}/engines": {
"post": {
"operationId": "postNodesIdEngines",
"summary": "Choose an engine's build for a node",
"description": "The node installs the build chosen. Build is auto, a build such as cu129, or none.",
"tags": [
"nodes"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The node's ID, as `llmgw ctl nodes` lists it.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeEngineRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeEngineRequest"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes/{id}/logs": {
"get": {
"operationId": "getNodesIdLogs",
"summary": "The last lines of a node's logs",
"tags": [
"nodes"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The node's ID, as `llmgw ctl nodes` lists it.",
"schema": {
"type": "string"
}
},
{
"name": "lines",
"in": "query",
"description": "How many lines; 300 when absent, at most 2000.",
"schema": {
"type": "integer"
}
},
{
"name": "source",
"in": "query",
"description": "Which log: agent when absent, or an engine the node lists in sources.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LogsView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes/{id}/state": {
"post": {
"operationId": "postNodesIdState",
"summary": "Cordon, drain or ready a node",
"tags": [
"nodes"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The node's ID, as `llmgw ctl nodes` lists it.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeStateRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NodeStateView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nodes/{id}/upgrade": {
"post": {
"operationId": "postNodesIdUpgrade",
"summary": "Have a node run a release",
"tags": [
"nodes"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The node's ID, as `llmgw ctl nodes` lists it.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpgradeRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpgradeView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/notify/test": {
"post": {
"operationId": "postNotifyTest",
"summary": "Send a test notification to every webhook",
"tags": [
"notify"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/notify.Result"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/nvlink": {
"get": {
"operationId": "getNvlink",
"summary": "The multi-node NVLink domains and what keeps nodes out of them",
"tags": [
"nvlink"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/nvlink.Report"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/openapi.json": {
"get": {
"operationId": "getOpenapiJson",
"summary": "This document",
"description": "The admin API in OpenAPI 3.1, generated from the route table and built into the binary.",
"tags": [
"openapi"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/plan": {
"get": {
"operationId": "getPlan",
"summary": "How a registry repository would be served here",
"tags": [
"plan"
],
"parameters": [
{
"name": "repo",
"in": "query",
"required": true,
"description": "The repository, owner/name.",
"schema": {
"type": "string"
}
},
{
"name": "format",
"in": "query",
"description": "gguf or safetensors; gguf when absent.",
"schema": {
"type": "string"
}
},
{
"name": "context",
"in": "query",
"description": "The context length to plan for, in tokens.",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/modelserve.Plan"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/quotas": {
"get": {
"operationId": "getQuotas",
"summary": "Every capacity quota, with what its scope holds now",
"tags": [
"quotas"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/QuotaView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
},
"put": {
"operationId": "putQuotas",
"summary": "Set a scope's capacity quota",
"description": "Replaces the scope's quota whole. The scope may be named by path or by ID; the answer names it by ID.",
"tags": [
"quotas"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QuotaRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QuotaSet"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/quotas/{scope}": {
"delete": {
"operationId": "deleteQuotasScope",
"summary": "Remove a scope's capacity quota",
"tags": [
"quotas"
],
"parameters": [
{
"name": "scope",
"in": "path",
"required": true,
"description": "The scope: org:NAME, team:ORG/TEAM, project:ORG/TEAM/PROJECT, or their IDs after the colon.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Removed"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/replicas": {
"get": {
"operationId": "getReplicas",
"summary": "Every replica, with its shards",
"tags": [
"replicas"
],
"parameters": [
{
"name": "model",
"in": "query",
"description": "Only this model's replicas.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ReplicaView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/requests/{id}": {
"get": {
"operationId": "getRequestsId",
"summary": "What one request went through",
"tags": [
"requests"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The request's ID: the x-request-id a client was answered with.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/requests/{id}/body": {
"get": {
"operationId": "getRequestsIdBody",
"summary": "A kept request and its answer",
"tags": [
"requests"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The request's ID: the x-request-id a client was answered with.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/store.RequestBody"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/requests/{id}/replay": {
"post": {
"operationId": "postRequestsIdReplay",
"summary": "Send a kept request again, to any model",
"tags": [
"requests"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The request's ID: the x-request-id a client was answered with.",
"schema": {
"type": "string"
}
},
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReplayRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReplayView"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/restart": {
"post": {
"operationId": "postRestart",
"summary": "Restart replicas, every replica of some models, or all",
"tags": [
"restart"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RestartRequest"
}
}
}
},
"responses": {
"202": {
"description": "Accepted: started, and running on.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RestartResult"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/summary": {
"get": {
"operationId": "getSummary",
"summary": "The whole fleet in one answer",
"tags": [
"summary"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Summary"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/updates": {
"get": {
"operationId": "getUpdates",
"summary": "Newer weights the registry has for models",
"tags": [
"updates"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.UpdateInfo"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/updates/check": {
"post": {
"operationId": "postUpdatesCheck",
"summary": "Ask the registry now, about one model or every one",
"tags": [
"updates"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CheckRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.UpdateInfo"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/usage": {
"get": {
"operationId": "getUsage",
"summary": "What each group of the tenancy tree spent",
"tags": [
"usage"
],
"parameters": [
{
"name": "by",
"in": "query",
"description": "org, team or project; team when absent.",
"schema": {
"type": "string"
}
},
{
"name": "since",
"in": "query",
"description": "A duration back from now, like 24h; 24h when absent.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ScopeUsageView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/usage/export": {
"get": {
"operationId": "getUsageExport",
"summary": "Usage totals by period and dimension, as CSV or JSON",
"tags": [
"usage"
],
"parameters": [
{
"name": "from",
"in": "query",
"description": "A date (2026-09-01) or an RFC 3339 time; the first of this month when absent.",
"schema": {
"type": "string"
}
},
{
"name": "to",
"in": "query",
"description": "A date or an RFC 3339 time; now when absent.",
"schema": {
"type": "string"
}
},
{
"name": "period",
"in": "query",
"description": "hour, day or month; day when absent.",
"schema": {
"type": "string"
}
},
{
"name": "by",
"in": "query",
"description": "Dimensions, comma-separated: org, team, project, user, key, model.",
"schema": {
"type": "string"
}
},
{
"name": "format",
"in": "query",
"description": "json for JSON; CSV otherwise.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/store.ExportRow"
}
}
},
"text/csv": {
"schema": {
"type": "string"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/weights/collect": {
"post": {
"operationId": "postWeightsCollect",
"summary": "Delete weights that no model uses",
"tags": [
"weights"
],
"parameters": [
{
"$ref": "#/components/parameters/Actor"
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CollectRequest"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CollectResult"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/weights/orphans": {
"get": {
"operationId": "getWeightsOrphans",
"summary": "Weights on nodes that no model uses",
"tags": [
"weights"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/OrphanView"
}
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"default": {
"$ref": "#/components/responses/Error"
}
}
}
}
},
"components": {
"securitySchemes": {
"adminToken": {
"type": "http",
"scheme": "bearer",
"description": "The admin token: the contents of /var/lib/llmgw/admin-token on the control plane (admin_token_file), readable by root and the server. Sent as Authorization: Bearer TOKEN."
}
},
"parameters": {
"Actor": {
"name": "X-Llmgw-Actor",
"in": "header",
"required": false,
"description": "Who the change is recorded as made by in the audit log: letters, digits and ._-@, at most 64. unknown when absent.",
"schema": {
"type": "string"
}
}
},
"responses": {
"Error": {
"description": "Refused: the error says why.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorView"
}
}
}
},
"Unauthorized": {
"description": "The admin token is missing or wrong.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorView"
}
}
}
}
},
"schemas": {
"AdaptersRequest": {
"type": "object",
"description": "AdaptersRequest replaces a model's LoRA adapters with these.",
"properties": {
"adapters": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.Adapter"
}
}
}
},
"CanaryPercentRequest": {
"type": "object",
"description": "CanaryPercentRequest changes the share of a model's requests its canary takes.",
"properties": {
"percent": {
"type": "integer"
}
}
},
"CapacityView": {
"type": "object",
"description": "CapacityView is one stored measurement, with who recorded it.",
"properties": {
"model": {
"type": "string"
},
"profile": {
"type": "string"
},
"max_concurrency_at_slo": {
"type": "integer",
"description": "MaxConcurrencyAtSLO is the capacity: the highest concurrency that still met the target. Zero means even one request did not, which is a real result and not a missing one — it says this hardware cannot serve this model at this SLO at all."
},
"throughput_tok_per_sec": {
"type": "number",
"description": "ThroughputTokPerSec and the latencies are taken at that level, not at the peak. Peak throughput arrives long after latency has become unusable, so reporting it would overstate what the hardware can serve."
},
"ttft_p99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"tpot_p99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"suggested_target_waiting": {
"type": "integer",
"description": "SuggestedTargetWaiting and SuggestedKVCeiling are the queue depth and cache pressure seen while the SLO was still being met, which is what admission should treat as healthy for this model. Admission currently applies one global default to every model; these are the per-model numbers it should be using instead."
},
"suggested_kv_ceiling": {
"type": "number"
},
"slo": {
"$ref": "#/components/schemas/bench.SLO",
"description": "SLO is recorded because capacity is meaningless without it. The same replica has a different capacity against a 200ms first-token target than against a 2s one, and a number stored without the target it was measured against cannot be compared with anything."
},
"target": {
"type": "string",
"description": "Target is the endpoint the load actually went to, kept so a profile measured against the gateway is never mistaken for one measured against a replica. Only the second says anything about the hardware."
},
"measured_at": {
"type": "string",
"format": "date-time"
},
"measured_by": {
"type": "string"
}
}
},
"CheckRequest": {
"type": "object",
"description": "CheckRequest asks the registry about one model now, or every one.",
"properties": {
"model": {
"type": "string"
}
}
},
"ClassGPUs": {
"type": "object",
"description": "ClassGPUs is how many of a node's devices are of one class, and how many of those are free or kept out of placement.",
"properties": {
"class": {
"type": "string"
},
"total": {
"type": "integer"
},
"free": {
"type": "integer"
},
"unhealthy": {
"type": "integer"
},
"mig": {
"type": "boolean",
"description": "MIG marks a class of MIG instances, each of which takes a replica of its own and never joins a tensor-parallel group."
}
}
},
"ClassRequest": {
"type": "object",
"description": "ClassRequest sets a model's capacity class: critical, standard or opportunistic, or empty to go back to what its scaling implies.",
"properties": {
"class": {
"type": "string"
}
}
},
"ClassUse": {
"type": "object",
"description": "ClassUse is how much of one kind of card is in use.",
"properties": {
"class": {
"type": "string"
},
"total": {
"type": "integer"
},
"used": {
"type": "integer"
},
"unhealthy": {
"type": "integer",
"description": "Unhealthy GPUs are neither used nor available, and counting them as free is how a cluster looks like it has room it does not have."
}
}
},
"ClassView": {
"type": "object",
"description": "ClassView is a model's capacity class now.",
"properties": {
"model": {
"type": "string"
},
"class": {
"type": "string"
}
}
},
"CollectRequest": {
"type": "object",
"description": "CollectRequest limits a sweep to one node. Empty means every node, which is the common case after removing a model from the catalog.",
"properties": {
"node": {
"type": "string"
}
}
},
"CollectResult": {
"type": "object",
"description": "CollectResult is what was deleted on one node, or why nothing was.",
"properties": {
"node": {
"type": "string"
},
"files": {
"type": "integer"
},
"bytes": {
"type": "integer",
"format": "int64"
},
"error": {
"type": "string"
}
}
},
"ErrorView": {
"type": "object",
"description": "ErrorView is every refusal: a 4xx or 5xx status with what went wrong.",
"properties": {
"error": {
"type": "string"
}
}
},
"EvalGateRequest": {
"type": "object",
"description": "EvalGateRequest sets a model's standing quality suite; an empty suite takes it away.",
"properties": {
"suite": {
"type": "string"
},
"min_score": {
"type": "number"
},
"judge": {
"type": "string"
}
}
},
"EvalGateView": {
"type": "object",
"description": "EvalGateView is a model's standing quality gate, as it is now; Eval is absent when it has none.",
"properties": {
"model": {
"type": "string"
},
"eval": {
"$ref": "#/components/schemas/catalog.EvalGate"
}
}
},
"ExplainView": {
"type": "object",
"description": "ExplainView is why a model could not be placed.",
"properties": {
"model": {
"type": "string"
},
"placed": {
"type": "boolean",
"description": "Placed is true when the model has replicas, in which case there is nothing to explain."
},
"rejections": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RejectionView"
},
"description": "Rejections is empty when placement was never attempted, which is itself the answer: the model is satisfied, or the reconciler has not run yet."
}
}
},
"FabricTestRequest": {
"type": "object",
"description": "FabricTestRequest is a bandwidth test between two nodes.",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
},
"fabric": {
"type": "string",
"description": "Fabric is the declared fabric to test over; empty is the one the two nodes share."
},
"seconds": {
"type": "integer",
"description": "Seconds each rail is measured for, from 1 to 30."
}
}
},
"FabricTestView": {
"type": "object",
"description": "FabricTestView is a bandwidth test between two nodes.",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
},
"fabric": {
"type": "string"
},
"ok": {
"type": "boolean"
},
"rails": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RailView"
}
},
"notes": {
"type": "array",
"items": {
"type": "string"
}
},
"took": {
"type": "string"
}
}
},
"FabricUse": {
"type": "object",
"description": "FabricUse is capacity within one fabric.",
"properties": {
"fabric": {
"type": "string"
},
"nodes": {
"type": "integer"
},
"nodes_with_weights": {
"type": "integer",
"description": "ModelsPresent is how many nodes here hold weights at all, and Models how many distinct models they hold between them.\n\nPer fabric because that is the unit at which the answer is actionable. Fabrics are not connected to one another, so weights in one are not weights in another: a model seeded into a single fabric leaves the rest of the cluster unable to serve it without first moving tens of gigabytes over the management network, and nothing said so."
},
"models_present": {
"type": "integer"
},
"largest_free_block": {
"type": "integer",
"description": "LargestFreeBlock is the most nodes on this fabric that are entirely free, which is the number that decides whether a multi-node replica can land."
}
}
},
"FetchView": {
"type": "object",
"description": "FetchView is a download in flight.",
"properties": {
"source": {
"type": "string"
},
"bytes_done": {
"type": "integer",
"format": "int64"
},
"bytes_total": {
"type": "integer",
"format": "int64",
"description": "BytesTotal is 0 when the server did not say how large the file is."
},
"percent": {
"type": "integer",
"description": "Percent is absent rather than zero when the total is unknown: an invented percentage that stops moving is worse than a byte count that keeps rising."
}
}
},
"GPUView": {
"type": "object",
"description": "GPUView is one card as a node's page shows it.",
"properties": {
"index": {
"type": "integer"
},
"name": {
"type": "string"
},
"label": {
"type": "string",
"description": "Label is the device as people are shown it: \"3\" for a whole card, \"0/mig2\" for card 0's MIG instance 2."
},
"class": {
"type": "string"
},
"card": {
"type": "integer",
"description": "Card is the physical card's index: the device's own, or for a MIG instance its parent's, which is what the card's sensors are under."
},
"mig_profile": {
"type": "string",
"description": "MIGProfile is the instance's profile, like 3g.40gb; empty for a whole card."
},
"memory_total_mb": {
"type": "integer"
},
"memory_used_mb": {
"type": "integer"
},
"compute_capability": {
"type": "string",
"description": "ComputeCapability is what decides which engine builds run on the card: CUDA 13 builds need 7.5, so a V100 (7.0) runs only older ones."
},
"numa": {
"type": "integer"
},
"nvlink_peers": {
"type": "array",
"items": {
"type": "integer"
}
},
"nearest_nic": {
"type": "string",
"description": "NearestNIC is the adapter closest to the card, and how close."
},
"nic_path": {
"type": "string"
},
"fabric_state": {
"type": "string"
},
"domain": {
"type": "string"
},
"bandwidth": {
"type": "string"
}
}
},
"GuardAttachmentRequest": {
"type": "object",
"description": "GuardAttachmentRequest attaches a policy to a part of the tenancy tree, a key or a person, or with DELETE takes it off again.",
"properties": {
"target": {
"type": "string",
"description": "Target is org:NAME, team:ORG/TEAM, project:ORG/TEAM/PROJECT (or the ID after the colon), key:KEY-ID or user:USER-ID."
},
"policy": {
"type": "string",
"description": "Policy is a policy's name in server.yaml's guard.policies."
}
}
},
"GuardAttachmentView": {
"type": "object",
"description": "GuardAttachmentView is one attachment, with the name people know its scope by.",
"properties": {
"Scope": {
"type": "string"
},
"ScopeID": {
"type": "string"
},
"Policy": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"GuardView": {
"type": "object",
"description": "GuardView is the library and where its policies are attached.",
"properties": {
"policies": {
"type": "array",
"items": {
"type": "string"
}
},
"default": {
"type": "array",
"items": {
"type": "string"
}
},
"attachments": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GuardAttachmentView"
}
}
}
},
"HeadroomView": {
"type": "object",
"description": "HeadroomView is how many more replicas of a model fit now, and where.",
"properties": {
"model": {
"type": "string"
},
"current": {
"type": "integer",
"description": "Current is the replicas holding capacity: starting or ready."
},
"more": {
"type": "integer",
"description": "More is how many more placement would find room for now."
},
"nodes": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "Nodes is where each of those would go."
},
"limited": {
"type": "boolean",
"description": "Limited is set when More stopped at the limit asked rather than at the cluster's edge: there may be room for more."
},
"blocked": {
"type": "array",
"items": {
"type": "string"
},
"description": "Blocked says why one more does not fit, a line per node considered."
},
"tok_per_sec": {
"type": "number",
"description": "TokPerSec is what one more replica was measured to serve; 0 unmeasured."
},
"by_preempting": {
"type": "integer",
"description": "ByPreempting is how many more would fit by stopping replicas this model's class may take; Preempts the models those belong to."
},
"preempts": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"IBPortView": {
"type": "object",
"description": "IBPortView is one port as a page shows it.",
"properties": {
"hca": {
"type": "string"
},
"port": {
"type": "integer"
},
"state": {
"type": "string"
},
"phys_state": {
"type": "string"
},
"rate_gbps": {
"type": "integer"
},
"link_layer": {
"type": "string"
},
"active": {
"type": "boolean"
},
"fabric": {
"type": "string",
"description": "Fabric is the declared fabric this port's adapter carries, if any."
},
"physical": {
"type": "string",
"description": "Physical is the fabric the port is physically on: its subnet manager, or its RoCE network. SMError says why that is not known."
},
"sm_error": {
"type": "string"
},
"errors": {
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "int64"
},
"description": "Errors are the error counters that are not zero, by name."
},
"tx_bytes": {
"type": "integer",
"format": "int64"
},
"rx_bytes": {
"type": "integer",
"format": "int64"
}
}
},
"IdleReplica": {
"type": "object",
"description": "IdleReplica is a replica holding hardware nothing is asking for.",
"properties": {
"id": {
"type": "string"
},
"model": {
"type": "string"
},
"idle_seconds": {
"type": "integer",
"format": "int64"
},
"gpus": {
"type": "integer"
}
}
},
"Live": {
"type": "object",
"description": "Live is one of the cluster's adapters as its node last reported it.",
"properties": {
"node": {
"type": "string"
},
"hca": {
"type": "string"
},
"state": {
"type": "string"
},
"phys_state": {
"type": "string"
},
"gbps": {
"type": "integer"
},
"tx_bps": {
"type": "number"
},
"rx_bps": {
"type": "number"
},
"errors": {
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "int64"
}
}
}
},
"LoadView": {
"type": "object",
"description": "LoadView is a node's CPU and memory in use, at its last heartbeat.",
"properties": {
"cpu_percent": {
"type": "number"
},
"cpus": {
"type": "integer"
},
"load1": {
"type": "number"
},
"load5": {
"type": "number"
},
"load15": {
"type": "number"
},
"memory_used_bytes": {
"type": "integer",
"format": "int64"
},
"memory_total_bytes": {
"type": "integer",
"format": "int64"
},
"memory_percent": {
"type": "number",
"description": "MemPercent is used over used plus available."
},
"age_seconds": {
"type": "integer",
"format": "int64"
},
"cpu_temp_c": {
"type": "number",
"description": "What the node's sensors say; zero is not measured."
},
"cpu_power_w": {
"type": "number"
},
"inlet_temp_c": {
"type": "number"
},
"gpu_sensors": {
"type": "array",
"items": {
"$ref": "#/components/schemas/inventory.GPUSensor"
}
}
}
},
"LogsView": {
"type": "object",
"description": "LogsView is one of a node's logs, as the node sent it.",
"properties": {
"node": {
"type": "string"
},
"source": {
"type": "string"
},
"lines": {
"type": "array",
"items": {
"type": "string"
}
},
"sources": {
"type": "array",
"items": {
"type": "string"
},
"description": "Sources are every log the node can show: \"agent\", and one per engine running there."
},
"error": {
"type": "string"
}
}
},
"MetricsQuery": {
"type": "object",
"description": "MetricsQuery is one line set of a chart: a PromQL expression, and the label naming each line.",
"properties": {
"id": {
"type": "string"
},
"expr": {
"type": "string"
},
"by": {
"type": "string"
}
}
},
"MetricsRequest": {
"type": "object",
"description": "MetricsRequest asks for several queries over one window at once.",
"properties": {
"window": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"step": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"queries": {
"type": "array",
"items": {
"$ref": "#/components/schemas/MetricsQuery"
}
}
}
},
"MetricsResult": {
"type": "object",
"description": "MetricsResult is each query's lines, by id; Configured is false when no Prometheus is set, and Errors says which queries failed and why.",
"properties": {
"configured": {
"type": "boolean"
},
"series": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"$ref": "#/components/schemas/promq.Series"
}
}
},
"errors": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"ModelAdded": {
"type": "object",
"description": "ModelAdded names the model added to the catalog.",
"properties": {
"added": {
"type": "string"
}
}
},
"ModelTotals": {
"type": "object",
"description": "ModelTotals counts models by whether they have what they asked for.",
"properties": {
"total": {
"type": "integer"
},
"satisfied": {
"type": "integer"
},
"short": {
"type": "integer"
}
}
},
"ModelView": {
"type": "object",
"description": "ModelView is a model as `ctl models` shows it.",
"properties": {
"name": {
"type": "string"
},
"canary": {
"$ref": "#/components/schemas/catalog.Canary",
"description": "Canary is a share of its requests sent to a candidate; CanaryOf is set on the candidate, naming the model it is a canary of."
},
"canary_of": {
"type": "string"
},
"eval": {
"$ref": "#/components/schemas/catalog.EvalGate",
"description": "Eval is the quality suite its new weights must pass, when it has one."
},
"description": {
"type": "string",
"description": "Description is what the model is for, when somebody said."
},
"aliases": {
"type": "array",
"items": {
"type": "string"
}
},
"source": {
"type": "string"
},
"min_replicas": {
"type": "integer"
},
"max_replicas": {
"type": "integer"
},
"ready_replicas": {
"type": "integer"
},
"total_replicas": {
"type": "integer"
},
"desired_replicas": {
"type": "integer",
"description": "Desired is how many it should have now: Min, or for an on-demand model one while it is being asked for and none otherwise."
},
"failures": {
"type": "integer",
"description": "Failures counts replicas that failed to start in a row."
},
"parked": {
"type": "boolean",
"description": "Parked is set once Failures reached the limit; the model is not retried until its definition changes or `ctl retry` is run. Reason is the last error."
},
"reason": {
"type": "string"
},
"unplaceable": {
"type": "boolean",
"description": "Unplaceable is set when it is short and the last attempt found no node."
},
"fallbacks": {
"type": "array",
"items": {
"type": "string"
}
},
"profiles": {
"type": "array",
"items": {
"type": "string"
}
},
"memory_gb": {
"type": "integer",
"description": "MemoryGB and CPUCores are what one replica reserves, from its first profile; MeasuredMemoryGB is the most one of its replicas uses now, 0 when none is measured."
},
"cpu_cores": {
"type": "integer"
},
"measured_memory_gb": {
"type": "number"
},
"warnings": {
"type": "array",
"items": {
"type": "string"
},
"description": "Warnings are what makes its reservation wrong: nothing declared where placement needs a figure, or less declared than it uses."
},
"class": {
"type": "string",
"description": "Class is its capacity class; Preempted the replicas it lost to a higher class; HeldFor the model it is giving room to now, if any."
},
"owner": {
"type": "string"
},
"external": {
"type": "string",
"description": "External is where a model served outside the cluster goes, provider host and its name for the model; empty for one served here."
},
"adapters": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.Adapter"
},
"description": "Adapters are the LoRA adapters it serves."
},
"preempted": {
"type": "integer"
},
"held_for": {
"type": "string"
},
"origin": {
"$ref": "#/components/schemas/OriginView",
"description": "Origin is the registry repository its weights came from, and at which commit; Update what that repository had when it was last asked."
},
"update": {
"$ref": "#/components/schemas/modelserve.UpdateInfo"
}
}
},
"NodeEngineRequest": {
"type": "object",
"description": "NodeEngineRequest chooses one engine's build for a node.",
"properties": {
"engine": {
"type": "string"
},
"build": {
"type": "string",
"description": "Build is \"auto\", a build such as \"cu129\", or \"none\"."
}
}
},
"NodeRemoved": {
"type": "object",
"description": "NodeRemoved names the node forgotten. Removed is the string \"true\".",
"properties": {
"id": {
"type": "string"
},
"removed": {
"type": "string"
}
}
},
"NodeStateRequest": {
"type": "object",
"description": "NodeStateRequest cordons, drains or readies a node: ready (or uncordon), cordoned (or cordon), draining (or drain).",
"properties": {
"state": {
"type": "string"
}
}
},
"NodeStateView": {
"type": "object",
"description": "NodeStateView is a node's state after the change.",
"properties": {
"id": {
"type": "string"
},
"state": {
"type": "string"
}
}
},
"NodeTotals": {
"type": "object",
"description": "NodeTotals counts nodes by the states that need different responses.",
"properties": {
"total": {
"type": "integer"
},
"ready": {
"type": "integer"
},
"cordoned": {
"type": "integer"
},
"draining": {
"type": "integer"
},
"unreachable": {
"type": "integer"
}
}
},
"NodeView": {
"type": "object",
"description": "NodeView is a node as `ctl nodes` shows it.",
"properties": {
"id": {
"type": "string"
},
"hostname": {
"type": "string"
},
"mgmt_addr": {
"type": "string"
},
"state": {
"type": "string"
},
"labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"gpu_total": {
"type": "integer"
},
"gpu_free": {
"type": "integer"
},
"memory_gb": {
"type": "integer",
"description": "MemoryGB is the machine's RAM, 0 when the agent did not report it. It is what decides whether a CPU profile can be placed here, so it belongs where someone looks when a model will not schedule."
},
"cpu_count": {
"type": "integer",
"description": "CPUCount is the machine's CPUs, 0 when the agent did not report them."
},
"engines": {
"type": "array",
"items": {
"type": "string"
},
"description": "Engines are the inference engines installed here, as the agent found them. Absent means the agent is older than the probe and said nothing, which is not the same as having none — placement treats it that way too, or a control plane upgrade would empty a fleet."
},
"provision": {
"type": "array",
"items": {
"$ref": "#/components/schemas/inventory.EngineInstall"
},
"description": "Provision is where installing each wanted engine stands. An engine is in Engines only once its installation here is ready."
},
"engine_builds": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "EngineBuilds are the builds chosen for this node, by engine: \"auto\" (its hardware decides), a build (\"cu129\"), or \"none\". Only on a node with GPUs, the only kind with a choice to make."
},
"os": {
"type": "string",
"description": "OS is the operating system and architecture, as the agent read them."
},
"warnings": {
"type": "array",
"items": {
"type": "string"
},
"description": "Warnings are facts about the machine that make it slow or unusable without making it unhealthy: a VM with no vector instructions runs every model, at a fifth of the speed."
},
"models_on_disk": {
"type": "array",
"items": {
"type": "string"
},
"description": "Models are the weights this node can see. Absent means it was not asked to look, which is not the same as holding none."
},
"disk_free_gb": {
"type": "integer",
"description": "DiskFreeGB and DiskTotalGB are the filesystems holding those weights, summed. Zero means the agent did not report any, which an older agent and a node with no model directories both do — so it reads as unknown rather than as a full disk.\n\nSummed because an operator asking \"can this node take another model\" wants one number; the per-filesystem detail is in the node's own record for anyone who needs it. Shared filesystems are left out of the sum: the space on a filer is not this node's to spend, and adding it would let a fleet of twenty nodes each believe it has the same free terabyte."
},
"disk_total_gb": {
"type": "integer"
},
"gpu_classes": {
"type": "array",
"items": {
"type": "string"
}
},
"gpus_by_class": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ClassGPUs"
},
"description": "ClassGPUs counts the node's devices by class, in the order of Classes. A node with a card in MIG mode has several classes — each profile its instances are cut to, and any whole card beside them — and GPUTotal alone would add 3g.40gb instances to 80 GB cards."
},
"fabrics": {
"type": "array",
"items": {
"type": "string"
}
},
"unhealthy_gpus": {
"type": "array",
"items": {
"type": "string"
},
"description": "Unhealthy lists GPUs kept out of placement and why, which is usually the answer when a node looks idle but nothing will schedule onto it."
},
"last_seen_ago": {
"type": "string"
},
"agent_version": {
"type": "string"
},
"features": {
"type": "array",
"items": {
"type": "string"
},
"description": "Features are the requests the agent answers beyond the usual: \"fabric-test\". Absent is an agent too old to say."
},
"replicas": {
"type": "integer"
},
"load": {
"$ref": "#/components/schemas/LoadView",
"description": "Load is how busy the machine is, absent when its agent has not measured it lately — which is unknown, not idle."
},
"ib_ports": {
"type": "array",
"items": {
"$ref": "#/components/schemas/IBPortView"
},
"description": "IBPorts are the node's InfiniBand and RoCE ports at the last heartbeat."
},
"gpus": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GPUView"
},
"description": "GPUs are the cards, with how they are wired: NVLink peers, the adapter nearest each, and the NVLink domain each has joined."
},
"nvlink_domain": {
"type": "string",
"description": "NVLinkDomain is the multi-node domain every card has joined, if any."
},
"imex": {
"type": "string"
},
"imex_channels": {
"type": "integer"
}
}
},
"OriginRequest": {
"type": "object",
"description": "OriginRequest names the repository a model's weights came from.",
"properties": {
"repo": {
"type": "string"
}
}
},
"OriginView": {
"type": "object",
"description": "OriginView is where a model's weights were published.",
"properties": {
"repo": {
"type": "string"
},
"revision": {
"type": "string"
},
"previous": {
"type": "string",
"description": "Previous is the commit the last update replaced, which it can go back to."
}
}
},
"OrphanView": {
"type": "object",
"description": "OrphanView is cached weights on one node that no catalog model accounts for.",
"properties": {
"node": {
"type": "string"
},
"paths": {
"type": "array",
"items": {
"type": "string"
}
},
"bytes": {
"type": "integer",
"format": "int64",
"description": "Bytes is what deleting them would free, as far as the node reported. A file whose size was not reported counts as zero rather than being left out, so the list and the number always describe the same set."
}
}
},
"OwnerRequest": {
"type": "object",
"description": "OwnerRequest sets the part of the tenancy tree a model's capacity counts against: org:NAME, team:ORG/TEAM or project:ORG/TEAM/PROJECT, or their IDs. Empty makes the model shared.",
"properties": {
"owner": {
"type": "string"
}
}
},
"OwnerView": {
"type": "object",
"description": "OwnerView is a model's owner now, as scope:ID.",
"properties": {
"model": {
"type": "string"
},
"owner": {
"type": "string"
}
}
},
"ParkedModel": {
"type": "object",
"description": "ParkedModel is a model no longer retried, and why.",
"properties": {
"model": {
"type": "string"
},
"failures": {
"type": "integer"
},
"reason": {
"type": "string"
}
}
},
"QuotaRequest": {
"type": "object",
"description": "QuotaRequest sets a scope's quota. Scope may be written with an ID or a name: org:Acme, team:Acme/ml, project:Acme/ml/training.",
"properties": {
"scope": {
"type": "string"
},
"guarantee": {
"$ref": "#/components/schemas/store.Resources"
},
"limit": {
"$ref": "#/components/schemas/store.Resources"
}
}
},
"QuotaSet": {
"type": "object",
"description": "QuotaSet is the scope a quota was set on, as org:ID, team:ID or project:ID whatever name it was asked by.",
"properties": {
"scope": {
"type": "string"
}
}
},
"QuotaView": {
"type": "object",
"description": "QuotaView is one scope's quota with what it holds now.",
"properties": {
"scope": {
"type": "string",
"description": "Scope is team:ID; Name is how people know it, \"Acme / ml\"."
},
"name": {
"type": "string"
},
"guarantee": {
"$ref": "#/components/schemas/store.Resources"
},
"limit": {
"$ref": "#/components/schemas/store.Resources"
},
"holds": {
"$ref": "#/components/schemas/quota.Amount"
},
"updated_by": {
"type": "string"
},
"updated_at": {
"type": "string",
"format": "date-time"
}
}
},
"RailView": {
"type": "object",
"description": "RailView is one rail's result.",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
},
"rate_gbps": {
"type": "integer"
},
"gbps": {
"type": "number"
},
"verdict": {
"type": "string"
},
"detail": {
"type": "string"
}
}
},
"RejectionView": {
"type": "object",
"description": "RejectionView is one rejected candidate.",
"properties": {
"profile": {
"type": "string"
},
"pool": {
"type": "string"
},
"node": {
"type": "string"
},
"reason": {
"type": "string"
}
}
},
"Removed": {
"type": "object",
"description": "Removed names what was taken away: a model, or a quota's scope.",
"properties": {
"removed": {
"type": "string"
}
}
},
"ReplayRequest": {
"type": "object",
"description": "ReplayRequest names the model a kept request is sent to again.",
"properties": {
"model": {
"type": "string"
}
}
},
"ReplayView": {
"type": "object",
"description": "ReplayView is a kept request sent again, beside what it got the first time.",
"properties": {
"original": {
"$ref": "#/components/schemas/store.RequestBody"
},
"model": {
"type": "string"
},
"status": {
"type": "integer"
},
"body": {
"description": "Any JSON value."
},
"took_ms": {
"type": "integer",
"format": "int64"
}
}
},
"ReplicaTotal": {
"type": "object",
"description": "ReplicaTotal counts replicas by state.",
"properties": {
"ready": {
"type": "integer"
},
"starting": {
"type": "integer"
},
"draining": {
"type": "integer"
},
"failed": {
"type": "integer"
}
}
},
"ReplicaView": {
"type": "object",
"description": "ReplicaView is a replica as `ctl replicas` shows it.",
"properties": {
"id": {
"type": "string"
},
"engine_key": {
"type": "string",
"description": "EngineKey is the key this replica's engine demands, for `ctl bench` and anyone else holding the admin listener who needs to reach an engine directly. The client-facing pages never render it."
},
"restart": {
"type": "string",
"description": "Restart is \"queued\" or \"replacing\" while an operator's restart of this replica is under way."
},
"model": {
"type": "string"
},
"profile": {
"type": "string"
},
"stale": {
"type": "boolean",
"description": "Stale is true when the profile has been edited since this replica was placed, so it is running a definition the catalog no longer holds.\n\nReported rather than acted on. Moving a replica that is serving costs more than the imperfection, and the operator who made the edit is the one who should decide whether it is worth a restart."
},
"state": {
"type": "string"
},
"pool": {
"type": "string"
},
"fabric": {
"type": "string"
},
"endpoint": {
"type": "string"
},
"age_seconds": {
"type": "integer",
"format": "int64"
},
"idle_seconds": {
"type": "integer",
"format": "int64",
"description": "IdleSec is how long since a request was routed here. Negative means the router has not reported any use of this replica, which is not the same as idle — it is what a replica looks like before anything has asked for it, and after a router restart."
},
"error": {
"type": "string"
},
"shards": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ShardView"
}
}
}
},
"RequestView": {
"type": "object",
"description": "RequestView is what one request went through.",
"properties": {
"request_id": {
"type": "string"
},
"at": {
"type": "string",
"format": "date-time"
},
"key_id": {
"type": "string"
},
"user_id": {
"type": "string"
},
"project_id": {
"type": "string"
},
"model": {
"type": "string"
},
"served_model": {
"type": "string"
},
"replica": {
"type": "string"
},
"status": {
"type": "integer"
},
"latency_ms": {
"type": "integer",
"format": "int64"
},
"queue_ms": {
"type": "integer",
"format": "int64"
},
"ttft_ms": {
"type": "integer",
"format": "int64"
},
"prompt_tokens": {
"type": "integer",
"format": "int64"
},
"completion_tokens": {
"type": "integer",
"format": "int64"
},
"cost_micros": {
"type": "integer",
"format": "int64"
},
"guard_action": {
"type": "string",
"description": "What the guardrails did, by name."
},
"guard_policy": {
"type": "string"
},
"guard_category": {
"type": "string"
},
"guard_ms": {
"type": "integer",
"format": "int64"
},
"end_user": {
"type": "string",
"description": "What the client said about it: OpenAI's user field, and its tags."
},
"tags": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"cache_hit": {
"type": "boolean",
"description": "CacheHit is an answer reused from the project's answer cache."
}
}
},
"ResourcesRequest": {
"type": "object",
"description": "ResourcesRequest sets what a model's profiles reserve of a node.",
"properties": {
"profile": {
"type": "string",
"description": "Profile is one profile's name; empty is every profile."
},
"memory_gb": {
"type": "integer"
},
"cpu_cores": {
"type": "integer"
}
}
},
"RestartRequest": {
"type": "object",
"description": "RestartRequest names what to restart: replicas by id, every replica of some models, or — All — every ready replica in the cluster.",
"properties": {
"replicas": {
"type": "array",
"items": {
"type": "string"
}
},
"models": {
"type": "array",
"items": {
"type": "string"
}
},
"all": {
"type": "boolean"
},
"in_place": {
"type": "boolean",
"description": "InPlace stops each replica before starting its replacement, rather than starting the replacement beside it first."
}
}
},
"RestartResult": {
"type": "object",
"description": "RestartResult lists the replicas queued.",
"properties": {
"queued": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"Result": {
"type": "object",
"description": "Result is what a change that has no other answer says it did.",
"properties": {
"result": {
"type": "string"
}
}
},
"RetryView": {
"type": "object",
"description": "RetryView says whether the model had been parked, given up on after failing to start, before it was retried.",
"properties": {
"was_parked": {
"type": "boolean"
}
}
},
"ScaleRequest": {
"type": "object",
"description": "ScaleRequest is how many replicas a model should run.",
"properties": {
"min": {
"type": "integer"
},
"max": {
"type": "integer",
"description": "Max omitted follows Min, which is what the catalog does for a model that declares only a minimum."
},
"idle_timeout": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
}
}
},
"ScaleResponse": {
"type": "object",
"description": "ScaleResponse reports the scaling that is now in force.\n\nWhat is in force rather than what was asked for: the catalog fills in a max that was left out, and a caller that echoed its own request would print a number the cluster is not using.",
"properties": {
"model": {
"type": "string"
},
"min": {
"type": "integer"
},
"max": {
"type": "integer"
},
"idle_timeout": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"on_demand": {
"type": "boolean"
}
}
},
"ScopeUsageView": {
"type": "object",
"description": "ScopeUsageView is one group's spend, with its quota when it has one.",
"properties": {
"scope": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"keys": {
"type": "integer",
"format": "int64"
},
"requests": {
"type": "integer",
"format": "int64"
},
"prompt_tokens": {
"type": "integer",
"format": "int64"
},
"completion_tokens": {
"type": "integer",
"format": "int64"
},
"cost_micros": {
"type": "integer",
"format": "int64"
},
"errors": {
"type": "integer",
"format": "int64"
},
"last_at": {
"type": "string",
"format": "date-time"
},
"budget_micros": {
"type": "integer",
"format": "int64",
"description": "Budget is what this level sets, absent when it sets none. A group bounded only by its parent has no budget of its own, and reporting the parent's against each child would read as though each had that much."
},
"budget_period": {
"type": "string"
},
"fraction": {
"type": "number",
"description": "Fraction is spend over budget, absent for the same reason."
}
}
},
"ShardView": {
"type": "object",
"description": "ShardView is one shard of a replica.",
"properties": {
"id": {
"type": "string"
},
"node": {
"type": "string"
},
"rank": {
"type": "integer"
},
"gpus": {
"type": "array",
"items": {
"type": "integer"
}
},
"state": {
"type": "string"
},
"error": {
"type": "string"
},
"fetch": {
"$ref": "#/components/schemas/FetchView",
"description": "Fetch is the download this shard is waiting on, absent when it is not waiting on one. It is what tells a replica pulling a hundred gigabytes apart from one that is wedged — which look identical without it."
},
"cpu_cores": {
"type": "number",
"description": "CPUCores and MemoryBytes are the engine's use of its node, from the node's last heartbeat; zero when not measured."
},
"memory_bytes": {
"type": "integer",
"format": "int64"
}
}
},
"StoreMember": {
"type": "object",
"description": "StoreMember is one member of a replicated store, as its Patroni reports it.",
"properties": {
"name": {
"type": "string"
},
"host": {
"type": "string"
},
"role": {
"type": "string"
},
"state": {
"type": "string"
},
"lag": {
"type": "integer",
"format": "int64",
"description": "Lag is bytes behind the leader; -1 unknown, 0 for the leader."
}
}
},
"Summary": {
"type": "object",
"description": "Summary is the whole fleet in one answer.\n\nA per-node listing is the right tool for four nodes and the wrong one for two hundred: the questions that matter at that size — how full am I, what is broken, what is holding cards it is not using — are aggregates, and reading them off a long table is a chore that gets skipped. Everything here is derived from the same state the tables show, so it can never disagree with them; it is a different question asked of the same facts.",
"properties": {
"nodes": {
"$ref": "#/components/schemas/NodeTotals"
},
"gpus": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ClassUse"
}
},
"fabrics": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FabricUse"
},
"description": "Fabrics matter because a multi-node replica may never span two of them, so free capacity in the wrong fabric is not capacity for the model that needs it."
},
"replicas": {
"$ref": "#/components/schemas/ReplicaTotal"
},
"models": {
"$ref": "#/components/schemas/ModelTotals"
},
"unplaceable": {
"type": "array",
"items": {
"type": "string"
},
"description": "Unplaceable names models the scheduler currently cannot satisfy. This is the line that turns \"something is wrong\" into a place to look."
},
"parked": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ParkedModel"
},
"description": "Parked are models that failed every time they started and are no longer retried, with the last error."
},
"idle_replicas": {
"type": "array",
"items": {
"$ref": "#/components/schemas/IdleReplica"
},
"description": "IdleReplicas are serving replicas nothing has asked for in a while, which on a fleet with more models than GPUs is the first place to find room."
},
"store": {
"type": "array",
"items": {
"$ref": "#/components/schemas/StoreMember"
},
"description": "Store is the members of the store's cluster when it is replicated, and StoreError why it could not be read; both empty for a single database."
},
"store_error": {
"type": "string"
}
}
},
"TargetView": {
"type": "object",
"description": "TargetView is how many replicas a model needs to serve a throughput, from what one replica was measured to serve, and whether the cluster has room.",
"properties": {
"model": {
"type": "string"
},
"tok_per_sec": {
"type": "number",
"description": "TokPerSec is what was asked for; PerReplica what one replica was measured to serve at its SLO, on Profile."
},
"per_replica_tok_per_sec": {
"type": "number"
},
"profile": {
"type": "string"
},
"needed": {
"type": "integer",
"description": "Needed replicas in all; Current hold capacity now; More is how many of Needed are not running, and Room how many more fit."
},
"current": {
"type": "integer"
},
"more": {
"type": "integer"
},
"room": {
"type": "integer"
},
"fits": {
"type": "boolean"
},
"blocked": {
"type": "array",
"items": {
"type": "string"
}
},
"preempts": {
"type": "array",
"items": {
"type": "string"
},
"description": "Preempts is whose replicas would be stopped to make the room, when free room alone is not enough; Room counts that room too."
}
}
},
"TopologyView": {
"type": "object",
"description": "TopologyView is one fabric's map, with the cluster's own adapters on it live: their state, rate and traffic from the last heartbeat.",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"declared": {
"type": "array",
"items": {
"type": "string"
}
},
"scanned_at": {
"type": "string",
"format": "date-time"
},
"scanned_by": {
"type": "string"
},
"took_ms": {
"type": "integer",
"format": "int64"
},
"error": {
"type": "string"
},
"map": {
"$ref": "#/components/schemas/topology.View"
},
"live": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/Live"
}
},
"problems": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.Problem"
},
"description": "Problems are the fabric's own, from the analysis of its identity and subnet managers."
},
"sm": {
"$ref": "#/components/schemas/fabrics.SM"
},
"sms": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.SM"
}
}
}
},
"UpgradeRequest": {
"type": "object",
"description": "UpgradeRequest names the release a node should run.",
"properties": {
"version": {
"type": "string"
}
}
},
"UpgradeView": {
"type": "object",
"description": "UpgradeView is the release a node was told to run.",
"properties": {
"node": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"bench.Capacity": {
"type": "object",
"description": "Capacity is what one replica was measured to serve, kept so the measurement outlives the terminal it was printed in.\n\nThe conclusion of a run, not the run. The ramp itself — every concurrency level, its latencies, its errors — is worth reading once, while deciding whether the run was sound; it is not worth carrying around afterwards, and storing it would grow without bound as a model is re-benchmarked. What a later reader needs is the number and enough provenance to judge whether it is still true.",
"properties": {
"model": {
"type": "string"
},
"profile": {
"type": "string"
},
"max_concurrency_at_slo": {
"type": "integer",
"description": "MaxConcurrencyAtSLO is the capacity: the highest concurrency that still met the target. Zero means even one request did not, which is a real result and not a missing one — it says this hardware cannot serve this model at this SLO at all."
},
"throughput_tok_per_sec": {
"type": "number",
"description": "ThroughputTokPerSec and the latencies are taken at that level, not at the peak. Peak throughput arrives long after latency has become unusable, so reporting it would overstate what the hardware can serve."
},
"ttft_p99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"tpot_p99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"suggested_target_waiting": {
"type": "integer",
"description": "SuggestedTargetWaiting and SuggestedKVCeiling are the queue depth and cache pressure seen while the SLO was still being met, which is what admission should treat as healthy for this model. Admission currently applies one global default to every model; these are the per-model numbers it should be using instead."
},
"suggested_kv_ceiling": {
"type": "number"
},
"slo": {
"$ref": "#/components/schemas/bench.SLO",
"description": "SLO is recorded because capacity is meaningless without it. The same replica has a different capacity against a 200ms first-token target than against a 2s one, and a number stored without the target it was measured against cannot be compared with anything."
},
"target": {
"type": "string",
"description": "Target is the endpoint the load actually went to, kept so a profile measured against the gateway is never mistaken for one measured against a replica. Only the second says anything about the hardware."
},
"measured_at": {
"type": "string",
"format": "date-time"
}
}
},
"bench.SLO": {
"type": "object",
"description": "SLO is the latency target capacity is measured against.",
"properties": {
"TTFTp99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
},
"TPOTp99": {
"type": "integer",
"format": "int64",
"description": "A duration, in nanoseconds."
}
}
},
"canary.Side": {
"type": "object",
"description": "Side is what one side of a canary served since it began.",
"properties": {
"requests": {
"type": "integer",
"format": "int64"
},
"errors": {
"type": "integer",
"format": "int64",
"description": "Errors are answers of 500 and up: the engine's failures, not the client's mistakes."
},
"ttft_ms": {
"type": "number",
"description": "TTFT is over streamed requests, Latency over the rest, both means in milliseconds with how many they are over."
},
"ttft_count": {
"type": "integer",
"format": "int64"
},
"latency_ms": {
"type": "number"
},
"latency_count": {
"type": "integer",
"format": "int64"
}
}
},
"canary.Stat": {
"type": "object",
"description": "Stat compares the two sides of one model's canary.",
"properties": {
"canary": {
"type": "string"
},
"since": {
"type": "string",
"format": "date-time"
},
"stable": {
"$ref": "#/components/schemas/canary.Side"
},
"candidate": {
"$ref": "#/components/schemas/canary.Side"
}
}
},
"catalog.Adapter": {
"type": "object",
"description": "Adapter is a LoRA adapter served on a model's replicas.",
"properties": {
"name": {
"type": "string",
"description": "Name is what clients ask for, like a model name."
},
"source": {
"type": "string",
"description": "Source is the adapter file (GGUF for llama.cpp), fetched by each node as the model's weights are."
},
"scale": {
"type": "number",
"description": "Scale is how strongly it is applied; zero takes 1."
}
}
},
"catalog.Canary": {
"type": "object",
"description": "Canary is a share of a model's requests sent to a candidate, and when to give up on it.",
"properties": {
"model": {
"type": "string",
"description": "Model is the candidate: a catalog model, usually this one at newer weights, which clients cannot name themselves."
},
"percent": {
"type": "integer",
"description": "Percent of requests go to it, 0 to 100."
},
"min_requests": {
"type": "integer",
"description": "The candidate is taken out — rolled back — when, over at least MinRequests of its own, its error rate is MaxErrorIncrease above this model's (0.05 is five points), or its mean time to the first token is MaxTTFTRatio times this model's. Zero is 50, 0.05 and 1.5."
},
"max_error_increase": {
"type": "number"
},
"max_ttft_ratio": {
"type": "number"
}
}
},
"catalog.Capabilities": {
"type": "object",
"description": "Capabilities describes what a client may ask a model for.\n\nDeclared by the operator rather than discovered, because there is no way to ask an engine what its model can do. That makes these claims, and a wrong claim is worse than none — which is why `ctl engine-check` verifies tool calling against a running engine rather than trusting this.\n\nThe reason it exists: the gateway forwards a tools array to any model, and a model that cannot use them answers in prose. Every OpenAI-compatible client then behaves as though the model is broken, and the only way to find out was to try it. That cost an afternoon.",
"properties": {
"tools": {
"type": "boolean"
},
"vision": {
"type": "boolean"
},
"embeddings": {
"type": "boolean"
}
}
},
"catalog.EvalGate": {
"type": "object",
"description": "EvalGate is a quality suite a model's new weights must pass.",
"properties": {
"suite": {
"type": "string",
"description": "Suite is a suite's name in control.eval_dir, or one the binary carries (arithmetic, json-format)."
},
"min_score": {
"type": "number",
"description": "MinScore is the score, 0 to 1, to pass at; zero is the suite's own threshold."
},
"judge": {
"type": "string",
"description": "Judge grades the suite's rubric cases, instead of the judge it names."
}
}
},
"catalog.External": {
"type": "object",
"description": "External is a provider outside the cluster that serves a model.",
"properties": {
"url": {
"type": "string",
"description": "URL is the provider's base address, without /v1: https://api.openai.com."
},
"model": {
"type": "string",
"description": "Model is what the provider calls it; requests are rewritten to it."
},
"api_key_file": {
"type": "string",
"description": "APIKeyFile holds the provider's key, on the control plane. A file rather than the key itself, so the key is in neither the catalog, the store nor the audit log; empty for a provider that asks for none."
}
}
},
"catalog.GuardModel": {
"type": "object",
"description": "GuardModel is how a judge model's answers are read.",
"properties": {
"format": {
"type": "string",
"description": "Format is llamaguard3 (Meta's Llama Guard 3: \"safe\", or \"unsafe\" and the categories), shieldgemma (Google's ShieldGemma: Yes or No), or json ({\"safe\": false, \"categories\": [\"...\"]})."
},
"categories": {
"type": "array",
"items": {
"type": "string"
},
"description": "Categories the model is asked about, for shieldgemma — each a policy sentence — and the names reported for llamaguard3's S1, S2, …."
}
}
},
"catalog.Model": {
"type": "object",
"description": "Model is a catalog entry as clients see it.",
"properties": {
"name": {
"type": "string"
},
"aliases": {
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"type": "string",
"description": "Description is what this model is for, in a line.\n\nWritten by whoever added it, because nobody else can say it. A registry offers a pipeline tag and a wall of README, and neither answers the question a person picking from a list is asking: which of these nine names should I send this request to.\n\nIt reaches clients through /v1/models, which is the only view most of them ever see. A gateway serving nine models by name alone makes that choice by guesswork."
},
"source": {
"type": "string",
"description": "Source is the weights path or a HuggingFace id."
},
"profiles": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.Profile"
}
},
"scaling": {
"$ref": "#/components/schemas/catalog.Scaling"
},
"class": {
"type": "string",
"description": "Class is how much this model's capacity is worth against another's, when there is not enough for both: critical, standard or opportunistic. Empty is standard, or opportunistic for a model loaded on demand. See EffectiveClass."
},
"owner": {
"type": "string",
"description": "Owner is the part of the tenancy tree whose capacity quota this model counts against, written org:ID, team:ID or project:ID. Empty is shared: held by the cluster, counted against nobody."
},
"external": {
"$ref": "#/components/schemas/catalog.External",
"description": "External is a model served by someone else — an OpenAI-compatible API outside the cluster — rather than by replicas placed here. Such a model has no profiles and nothing is placed for it; the router sends its requests to the provider. Most useful named in another model's fallbacks: used only when the cluster has no capacity left. Its prompts leave the cluster, so which keys may name it is worth an allowlist."
},
"adapters": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.Adapter"
},
"description": "Adapters are LoRA adapters served on this model's replicas, each asked for by its own name as though it were a model. Every replica loads every adapter, applying one only to a request that names it."
},
"fallbacks": {
"type": "array",
"items": {
"type": "string"
}
},
"canary": {
"$ref": "#/components/schemas/catalog.Canary",
"description": "Canary sends a share of this model's requests to another catalog model — the same model at new weights — to compare the two before moving to it (`llmgw ctl model canary`)."
},
"eval": {
"$ref": "#/components/schemas/catalog.EvalGate",
"description": "Eval is a quality suite new weights must pass before they replace this model's: `llmgw ctl model update` and `model promote` run it against them first, and stop below its score."
},
"routing_profile": {
"type": "string",
"description": "RoutingProfile selects how the router scores endpoints for this model."
},
"slo": {
"$ref": "#/components/schemas/catalog.SLO"
},
"context_length": {
"type": "integer",
"description": "ContextLength is how many tokens one request may use, prompt and completion together, and MaxOutput bounds the completion alone. Zero means unknown, which is what every model was until now.\n\nThe gateway knew neither, so an over-long prompt was not refused: it was admitted, given a replica, and failed at the engine, and a client sizing its prompts from /v1/models had nothing to read. Worse, the number is not the one an operator writes in the engine's arguments — llama.cpp divides --ctx-size across its parallel slots, so a pool of 8192 across four slots is 2048 a request, and nothing said so."
},
"max_output": {
"type": "integer"
},
"capabilities": {
"$ref": "#/components/schemas/catalog.Capabilities",
"description": "Capabilities is what this model can do beyond plain completion."
},
"role": {
"type": "string",
"description": "Role \"guard\" is a model that judges the gateway's traffic for the guardrails rather than serving clients: hidden from /v1/models and the chat page, refused to any key that names it, critical by default, and always running. Guard says how its answers are read."
},
"guard": {
"$ref": "#/components/schemas/catalog.GuardModel"
},
"origin": {
"$ref": "#/components/schemas/catalog.Origin",
"description": "Origin is the registry repository the weights came from, at which commit, and each file's checksum there. Written when a model is served from the registry; for one that was not, worked out from the mirror's record of where it fetched the file. It is what lets the control plane say that the repository has published different weights since, and move the model to them."
}
}
},
"catalog.Origin": {
"type": "object",
"description": "Origin is where a model's weights were published.",
"properties": {
"repo": {
"type": "string",
"description": "Repo is the repository, owner/name."
},
"revision": {
"type": "string",
"description": "Revision is the commit the files were fetched at."
},
"files": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.OriginFile"
},
"description": "Files are the weights fetched from it, with what the registry published as each one's sha256. A new commit that leaves them alone — a README edited — is not an update."
},
"previous": {
"$ref": "#/components/schemas/catalog.PreviousOrigin",
"description": "Previous is what the last update replaced, kept so it can be gone back to while its files are still on the mirror."
}
}
},
"catalog.OriginFile": {
"type": "object",
"description": "OriginFile is one weights file of an origin.",
"properties": {
"path": {
"type": "string"
},
"sha256": {
"type": "string"
},
"bytes": {
"type": "integer",
"format": "int64"
}
}
},
"catalog.PreviousOrigin": {
"type": "object",
"description": "PreviousOrigin is a model's source before an update, and where it came from.",
"properties": {
"source": {
"type": "string"
},
"revision": {
"type": "string"
},
"files": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.OriginFile"
}
}
}
},
"catalog.Profile": {
"type": "object",
"description": "Profile is how a model runs on one GPU class.",
"properties": {
"name": {
"type": "string"
},
"engine": {
"type": "string"
},
"gpu_class": {
"type": "string"
},
"tp": {
"type": "integer"
},
"pp": {
"type": "integer"
},
"gpus_per_node": {
"type": "integer",
"description": "GPUsPerNode defaults to TP for a single-node profile."
},
"nodes": {
"type": "integer",
"description": "Nodes above 1 makes this a multi-node profile, which requires a fabric."
},
"args": {
"type": "array",
"items": {
"type": "string"
}
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"min_memory_gb": {
"type": "integer",
"description": "MinMemoryGB is the host RAM this profile needs to run.\n\nThe number that matters is the model's working set: the weights, plus the KV cache for the whole context pool, plus the engine's own overhead. For a GPU profile that lives in the cards and this is small; for a CPU profile it is the whole thing, and getting it wrong means an OOM on a node that reported itself healthy.\n\nZero means unconstrained, which is every profile that existed before this. A node that does not report its memory is not excluded either — an older agent must not have its nodes quietly emptied by an upgrade of the control plane."
},
"cpu_cores": {
"type": "integer",
"description": "CPUCores is the cores a replica of a profile with no GPU is given: reserved out of its node's CPUs by placement, as memory is, and what its engine computes on (llama.cpp's --threads).\n\nReserved because an engine takes every core it is told about, and two on one node that each think they have all of them spin against each other: on an 8-vCPU node, two 7B replicas fell from 10 tokens a second to under one each. Zero reserves nothing and leaves the thread count to the node, which is every profile from before this."
},
"min_disk_gb": {
"type": "integer",
"description": "MinDiskGB is the free space a node needs before it can hold these weights.\n\nOnly checked when the node does not already have them: a node holding the file needs no room for it, and requiring the space twice would keep a model off the one node best placed to run it.\n\nDeclared rather than derived, because the size of a model that has never been fetched anywhere is not knowable from here — and a wrong guess fails late, halfway through a download, which is the failure this exists to prevent. Zero means unconstrained, and a node that reports no storage is not excluded: unknown is not full."
},
"node_selector": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "NodeSelector restricts this profile to nodes carrying every one of these labels, with these values.\n\nA CPU profile otherwise fits everywhere, because there is no card to be free — which is right for a 0.5B model and wrong for a 14B one. Nothing in the inventory says how much memory a node has, so the operator says which nodes are meant for a model instead of the scheduler inferring it. Agents have reported labels since the beginning; this is what reads them."
},
"weight": {
"type": "number",
"description": "Weight is the router's capacity weight. It should come from ctl bench rather than a guess (plan §6.2.1)."
},
"priority": {
"type": "integer",
"description": "Priority orders profiles during placement; highest that fits wins."
},
"startup_timeout": {
"type": "integer",
"format": "int64",
"description": "StartupTimeout bounds model loading. A 70B model across two nodes takes tens of minutes, so this is per profile rather than global.\n\nA duration, in nanoseconds."
}
}
},
"catalog.SLO": {
"type": "object",
"description": "SLO is the latency target a model is expected to meet. `ctl bench` measures capacity against it (plan §6.2.1), and admission holds the lower bands back while the model's recent p99 is past it.",
"properties": {
"TTFTp99": {
"type": "integer",
"format": "int64",
"description": "TTFTp99 is the time to the first token 99 requests in 100 are within.\n\nA duration, in nanoseconds."
},
"TPOTp99": {
"type": "integer",
"format": "int64",
"description": "TPOTp99 is the time per output token, after the first, 99 streamed requests in 100 are within.\n\nA duration, in nanoseconds."
}
}
},
"catalog.ScaleWindow": {
"type": "object",
"description": "ScaleWindow is a part of the week with its own min and max.",
"properties": {
"days": {
"type": "array",
"items": {
"type": "string"
},
"description": "Days are mon … sun, or weekdays, weekends; empty is every day."
},
"from": {
"type": "string",
"description": "From and To are HH:MM; a window whose To is before its From runs past midnight."
},
"to": {
"type": "string"
},
"min": {
"type": "integer"
},
"max": {
"type": "integer",
"description": "Max, when set, is the window's ceiling for load scaling; zero keeps the model's own."
}
}
},
"catalog.Scaling": {
"type": "object",
"description": "Scaling is how many replicas a model should have.",
"properties": {
"min": {
"type": "integer"
},
"max": {
"type": "integer"
},
"idle_timeout": {
"type": "integer",
"format": "int64",
"description": "IdleTimeout is how long an on-demand model may go unasked-for before its replicas are stopped. Zero takes the cluster default.\n\nMinutes rather than seconds, always. Stopping a replica throws away the KV cache prefix routing spent its effort filling, and a model that flaps in and out loses that entirely — so the saving has to be worth more than the cache, which it only is over a real idle period.\n\nA duration, in nanoseconds."
},
"schedule": {
"type": "array",
"items": {
"$ref": "#/components/schemas/catalog.ScaleWindow"
},
"description": "Schedule changes min and max by the time of day, in the control plane's control.timezone: more replicas kept through working hours, fewer at night, an on-demand model kept loaded while people are at work. The first window that holds now wins; outside them all, Min and Max apply."
},
"prewarm": {
"type": "integer",
"format": "int64",
"description": "Prewarm starts a window this long before it opens, so its replicas have loaded by then: loading a model is minutes, and the people who arrive at nine are the reason for the window.\n\nA duration, in nanoseconds."
}
}
},
"eval.Live": {
"type": "object",
"description": "Live is a run as it stands: one running, with how many of its cases are done, or one finished.",
"properties": {
"id": {
"type": "string"
},
"model": {
"type": "string",
"description": "Model is the model the run is about; Target the catalog model that answered, when that was another — its canary, or the new weights an update tried before moving to them."
},
"target": {
"type": "string"
},
"repo": {
"type": "string",
"description": "Repo and Revision are where the weights that answered came from, when that is known."
},
"revision": {
"type": "string"
},
"suite": {
"type": "string",
"description": "Suite is its name, SuiteHash the sha256 of its text."
},
"suite_hash": {
"type": "string"
},
"at": {
"type": "string",
"format": "date-time"
},
"took_ms": {
"type": "integer",
"format": "int64"
},
"score": {
"type": "number",
"description": "Score is the cases' scores weighed, 0 to 1; Passed whether it reached Threshold."
},
"threshold": {
"type": "number"
},
"passed": {
"type": "boolean"
},
"cases": {
"type": "integer",
"description": "Cases were asked; Below scored under half; Errors got no answer."
},
"below": {
"type": "integer"
},
"errors": {
"type": "integer"
},
"judge": {
"type": "string"
},
"by": {
"type": "string"
},
"job": {
"type": "string",
"description": "Job is the update or promotion the run gated, if one did."
},
"error": {
"type": "string",
"description": "Error is why the run could not be scored at all."
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/store.EvalCase"
}
},
"state": {
"type": "string"
},
"done": {
"type": "integer"
}
}
},
"eval.Request": {
"type": "object",
"description": "Request is a suite to run against a model: one on the control plane, by its name, or one sent whole.",
"properties": {
"suite": {
"type": "string",
"description": "Suite is a suite's name in the eval directory, or carried in the binary (arithmetic, json-format)."
},
"content": {
"type": "string",
"description": "Content is a suite's text instead, and File the name of the file it was read from, which names the suite unless it names itself."
},
"file": {
"type": "string"
},
"concurrency": {
"type": "integer",
"description": "Concurrency, Judge and MinScore are as Options has them."
},
"judge": {
"type": "string"
},
"min_score": {
"type": "number"
}
}
},
"eval.SuiteInfo": {
"type": "object",
"description": "SuiteInfo is a suite the control plane can run by name.",
"properties": {
"name": {
"type": "string"
},
"from": {
"type": "string",
"description": "From is the file it is read from, or \"built in\"."
},
"description": {
"type": "string"
},
"cases": {
"type": "integer"
},
"threshold": {
"type": "number"
},
"judge": {
"type": "boolean"
},
"hash": {
"type": "string"
},
"error": {
"type": "string",
"description": "Error is why the file cannot be run."
}
}
},
"fabrics.Change": {
"type": "object",
"description": "Change is a fabric's master subnet manager changing, as its ports saw it.",
"properties": {
"at": {
"type": "string",
"format": "date-time"
},
"from": {
"type": "string"
},
"to": {
"type": "string"
},
"ports": {
"type": "integer"
}
}
},
"fabrics.Member": {
"type": "object",
"description": "Member is one node's adapters on a physical fabric.",
"properties": {
"node": {
"type": "string"
},
"hcas": {
"type": "array",
"items": {
"type": "string"
}
},
"declared": {
"type": "string",
"description": "Declared is the name this node gives these adapters, empty when it declares them in no fabric."
}
}
},
"fabrics.Physical": {
"type": "object",
"description": "Physical is one fabric as the adapters find it.",
"properties": {
"key": {
"type": "string"
},
"kind": {
"type": "string",
"description": "Kind is infiniband or roce."
},
"label": {
"type": "string",
"description": "Label is the key as a person reads it."
},
"sm": {
"$ref": "#/components/schemas/fabrics.SM",
"description": "SM is the master subnet manager, on InfiniBand: the one most of its ports see."
},
"sms": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.SM"
},
"description": "SMs is every subnet manager the fabric lists, master first; empty when no port could ask. Standbys counts those that could take over."
},
"standbys": {
"type": "integer"
},
"masters": {
"type": "object",
"additionalProperties": {
"type": "integer"
},
"description": "Masters is how many ports see each master, when they do not all agree."
},
"changes": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.Change"
},
"description": "Changes are the master changes seen in the last day, newest first."
},
"declared": {
"type": "array",
"items": {
"type": "string"
},
"description": "Declared are the names nodes gave this fabric; one, when all is well."
},
"members": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.Member"
}
},
"rate_gbps": {
"type": "integer"
},
"gid_prefix": {
"type": "string"
}
}
},
"fabrics.Problem": {
"type": "object",
"description": "Problem is one disagreement, in words.",
"properties": {
"level": {
"type": "string"
},
"fabric": {
"type": "string"
},
"message": {
"type": "string"
}
}
},
"fabrics.Report": {
"type": "object",
"description": "Report is the whole picture.",
"properties": {
"physical": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.Physical"
}
},
"problems": {
"type": "array",
"items": {
"$ref": "#/components/schemas/fabrics.Problem"
}
},
"unverified": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "Unverified are declared fabrics some of whose nodes cannot say which physical fabric they are on, with why."
}
}
},
"fabrics.SM": {
"type": "object",
"description": "SM is a subnet manager as the ports see it.",
"properties": {
"guid": {
"type": "string"
},
"lid": {
"type": "integer"
},
"priority": {
"type": "integer"
},
"state": {
"type": "string"
}
}
},
"guard.Attachment": {
"type": "object",
"description": "Attachment ties a policy to a part of the tenancy tree: scope is org, team, project, user or key, and ScopeID which one.",
"properties": {
"Scope": {
"type": "string"
},
"ScopeID": {
"type": "string"
},
"Policy": {
"type": "string"
}
}
},
"inventory.EngineInstall": {
"type": "object",
"description": "EngineInstall is where one engine's installation stands on a node.",
"properties": {
"engine": {
"type": "string"
},
"version": {
"type": "string"
},
"variant": {
"type": "string"
},
"state": {
"type": "string",
"description": "State is \"installing\", \"ready\", \"failed\" or \"unsupported\"."
},
"detail": {
"type": "string"
}
}
},
"inventory.GPUSensor": {
"type": "object",
"description": "GPUSensor is one card's heat and power, and what is throttling it.",
"properties": {
"index": {
"type": "integer"
},
"temp_c": {
"type": "number"
},
"memory_temp_c": {
"type": "number"
},
"power_w": {
"type": "number"
},
"power_limit_w": {
"type": "number"
},
"throttle": {
"type": "array",
"items": {
"type": "string"
}
},
"util_percent": {
"type": "number",
"description": "How busy the card is, as of this sample; -1 is not reported. Zero MemoryTotalMB is an agent too old to send these, whose figures are the ones it read at registration."
},
"mem_util_percent": {
"type": "number"
},
"memory_used_mb": {
"type": "number"
},
"memory_total_mb": {
"type": "number"
},
"sm_clock_mhz": {
"type": "number"
},
"ecc_uncorrected": {
"type": "number"
},
"wear": {
"$ref": "#/components/schemas/inventory.GPUWear",
"description": "Wear is what wears the card out, read every minute; nil from an agent that does not read it."
}
}
},
"inventory.GPUWear": {
"type": "object",
"description": "GPUWear is a card's wear and failures. Counts of -1 are not reported for it: a card before Ampere has no remapped rows, one after no retired pages.",
"properties": {
"pcie_replays": {
"type": "integer",
"format": "int64"
},
"retired_pages_sbe": {
"type": "integer",
"format": "int64"
},
"retired_pages_dbe": {
"type": "integer",
"format": "int64"
},
"retire_pending": {
"type": "boolean"
},
"remapped_rows_correctable": {
"type": "integer",
"format": "int64"
},
"remapped_rows_uncorrectable": {
"type": "integer",
"format": "int64"
},
"remap_pending": {
"type": "boolean"
},
"remap_failure": {
"type": "boolean"
},
"nvlink_crc_errors": {
"type": "integer",
"format": "int64"
},
"nvlink_replay_errors": {
"type": "integer",
"format": "int64"
},
"nvlink_recovery_errors": {
"type": "integer",
"format": "int64"
},
"xid_errors": {
"type": "integer",
"format": "int64"
},
"last_xid": {
"type": "integer"
},
"last_xid_text": {
"type": "string"
},
"last_xid_at": {
"type": "string",
"format": "date-time"
}
}
},
"modelplan.Option": {
"type": "object",
"description": "Option is one way to run one artifact.",
"properties": {
"artifact": {
"type": "string"
},
"format": {
"type": "string"
},
"engine": {
"type": "string"
},
"cpu": {
"type": "boolean"
},
"gpu_class": {
"type": "string"
},
"fabric": {
"type": "string"
},
"gpus_per_node": {
"type": "integer",
"description": "GPUsPerNode cards on each of Nodes nodes."
},
"nodes": {
"type": "integer"
},
"need_gb": {
"type": "number",
"description": "NeedGB is what one card holds, or for CPU the whole replica in RAM; HaveGB what a card, or the node, offers for it."
},
"have_gb": {
"type": "number"
},
"hosts": {
"type": "integer",
"description": "Hosts is how many nodes could run it at all, and FreeNow whether one (or enough, together) could right now."
},
"free_now": {
"type": "boolean"
},
"bits_per_weight": {
"type": "number",
"description": "BitsPerWeight is the artifact's precision, 0 when unknown."
}
}
},
"modelserve.CanaryView": {
"type": "object",
"description": "CanaryView is one model's canary as it stands.",
"properties": {
"model": {
"type": "string"
},
"canary": {
"$ref": "#/components/schemas/catalog.Canary"
},
"serving": {
"$ref": "#/components/schemas/canary.Stat"
}
}
},
"modelserve.Change": {
"type": "object",
"description": "Change is how an update or a promotion is held to quality.",
"properties": {
"eval": {
"$ref": "#/components/schemas/eval.Request",
"description": "Eval is a suite the new weights must pass first. Nil takes the model's own (eval: in its catalog entry), if it has one."
},
"skip_eval": {
"type": "boolean",
"description": "SkipEval moves without the model's own suite; the job says so."
}
}
},
"modelserve.Job": {
"type": "object",
"description": "Job is one model being served, and where it stands.",
"properties": {
"id": {
"type": "string"
},
"kind": {
"type": "string",
"description": "Kind is \"update\" for a model moved to new weights, empty for one served."
},
"request": {
"$ref": "#/components/schemas/modelserve.Request"
},
"state": {
"type": "string"
},
"error": {
"type": "string"
},
"model": {
"type": "string"
},
"steps": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.Step"
}
},
"started": {
"type": "string",
"format": "date-time"
},
"reply": {
"type": "string",
"description": "Reply is what the model said to the smoke test, and TokensPerSecond how fast it said it."
},
"tokens_per_second": {
"type": "number"
},
"eval": {
"$ref": "#/components/schemas/store.EvalRun",
"description": "Eval is the quality suite the new weights were asked before they replaced the old, and how they scored, without each case."
}
}
},
"modelserve.Plan": {
"type": "object",
"description": "Plan is every way a repository's files could run here, best first.",
"properties": {
"repo": {
"type": "string"
},
"revision": {
"type": "string"
},
"format": {
"type": "string"
},
"architecture": {
"type": "string"
},
"license": {
"type": "string"
},
"params": {
"type": "integer",
"format": "int64"
},
"context": {
"type": "integer"
},
"gated": {
"type": "boolean"
},
"servable": {
"type": "boolean",
"description": "Servable is false when the nodes' engine cannot run the model at all, and Reason says why."
},
"reason": {
"type": "string"
},
"note": {
"type": "string",
"description": "Note is anything the plan could not know, said once."
},
"projectors": {
"type": "array",
"items": {
"type": "string"
}
},
"artifacts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelserve.PlannedArtifact"
}
},
"options": {
"type": "array",
"items": {
"$ref": "#/components/schemas/modelplan.Option"
}
}
}
},
"modelserve.PlannedArtifact": {
"type": "object",
"description": "PlannedArtifact is one file a repository offers, and the best way to run it.",
"properties": {
"name": {
"type": "string",
"description": "Name is the file, or the set's name; for original weights, \"original\"."
},
"format": {
"type": "string",
"description": "\"gguf\" or \"safetensors\""
},
"bytes": {
"type": "integer",
"format": "int64"
},
"shards": {
"type": "integer"
},
"quant": {
"type": "string",
"description": "Quant is the quantisation read from the name, like Q4_K_M; \"bf16\" for original weights."
},
"best": {
"$ref": "#/components/schemas/modelplan.Option"
}
}
},
"modelserve.Request": {
"type": "object",
"description": "Request is what to serve.",
"properties": {
"repo": {
"type": "string",
"description": "Repo is the registry repository, owner/name."
},
"quant": {
"type": "string",
"description": "Quant picks the file by its quantisation, Q4_K_M unless given."
},
"file": {
"type": "string",
"description": "File picks it by name instead."
},
"projector": {
"type": "string",
"description": "Projector is a vision model's mmproj file in the repository, fetched beside the weights and loaded with them; empty serves text alone."
},
"format": {
"type": "string",
"description": "Format is \"gguf\", run by llama.cpp, or \"safetensors\": the original weights with their config and tokenizer, run by vLLM on GPUs of GPUClass, across TP of them."
},
"cpu": {
"type": "boolean",
"description": "Where it runs: on the CPU, or on GPUsPerNode cards of GPUClass on each of Nodes nodes. Left empty, the plan decides: the best way the cluster can run the chosen file. TP is GPUsPerNode's older name."
},
"gpu_class": {
"type": "string"
},
"gpus_per_node": {
"type": "integer"
},
"nodes": {
"type": "integer"
},
"tp": {
"type": "integer"
},
"fallbacks": {
"type": "boolean",
"description": "Fallbacks adds the next best ways, lower in priority, so a model whose first choice is busy runs on another rather than waiting."
},
"name": {
"type": "string",
"description": "Name is the catalog name; the repository suggests one otherwise."
},
"aliases": {
"type": "array",
"items": {
"type": "string"
}
},
"description": {
"type": "string"
},
"replicas": {
"type": "integer",
"description": "Replicas to run; 0 makes it on demand, loaded when first asked for."
},
"guard_format": {
"type": "string",
"description": "GuardFormat makes it a judge model for the guardrails (role: guard): llamaguard3, shieldgemma or json. Empty serves clients."
},
"ctx_pool": {
"type": "integer",
"description": "CtxPool is llama.cpp's --ctx-size; ContextLength what one request may use. They default to 16384 and 4096, what four parallel slots divide."
},
"context_length": {
"type": "integer"
},
"cpu_cores": {
"type": "integer",
"description": "CPUCores is what a replica computes on; zero takes half the smallest node it fits on."
}
}
},
"modelserve.Step": {
"type": "object",
"description": "Step is one stage of a job.",
"properties": {
"name": {
"type": "string"
},
"state": {
"type": "string"
},
"detail": {
"type": "string"
},
"at": {
"type": "string",
"format": "date-time"
}
}
},
"modelserve.UpdateInfo": {
"type": "object",
"description": "UpdateInfo is what the registry has for a model against what it runs.",
"properties": {
"model": {
"type": "string"
},
"repo": {
"type": "string"
},
"current": {
"type": "string",
"description": "Current is the commit the model runs, Latest the repository's now."
},
"latest": {
"type": "string"
},
"changed": {
"type": "array",
"items": {
"type": "string"
},
"description": "Changed are the model's files whose weights differ at Latest, and Missing those Latest no longer has at all."
},
"missing": {
"type": "array",
"items": {
"type": "string"
}
},
"bytes": {
"type": "integer",
"format": "int64",
"description": "Bytes is what an update downloads."
},
"available": {
"type": "boolean",
"description": "Available is true when the model can be moved to Latest."
},
"previous": {
"type": "string",
"description": "Previous is the commit an update replaced, which it can go back to."
},
"checked_at": {
"type": "string",
"format": "date-time"
},
"error": {
"type": "string"
}
}
},
"notify.Result": {
"type": "object",
"description": "Result is how one webhook answered a test.",
"properties": {
"url": {
"type": "string"
},
"error": {
"type": "string"
}
}
},
"nvlink.Domain": {
"type": "object",
"description": "Domain is one multi-node NVLink domain.",
"properties": {
"key": {
"type": "string"
},
"cluster_uuid": {
"type": "string"
},
"clique_id": {
"type": "string"
},
"members": {
"type": "array",
"items": {
"$ref": "#/components/schemas/nvlink.Member"
}
},
"gpus": {
"type": "integer"
},
"joined": {
"type": "integer"
},
"usable_nodes": {
"type": "integer"
}
}
},
"nvlink.GPU": {
"type": "object",
"description": "GPU is one card as its domain sees it.",
"properties": {
"index": {
"type": "integer"
},
"name": {
"type": "string"
},
"state": {
"type": "string"
},
"status": {
"type": "string"
},
"bandwidth": {
"type": "string"
},
"joined": {
"type": "boolean"
}
}
},
"nvlink.Member": {
"type": "object",
"description": "Member is one node of a domain.",
"properties": {
"node": {
"type": "string"
},
"gpus": {
"type": "array",
"items": {
"$ref": "#/components/schemas/nvlink.GPU"
}
},
"usable": {
"type": "boolean",
"description": "Usable is every card joined and IMEX up: what placement requires."
},
"imex": {
"type": "string"
},
"imex_channels": {
"type": "integer"
}
}
},
"nvlink.Problem": {
"type": "object",
"description": "Problem is one thing wrong with a domain.",
"properties": {
"level": {
"type": "string"
},
"domain": {
"type": "string"
},
"message": {
"type": "string"
}
}
},
"nvlink.Report": {
"type": "object",
"description": "Report is every domain and what is wrong with them.",
"properties": {
"domains": {
"type": "array",
"items": {
"$ref": "#/components/schemas/nvlink.Domain"
}
},
"problems": {
"type": "array",
"items": {
"$ref": "#/components/schemas/nvlink.Problem"
}
}
}
},
"promq.Point": {
"type": "object",
"description": "Point is one sample.",
"properties": {
"At": {
"type": "string",
"format": "date-time"
},
"Value": {
"type": "number"
}
}
},
"promq.Series": {
"type": "object",
"description": "Series is one line: a name and its points, oldest first.",
"properties": {
"Name": {
"type": "string"
},
"Points": {
"type": "array",
"items": {
"$ref": "#/components/schemas/promq.Point"
}
}
}
},
"quota.Amount": {
"type": "object",
"description": "Amount is how much of each resource something holds or needs.",
"properties": {
"GPUs": {
"type": "integer"
},
"CPUCores": {
"type": "integer"
},
"MemoryGB": {
"type": "integer"
}
}
},
"store.AuditEvent": {
"type": "object",
"description": "AuditEvent is one change: who made it, through what, to what, and how it ended. Detail never holds a secret; the writer takes them out.",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"at": {
"type": "string",
"format": "date-time"
},
"actor": {
"type": "string"
},
"source": {
"type": "string",
"description": "api, web"
},
"action": {
"type": "string",
"description": "\"POST /api/v1/models\", \"POST /admin/users/{id}/suspend\""
},
"target": {
"type": "string"
},
"detail": {
"type": "string"
},
"status": {
"type": "integer"
}
}
},
"store.EvalCase": {
"type": "object",
"description": "EvalCase is one case of a run: how its answer scored, and why.",
"properties": {
"id": {
"type": "string"
},
"kind": {
"type": "string"
},
"weight": {
"type": "number"
},
"score": {
"type": "number"
},
"passed": {
"type": "boolean"
},
"answer": {
"type": "string"
},
"detail": {
"type": "string"
},
"error": {
"type": "string"
},
"took_ms": {
"type": "integer",
"format": "int64"
}
}
},
"store.EvalRun": {
"type": "object",
"description": "EvalRun is one quality suite run against a model, as `llmgw ctl eval` and the gate on an update keep it.",
"properties": {
"id": {
"type": "string"
},
"model": {
"type": "string",
"description": "Model is the model the run is about; Target the catalog model that answered, when that was another — its canary, or the new weights an update tried before moving to them."
},
"target": {
"type": "string"
},
"repo": {
"type": "string",
"description": "Repo and Revision are where the weights that answered came from, when that is known."
},
"revision": {
"type": "string"
},
"suite": {
"type": "string",
"description": "Suite is its name, SuiteHash the sha256 of its text."
},
"suite_hash": {
"type": "string"
},
"at": {
"type": "string",
"format": "date-time"
},
"took_ms": {
"type": "integer",
"format": "int64"
},
"score": {
"type": "number",
"description": "Score is the cases' scores weighed, 0 to 1; Passed whether it reached Threshold."
},
"threshold": {
"type": "number"
},
"passed": {
"type": "boolean"
},
"cases": {
"type": "integer",
"description": "Cases were asked; Below scored under half; Errors got no answer."
},
"below": {
"type": "integer"
},
"errors": {
"type": "integer"
},
"judge": {
"type": "string"
},
"by": {
"type": "string"
},
"job": {
"type": "string",
"description": "Job is the update or promotion the run gated, if one did."
},
"error": {
"type": "string",
"description": "Error is why the run could not be scored at all."
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/store.EvalCase"
}
}
}
},
"store.ExportRow": {
"type": "object",
"description": "ExportRow is one line of a usage export: a period, the place, person, key and model it is about — those asked for, the rest empty — and what was used.",
"properties": {
"Period": {
"type": "string",
"format": "date-time"
},
"Org": {
"type": "string"
},
"Team": {
"type": "string"
},
"Project": {
"type": "string"
},
"User": {
"type": "string"
},
"Key": {
"type": "string"
},
"Model": {
"type": "string"
},
"Requests": {
"type": "integer",
"format": "int64"
},
"Errors": {
"type": "integer",
"format": "int64"
},
"Limited": {
"type": "integer",
"format": "int64"
},
"Prompt": {
"type": "integer",
"format": "int64"
},
"Completion": {
"type": "integer",
"format": "int64"
},
"CostMicros": {
"type": "integer",
"format": "int64"
}
}
},
"store.RequestBody": {
"type": "object",
"description": "RequestBody is one kept request and its answer.",
"properties": {
"request_id": {
"type": "string"
},
"project_id": {
"type": "string"
},
"at": {
"type": "string",
"format": "date-time"
},
"expires_at": {
"type": "string",
"format": "date-time"
},
"path": {
"type": "string"
},
"model": {
"type": "string"
},
"served_model": {
"type": "string"
},
"status": {
"type": "integer"
},
"request": {
"type": "string"
},
"response": {
"type": "string",
"description": "Response is the answer's text as the client was sent it; Truncated says it was longer than what is kept."
},
"truncated": {
"type": "boolean"
}
}
},
"store.Resources": {
"type": "object",
"description": "Resources are amounts of the three things a replica holds of a cluster. Nil is not governed: nothing guaranteed, or nothing limited.",
"properties": {
"gpus": {
"type": "integer"
},
"cpu_cores": {
"type": "integer"
},
"memory_gb": {
"type": "integer"
}
}
},
"topology.HostView": {
"type": "object",
"description": "HostView is an adapter, and the node it is in when the cluster knows it.",
"properties": {
"guid": {
"type": "string"
},
"desc": {
"type": "string"
},
"node": {
"type": "string"
},
"hca": {
"type": "string"
},
"rail": {
"type": "integer"
},
"leaf": {
"type": "string"
}
}
},
"topology.LinkView": {
"type": "object",
"description": "LinkView is a cable, with what it trained at and whether that is short of its kind.",
"properties": {
"from": {
"type": "string"
},
"from_port": {
"type": "integer"
},
"to": {
"type": "string"
},
"to_port": {
"type": "integer"
},
"rate": {
"type": "string"
},
"gbps": {
"type": "integer"
},
"host": {
"type": "boolean"
},
"degraded": {
"type": "boolean"
}
}
},
"topology.Rail": {
"type": "object",
"description": "Rail is the leaves one rail's adapters reach.",
"properties": {
"index": {
"type": "integer"
},
"leaves": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"topology.SwitchView": {
"type": "object",
"description": "SwitchView is a switch and its place in the tiers.",
"properties": {
"guid": {
"type": "string"
},
"name": {
"type": "string"
},
"tier": {
"type": "integer",
"description": "1 leaf, 2 spine, 3 core"
},
"ports": {
"type": "integer"
},
"used": {
"type": "integer"
},
"lid": {
"type": "integer"
},
"hosts": {
"type": "integer",
"description": "Hosts counts adapters hanging off it."
}
}
},
"topology.View": {
"type": "object",
"description": "View is a fabric's shape, ready to draw.",
"properties": {
"switches": {
"type": "array",
"items": {
"$ref": "#/components/schemas/topology.SwitchView"
}
},
"hosts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/topology.HostView"
}
},
"links": {
"type": "array",
"items": {
"$ref": "#/components/schemas/topology.LinkView"
}
},
"tiers": {
"type": "integer",
"description": "Tiers is how many switch levels: 1 for a single switch, 2 for leaf and spine, 3 with a core."
},
"expected_host_gbps": {
"type": "integer",
"description": "Expected is the rate most links of each kind trained at; a link below it is degraded."
},
"expected_switch_gbps": {
"type": "integer"
},
"degraded": {
"type": "integer"
},
"rails": {
"type": "array",
"items": {
"$ref": "#/components/schemas/topology.Rail"
},
"description": "Rails is, per rail — an adapter's position on its node — the leaves it reaches, and Aligned whether each rail has its own."
},
"rail_aligned": {
"type": "boolean"
},
"notes": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
}