{ "openapi": "3.0.3", "info": { "title": "Wicklee Fleet API", "description": "Sovereign GPU fleet monitor for local AI inference. Monitor WES scores, thermal state, inference efficiency, and hardware health across Ollama and vLLM nodes.", "version": "1.0.0", "contact": { "name": "Wicklee", "url": "https://wicklee.dev" } }, "servers": [ { "url": "https://wicklee.dev", "description": "Production fleet API" }, { "url": "http://localhost:7700", "description": "Local agent API (no auth)" } ], "security": [{ "ApiKeyAuth": [] }], "paths": { "/mcp": { "post": { "operationId": "mcpJsonRpc", "summary": "MCP JSON-RPC 2.0 endpoint", "description": "Model Context Protocol endpoint for AI agents. Supports tools (get_node_status, get_inference_state, get_active_models, get_observations — 18 agent-evaluated patterns; 2 additional cloud-evaluated patterns are queryable via the cloud Observations endpoint, get_metrics_history, get_model_fit) and resources (wicklee://node/metrics, wicklee://node/thermal). Localhost only, no auth required.", "servers": [{ "url": "http://localhost:7700" }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "jsonrpc": { "type": "string", "enum": ["2.0"] }, "method": { "type": "string" }, "params": { "type": "object" }, "id": {} }, "required": ["jsonrpc", "method", "id"] } } } }, "responses": { "200": { "description": "JSON-RPC 2.0 response" } } } }, "/.well-known/mcp.json": { "get": { "operationId": "mcpManifest", "summary": "MCP server discovery manifest", "servers": [{ "url": "http://localhost:7700" }], "responses": { "200": { "description": "MCP server manifest with capabilities, tools, and resources" } } } }, "/metrics": { "get": { "operationId": "prometheusMetrics", "summary": "Prometheus scrape endpoint (Team+ tier)", "description": "Returns fleet metrics in Prometheus text format. 7 gauges per node: gpu_utilization, power_watts, tokens_per_second, wes_score, thermal_penalty, memory_pressure, ttft_ms.", "parameters": [{ "name": "X-API-Key", "in": "header", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Prometheus text format", "content": { "text/plain": {} } }, "401": { "description": "Missing API key" }, "403": { "description": "Team tier required" } } } }, "/api/v1/fleet": { "get": { "operationId": "getFleet", "summary": "Get all fleet nodes with full telemetry", "description": "Returns all nodes belonging to the authenticated user with their latest MetricsPayload.", "responses": { "200": { "description": "Fleet node list", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FleetResponse" } } } }, "401": { "description": "Missing or invalid API key" } } } }, "/api/v1/fleet/wes": { "get": { "operationId": "getFleetWes", "summary": "Get WES scores for all nodes", "description": "Returns WES (Wicklee Efficiency Score) for each node, ranked by score.", "responses": { "200": { "description": "WES scores", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WesResponse" } } } } } } }, "/api/v1/nodes/{nodeId}": { "get": { "operationId": "getNode", "summary": "Get single node deep dive", "parameters": [{ "name": "nodeId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "WK-XXXX" }], "responses": { "200": { "description": "Node with full metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeResponse" } } } }, "404": { "description": "Node not found" } } } }, "/api/v1/route/best": { "get": { "operationId": "getBestRoute", "summary": "Get routing recommendation", "description": "Returns two candidates: latency (highest tok/s) and efficiency (highest WES). Default strategy is efficiency.", "responses": { "200": { "description": "Routing recommendation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RouteResponse" } } } } } } }, "/api/v1/insights/latest": { "get": { "operationId": "getInsights", "summary": "Get fleet intelligence snapshot (Team+)", "description": "Fleet summary with avg WES, total tok/s, and findings array (thermal stress, WES below baseline, etc.).", "responses": { "200": { "description": "Intelligence snapshot", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InsightsResponse" } } } }, "402": { "description": "Requires Team tier or above" } } } }, "/api/v1/keys": { "post": { "operationId": "createApiKey", "summary": "Create a new API key", "description": "Returns the raw key once (prefix wk_live_). Stored as SHA-256 hash.", "responses": { "200": { "description": "API key created" } } }, "get": { "operationId": "listApiKeys", "summary": "List all API keys", "responses": { "200": { "description": "API key list (hashes never exposed)" } } } }, "/api/v1/keys/{keyId}": { "delete": { "operationId": "revokeApiKey", "summary": "Revoke an API key", "parameters": [{ "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Key revoked" } } } }, "/api/sla": { "get": { "operationId": "getInferenceSla", "summary": "Inference SLA Monitor — p50/p95/p99 percentiles", "description": "Returns p50/p95/p99/max for TTFT, end-to-end latency, and TPOT computed via DuckDB quantile_cont() over per-request inference_traces. Compliance percentage against a configurable TTFT target, the 20 most-recent violations, and per-model breakdown. Requires the Ollama proxy (Settings → Proxy) to capture per-request data. Window: 1–1440 minutes (24h hard ceiling — that's the trace retention).", "servers": [{ "url": "http://localhost:7700" }], "parameters": [ { "name": "window_min", "in": "query", "required": false, "schema": { "type": "integer", "default": 60, "minimum": 1, "maximum": 1440 } }, { "name": "target_ttft_ms", "in": "query", "required": false, "schema": { "type": "integer", "default": 500, "minimum": 1 } }, { "name": "model", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Optional model filter — narrows percentiles to a single model name." } ], "responses": { "200": { "description": "SLA summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SlaSummary" } } } } } } }, "/api/v1/thermal-budget": { "get": { "operationId": "getThermalBudget", "summary": "Thermal Budget Calculator (Pro+) — predicts when pushing harder backfires", "description": "Walks the 7-day metrics_5min Postgres rollup, identifies sustained Normal-thermal blocks (≥30 min) and Normal→Fair transitions, computes the sustainable tok/s rate, the load level that pushes the node out of Normal, the average time-to-Fair, and the resulting penalized rate (push ÷ 1.25). Generates a plain-English advice string comparing 1-hour token output of stay-sustainable vs push-then-drop-to-penalized.", "parameters": [ { "name": "node_id", "in": "query", "required": true, "schema": { "type": "string" }, "example": "WK-XXXX" } ], "responses": { "200": { "description": "Thermal budget summary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ThermalBudget" } } } }, "400": { "description": "node_id query param required" }, "401": { "description": "Missing or invalid auth" }, "403": { "description": "Pro tier or higher required" }, "404": { "description": "Node not found in user's fleet" } } } }, "/api/runtime-config": { "get": { "operationId": "getRuntimeConfig", "summary": "Runtime Config Surface (v0.9.0) — cached launch-time config for a model", "description": "Returns the cached RuntimeConfig for the named model. Available across Ollama (parsed from /api/show on model change), vLLM (5-min poller, tries /v1/server_info then falls back to ps aux), and llama.cpp (5-min poller, tries /props then falls back to ps aux). Reads in-memory cache only — never blocks on I/O and works regardless of DuckDB store health. Templates and system prompts stay local — the cloud telemetry push does NOT carry these fields.", "servers": [{ "url": "http://localhost:7700" }], "parameters": [ { "name": "model", "in": "query", "required": true, "schema": { "type": "string" }, "example": "llama3.1:8b" } ], "responses": { "200": { "description": "Cached RuntimeConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RuntimeConfig" } } } }, "400": { "description": "Missing ?model= query param" }, "404": { "description": "No cached config for this model yet" } } } }, "/api/v1/fleet/model-comparison": { "get": { "operationId": "getFleetModelComparison", "summary": "Fleet-wide per-model rollup (WES, tok/s, watts, TTFT, cost)", "description": "Per-model aggregated stats across every node owned by the authenticated tenant. Reads metrics_5min for the long window plus a metrics_raw side query for TTFT (last 24h only). Empty array until new telemetry is ingested under the v0.9.x schema (ollama_active_model column).", "parameters": [ { "name": "hours", "in": "query", "required": false, "schema": { "type": "integer", "default": 168, "minimum": 1, "maximum": 720 } } ], "responses": { "200": { "description": "Per-model rollup", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FleetModelComparison" } } } }, "401": { "description": "Missing or invalid auth" } } } }, "/api/v1/fleet/model-switches": { "get": { "operationId": "getFleetModelSwitches", "summary": "Cross-node model swap events (LAG over metrics_raw)", "description": "Returns model transitions detected via a Postgres LAG window function over metrics_raw partitioned by node_id. Capped at 200 rows.", "parameters": [ { "name": "hours", "in": "query", "required": false, "schema": { "type": "integer", "default": 24, "minimum": 1, "maximum": 168 } } ], "responses": { "200": { "description": "Swap events", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FleetModelSwitches" } } } }, "401": { "description": "Missing or invalid auth" } } } }, "/api/v1/fleet/cost-by-model": { "get": { "operationId": "getFleetCostByModel", "summary": "Fleet-wide per-model power cost", "description": "Cost = avg_watts x hours_active x $0.16 / 1000. Uses metrics_raw at 30s granularity.", "parameters": [ { "name": "hours", "in": "query", "required": false, "schema": { "type": "integer", "default": 24, "minimum": 1, "maximum": 168 } } ], "responses": { "200": { "description": "Per-model cost rollup", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FleetCostByModel" } } } }, "401": { "description": "Missing or invalid auth" } } } }, "/api/v1/webhooks": { "post": { "operationId": "createWebhook", "summary": "Threshold Webhooks (Pro+) — create subscription", "description": "Register a webhook for state-transition push notifications (thermal_state_changed, inference_state_changed, wes_below, wes_above). Returns the HMAC-SHA256 secret ONCE — store it. Receivers verify the X-Wicklee-Signature header to confirm authenticity.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookBody" } } } }, "responses": { "200": { "description": "Subscription created (secret returned ONCE)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookSubscription" } } } }, "400": { "description": "Invalid url, event_type, or missing required threshold" }, "401": { "description": "Missing or invalid auth" }, "403": { "description": "Pro tier or higher required" }, "404": { "description": "Specified node_id not found in user's fleet" } } }, "get": { "operationId": "listWebhooks", "summary": "List your webhook subscriptions (no secrets)", "responses": { "200": { "description": "Subscription list", "content": { "application/json": { "schema": { "type": "object", "properties": { "subscriptions": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookSubscription" } } } } } } } } } }, "/api/v1/webhooks/{id}": { "delete": { "operationId": "deleteWebhook", "summary": "Remove a webhook subscription", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Subscription deleted" }, "404": { "description": "Subscription not found" } } } }, "/api/v1/webhooks/{id}/test": { "post": { "operationId": "testWebhook", "summary": "Fire a synthetic test payload to a subscription's URL", "description": "Sends a synthetic webhook payload to the subscription's configured URL with a valid HMAC signature. Use to verify your receiver before relying on real condition triggers.", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Test delivered", "content": { "application/json": { "schema": { "type": "object", "properties": { "delivered": { "type": "boolean" }, "status": { "type": "integer", "description": "Receiver's HTTP response status" } } } } } }, "404": { "description": "Subscription not found" }, "502": { "description": "Receiver unreachable or returned non-2xx" } } } } }, "components": { "securitySchemes": { "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "X-API-Key" } }, "schemas": { "FleetResponse": { "type": "object", "properties": { "nodes": { "type": "array", "items": { "$ref": "#/components/schemas/FleetNode" } } } }, "FleetNode": { "type": "object", "properties": { "node_id": { "type": "string", "example": "WK-XXXX" }, "hostname": { "type": "string", "example": "macmini.local" }, "online": { "type": "boolean" }, "last_seen_ms": { "type": "integer", "format": "int64" }, "metrics": { "$ref": "#/components/schemas/MetricsPayload" } } }, "WesResponse": { "type": "object", "properties": { "nodes": { "type": "array", "items": { "type": "object", "properties": { "node_id": { "type": "string" }, "online": { "type": "boolean" }, "wes": { "type": "number", "format": "float" } } }} } }, "NodeResponse": { "type": "object", "properties": { "node_id": { "type": "string" }, "hostname": { "type": "string" }, "online": { "type": "boolean" }, "last_seen_ms": { "type": "integer", "format": "int64" }, "metrics": { "$ref": "#/components/schemas/MetricsPayload" } } }, "RouteResponse": { "type": "object", "properties": { "latency": { "$ref": "#/components/schemas/RouteCandidate" }, "efficiency": { "$ref": "#/components/schemas/RouteCandidate" }, "default": { "type": "string", "enum": ["latency", "efficiency"] } } }, "RouteCandidate": { "type": "object", "properties": { "node": { "type": "string" }, "tok_s": { "type": "number", "format": "float" }, "wes": { "type": "number", "format": "float" }, "reason": { "type": "string" } } }, "InsightsResponse": { "type": "object", "properties": { "generated_at_ms": { "type": "integer", "format": "int64" }, "fleet": { "type": "object", "properties": { "online_count": { "type": "integer" }, "total_count": { "type": "integer" }, "avg_wes": { "type": "number", "format": "float" }, "fleet_tok_s": { "type": "number", "format": "float" } } }, "findings": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } } } }, "Finding": { "type": "object", "properties": { "node_id": { "type": "string" }, "hostname": { "type": "string" }, "severity": { "type": "string", "enum": ["low", "medium", "high"] }, "pattern": { "type": "string" }, "title": { "type": "string" }, "detail": { "type": "string" }, "value": { "type": "number", "format": "float" }, "unit": { "type": "string" } } }, "SlaSummary": { "type": "object", "properties": { "window_minutes": { "type": "integer" }, "request_count": { "type": "integer" }, "error_count": { "type": "integer" }, "error_rate_pct": { "type": "number", "format": "float" }, "ttft": { "$ref": "#/components/schemas/SlaPercentiles" }, "e2e": { "$ref": "#/components/schemas/SlaPercentiles" }, "tpot": { "$ref": "#/components/schemas/SlaPercentiles" }, "sla": { "type": "object", "properties": { "target_ttft_ms": { "type": "integer" }, "compliance_pct": { "type": "number", "format": "float" }, "violations_count": { "type": "integer" }, "violations": { "type": "array", "items": { "$ref": "#/components/schemas/SlaViolation" } } } }, "by_model": { "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "count": { "type": "integer" }, "p95_ttft_ms": { "type": "number", "format": "float" }, "p95_e2e_ms": { "type": "number", "format": "float" } } } } } }, "SlaPercentiles": { "type": "object", "properties": { "p50": { "type": "number", "format": "float" }, "p95": { "type": "number", "format": "float" }, "p99": { "type": "number", "format": "float" }, "max": { "type": "number", "format": "float" } } }, "SlaViolation": { "type": "object", "properties": { "ts_ms": { "type": "integer", "format": "int64" }, "model": { "type": "string" }, "ttft_ms": { "type": "integer" }, "latency_ms": { "type": "integer" } } }, "ThermalBudget": { "type": "object", "properties": { "node_id": { "type": "string" }, "samples_analyzed": { "type": "integer" }, "transitions_detected": { "type": "integer" }, "confidence": { "type": "string", "enum": ["insufficient", "low", "medium", "high"] }, "sustainable_tps": { "type": "number", "format": "float", "description": "Max tok/s sustained during any Normal-thermal block ≥30 min" }, "sustainable_watts": { "type": "number", "format": "float" }, "push_threshold_tps": { "type": "number", "format": "float", "nullable": true, "description": "Median tok/s in 10 min before any Normal→Fair transition" }, "push_threshold_watts": { "type": "number", "format": "float", "nullable": true }, "time_to_fair_min": { "type": "number", "format": "float", "nullable": true, "description": "Avg duration of Normal blocks before Fair transition (minutes)" }, "fair_penalized_tps": { "type": "number", "format": "float", "nullable": true, "description": "push_threshold_tps ÷ 1.25 — effective rate once Fair triggers" }, "advice": { "type": "string", "description": "Plain-English 1-hour-output comparison: stay-sustainable vs push-then-drop" } } }, "CreateWebhookBody": { "type": "object", "required": ["url", "event_type"], "properties": { "url": { "type": "string", "format": "uri", "example": "https://your-server.example.com/wicklee-hook" }, "event_type": { "type": "string", "enum": ["thermal_state_changed", "inference_state_changed", "wes_below", "wes_above"] }, "node_id": { "type": "string", "nullable": true, "description": "Omit to fire for any node owned by the user" }, "threshold": { "type": "number", "format": "float", "nullable": true, "description": "Required for wes_below / wes_above" }, "cooldown_s": { "type": "integer", "minimum": 10, "default": 60, "description": "Min seconds between fires per (subscription, node) pair" } } }, "WebhookSubscription": { "type": "object", "properties": { "id": { "type": "string" }, "url": { "type": "string" }, "event_type": { "type": "string" }, "node_id": { "type": "string", "nullable": true }, "threshold": { "type": "number", "format": "float", "nullable": true }, "cooldown_s": { "type": "integer" }, "enabled": { "type": "boolean" }, "last_fired_ms": { "type": "integer", "format": "int64", "nullable": true }, "secret": { "type": "string", "description": "HMAC-SHA256 secret returned ONLY at creation. Used to verify X-Wicklee-Signature on incoming webhook calls." } } }, "RuntimeConfig": { "type": "object", "properties": { "model": { "type": "string", "example": "llama3.1:8b" }, "runtime": { "type": "string", "enum": ["ollama", "vllm", "llamacpp"] }, "captured_at_ms": { "type": "integer", "format": "int64" }, "context_length": { "type": "integer", "format": "int64", "nullable": true }, "n_gpu_layers": { "type": "integer", "nullable": true }, "quantization": { "type": "string", "nullable": true, "example": "Q4_K_M" }, "parameter_count": { "type": "integer", "format": "int64", "nullable": true }, "template": { "type": "string", "nullable": true, "description": "Ollama only. Stays local — never pushed to cloud." }, "system_prompt": { "type": "string", "nullable": true, "description": "Ollama only. Stays local — never pushed to cloud." }, "process_args": { "type": "array", "items": { "type": "string" }, "nullable": true, "description": "vLLM / llama.cpp — full command-line args." }, "raw": { "type": "object", "nullable": true, "description": "Full raw runtime-introspection response." } } }, "FleetModelComparison": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "hours_active": { "type": "number", "format": "double" }, "avg_tok_s": { "type": "number", "format": "float", "nullable": true }, "avg_watts": { "type": "number", "format": "float", "nullable": true }, "wes": { "type": "number", "format": "float", "nullable": true }, "avg_ttft_ms": { "type": "number", "format": "float", "nullable": true }, "cost_per_hour": { "type": "number", "format": "double", "nullable": true }, "total_cost": { "type": "number", "format": "double", "nullable": true }, "sample_count": { "type": "integer", "format": "int64" } } }} } }, "FleetModelSwitches": { "type": "object", "properties": { "swaps": { "type": "array", "items": { "type": "object", "properties": { "ts_ms": { "type": "integer", "format": "int64" }, "node_id": { "type": "string" }, "from_model": { "type": "string", "nullable": true }, "to_model": { "type": "string" }, "gap_ms": { "type": "number", "format": "double" } } }}, "total_swaps": { "type": "integer", "format": "int64" }, "total_gap_ms": { "type": "number", "format": "double" }, "total_gap_minutes": { "type": "number", "format": "double" } } }, "FleetCostByModel": { "type": "object", "properties": { "models": { "type": "array", "items": { "type": "object", "properties": { "model": { "type": "string" }, "hours_active": { "type": "number", "format": "double" }, "avg_watts": { "type": "number", "format": "float", "nullable": true }, "cost_usd": { "type": "number", "format": "double" }, "tok_s_avg": { "type": "number", "format": "float", "nullable": true }, "sample_count": { "type": "integer", "format": "int64" } } }}, "total_cost_usd": { "type": "number", "format": "double" } } }, "MetricsPayload": { "type": "object", "description": "Full telemetry payload. All fields optional (null when unavailable).", "properties": { "node_id": { "type": "string" }, "hostname": { "type": "string" }, "inference_state": { "type": "string", "enum": ["live", "idle-spd", "busy", "idle"] }, "thermal_state": { "type": "string", "enum": ["Normal", "Fair", "Serious", "Critical"] }, "thermal_source": { "type": "string", "enum": ["nvml", "iokit", "coretemp", "clock_ratio", "sysfs", "wmi"] }, "penalty_avg": { "type": "number", "format": "float" }, "cpu_usage_percent": { "type": "number", "format": "float" }, "memory_pressure_percent": { "type": "number", "format": "float" }, "gpu_utilization_percent": { "type": "number", "format": "float" }, "apple_soc_power_w": { "type": "number", "format": "float" }, "nvidia_power_draw_w": { "type": "number", "format": "float" }, "nvidia_gpu_temp_c": { "type": "number", "format": "float" }, "ollama_running": { "type": "boolean" }, "ollama_active_model": { "type": "string" }, "ollama_tokens_per_second": { "type": "number", "format": "float" }, "ollama_ttft_ms": { "type": "number", "format": "float" }, "vllm_running": { "type": "boolean" }, "vllm_model_name": { "type": "string" }, "vllm_tokens_per_sec": { "type": "number", "format": "float" }, "vllm_avg_ttft_ms": { "type": "number", "format": "float" }, "vllm_requests_waiting": { "type": "integer" }, "runtime_config_available": { "type": "boolean", "description": "v0.9.0+ — true when the agent has at least one cached RuntimeConfig. Fetch via GET /api/runtime-config?model=." }, "agent_version": { "type": "string" }, "timestamp_ms": { "type": "integer", "format": "int64" } } } } } }