jgeiser's picture
Wicklee fleet demo (static build from main)
01560d7
|
Raw History Blame Contribute Delete
11 kB
# Wicklee API Reference
## Localhost Agent API
Base URL: `http://localhost:7700`
Auth: None required.
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /api/metrics | SSE stream — 1 Hz telemetry with full MetricsPayload |
| GET | /ws | WebSocket — 1 Hz live telemetry (same payload as SSE, fallback transport) |
| GET | /api/observations | 18 agent-evaluated patterns with routing_hint per observation + node-level routing_hint/routing_hint_source. (2 additional cloud-evaluated patterns are queryable via the cloud Observations endpoint.) |
| GET | /api/history?node_id=WK-XXXX | Metric history — 1h raw samples |
| GET | /api/profile?minutes=60 | Inference Profiler — correlated TTFT/KV/queue/thermal/power timeline |
| GET | /api/sla?window_min=60&target_ttft_ms=500 | Inference SLA Monitor — p50/p95/p99 for TTFT, E2E latency, TPOT plus compliance vs target |
| GET | /api/v1/thermal-budget?node_id=X | Thermal Budget Calculator (Pro+, cloud) — sustainable rate, push threshold, time-to-Fair, penalized rate, plain-English advice |
| POST/GET/DELETE | /api/v1/webhooks[/:id[/test]] | Threshold Webhooks (Pro+) — push notifications on thermal/inference state changes and WES threshold crossings. HMAC-SHA256 signed |
| GET | /api/health (localhost) | Agent diagnostic — agent version, build target, DuckDB store health, list of routes available/unavailable when store init failed. One-curl debug for "why are my routes missing?" |
| GET | /api/cost-by-model?hours=24 | Cost attribution per model — daily power cost breakdown |
| GET | /api/explain-slowdown?ts_ms=N | Slowdown explainer — root cause analysis for a slow request |
| GET | /api/model-comparison?hours=168 | Model comparison — side-by-side efficiency for every model that has run |
| GET | /api/model-switches?hours=24 | Model switching cost — swap frequency, idle gap per transition |
| GET | /api/model-candidates?search=llama&limit=20 | Model discovery — GGUF models from HuggingFace scored against local hardware |
| GET | /api/runtime-config?model=X | Runtime Config Surface (v0.9.0) — cached launch-time config for a named model (Ollama, vLLM, llama.cpp). 200 with JSON, 400 if `?model=` missing, 404 if not yet cached. Templates and system prompts stay local — never pushed to the fleet. |
| GET | /api/traces | Proxy inference traces |
| GET | /api/events/history | Node event log |
| GET | /api/events/recent | Recent in-memory events |
| GET | /api/export?format=json\|csv | Data export |
| GET | /api/tags | Ollama model tags |
| GET | /api/pair/status | Pairing status |
| POST | /api/insights/dismiss | Permanently dismiss a pattern |
| GET | /api/insights/dismissed | List dismissed patterns |
| POST | /mcp | MCP (Model Context Protocol) JSON-RPC 2.0 endpoint |
| GET | /.well-known/mcp.json | MCP server manifest |
## MCP (Model Context Protocol)
The agent exposes a local MCP server for AI agents (Cursor, Claude Desktop, custom agents).
**Endpoint:** `POST http://localhost:7700/mcp`
**Protocol:** JSON-RPC 2.0
**Auth:** None (localhost only)
### Tools
| Tool | Description |
|------|-------------|
| `get_node_status` | Full hardware + inference metrics snapshot |
| `get_inference_state` | Live/idle/busy state with sensor context |
| `get_active_models` | Running models across Ollama, vLLM, llama.cpp |
| `get_observations` | Server-side pattern evaluation — 17 agent-evaluated observations (live data) |
| `get_metrics_history` | 1-hour rolling telemetry buffer |
### Resources
| URI | Description |
|-----|-------------|
| `wicklee://node/metrics` | Live MetricsPayload JSON |
| `wicklee://node/thermal` | Thermal state + WES penalty values |
### Connect to Claude Desktop
Open the config file in your terminal:
```bash
# macOS
nano "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
# Linux
nano ~/.config/Claude/claude_desktop_config.json
# Windows (PowerShell)
notepad "$env:APPDATA\Claude\claude_desktop_config.json"
```
Add the `wicklee` entry inside `mcpServers` (create the file if it doesn't exist):
```json
{
"mcpServers": {
"wicklee": {
"command": "/opt/homebrew/bin/npx",
"args": ["-y", "mcp-remote", "http://localhost:7700/mcp"],
"env": {
"HOME": "/Users/YOUR_USERNAME",
"PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
}
}
}
}
```
Requires Node.js. Use `which npx` to find the correct npx path. Fully quit Claude Desktop (Cmd+Q) and relaunch after editing.
### Connect to Claude Code
```bash
claude mcp add -s user wicklee -- npx -y mcp-remote http://localhost:7700/mcp
```
### Cursor
Edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project). Add `wicklee` to `mcpServers`:
```json
"wicklee": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:7700/mcp"]
}
```
### Windsurf
Edit `~/.codeium/windsurf/mcp_config.json`. Add `wicklee` to `mcpServers`:
```json
"wicklee": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:7700/mcp"]
}
```
All setups require Node.js for the mcp-remote bridge. Restart your IDE after configuration changes.
### Test with curl
```bash
curl -X POST http://localhost:7700/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_inference_state"},"id":1}'
```
## Fleet API v1
Base URL: `https://wicklee.dev/api/v1`
Auth: `X-API-Key: wk_live_...` header.
| Method | Endpoint | Description | Tier |
|--------|----------|-------------|------|
| GET | /api/v1/fleet | All nodes with full MetricsPayload | All |
| GET | /api/v1/fleet/wes | WES scores ranked | All |
| GET | /api/v1/nodes/{id} | Single node deep dive | All |
| GET | /api/v1/route/best | Routing recommendation (latency or efficiency). Optional `?model=` for per-model routing | All |
| GET | /api/v1/models/discover | Model discovery — browse catalog, `?simulate_hw=` (Pro+), `?fleet=true` (Team+) | Tiered |
| GET | /api/v1/fleet/model-comparison?hours=168 | Fleet-wide per-model rollup (WES, tok/s, watts, TTFT, cost). Reads `metrics_5min`. 1–720 hour window. | All |
| GET | /api/v1/fleet/model-switches?hours=24 | Cross-node model swap events (LAG window function over `metrics_raw`). 1–168 hour window, capped at 200 rows. | All |
| GET | /api/v1/fleet/cost-by-model?hours=24 | Fleet-wide per-model power cost using $0.16/kWh default. 1–168 hour window. | All |
| GET | /api/v1/insights/latest | Fleet intelligence snapshot | Team+ |
| GET | /api/v1/fleet/chargeback?days=30 | Chargeback/showback (Clerk JWT auth) — cost + $/1M-token attribution by team tag / model / node + daily trend. `&format=csv&group=` for finance export (audited) | Team+ |
| GET | /api/v1/fleet/capacity?target_tok_s=200 | Capacity planner with procurement scenarios (Clerk JWT auth) — "reach 200 tok/s: 2× RTX 4090 vs 1× H100" priced from the fleet's own measured tok/W per hardware class; every scenario states its basis | Team+ |
| GET | /api/v1/fleet/migration-advisor | Cross-node model migration (Clerk JWT auth) — live WES vs peers' 7-day demonstrated WES + free memory; moves with ≥20% estimated gain and 1.2× headroom | Team+ |
| GET | /api/v1/fleet/idle-waste?days=30 | Idle-waste & right-sizing report (Clerk JWT auth) — phantom-load cost + recovery actions (unload idle model, consolidate) with projected $/mo recovery | Team+ |
| GET/PUT | /api/digest | Weekly idle-waste email digest settings (Clerk JWT auth) — Resend-delivered, one per tenant, audited | Team+ |
| POST | /api/v1/keys | Create API key | All |
| GET | /api/v1/keys | List API keys | All |
| DELETE | /api/v1/keys/{id} | Revoke API key | All |
| GET | /metrics | Prometheus scrape endpoint (text format) | Team+ |
| GET | /api/otel/config | OpenTelemetry export configuration | Team+ |
| PUT | /api/otel/config | Update OTel export settings | Team+ |
## Response Examples
### GET /api/v1/fleet/wes
```json
{
"nodes": [
{ "node_id": "WK-XXXX", "online": true, "wes": 15.0 },
{ "node_id": "WK-99E9", "online": true, "wes": 3.2 }
]
}
```
### GET /api/v1/route/best
```json
{
"latency": { "node": "WK-99E9", "tok_s": 31.9, "wes": 3.3, "reason": "Highest throughput" },
"efficiency": { "node": "WK-XXXX", "tok_s": 19.5, "wes": 15.0, "reason": "Highest WES" },
"default": "efficiency"
}
```
### GET /api/runtime-config?model=llama3.1:8b
```json
{
"model": "llama3.1:8b",
"runtime": "ollama",
"captured_at_ms": 1774622475195,
"context_length": 131072,
"n_gpu_layers": 33,
"quantization": "Q4_K_M",
"parameter_count": 8030261312,
"template": "{{ if .System }}<|system|>{{ .System }}{{ end }}...",
"system_prompt": "You are a helpful assistant."
}
```
### GET /api/v1/fleet/model-comparison?hours=168
```json
{
"models": [
{ "model": "llama3.1:70b", "hours_active": 18.3, "avg_tok_s": 22.5, "avg_watts": 95.0, "wes": 0.24, "avg_ttft_ms": 245, "cost_per_hour": 0.0152, "total_cost": 0.278, "sample_count": 219 },
{ "model": "phi3:mini", "hours_active": 42.0, "avg_tok_s": 85.1, "avg_watts": 12.0, "wes": 7.09, "avg_ttft_ms": 34, "cost_per_hour": 0.0019, "total_cost": 0.081, "sample_count": 504 }
]
}
```
### GET /api/v1/fleet/model-switches?hours=24
```json
{
"swaps": [
{ "ts_ms": 1774621630223, "node_id": "WK-XXXX", "from_model": "llama3.1:70b", "to_model": "phi3:mini", "gap_ms": 3200 }
],
"total_swaps": 14,
"total_gap_ms": 480000,
"total_gap_minutes": 8.0
}
```
### GET /api/v1/fleet/cost-by-model?hours=24
```json
{
"models": [
{ "model": "llama3.1:70b", "hours_active": 6.2, "avg_watts": 95.0, "cost_usd": 0.0942, "tok_s_avg": 22.5, "sample_count": 744 }
],
"total_cost_usd": 0.221
}
```
### GET /api/v1/insights/latest
```json
{
"generated_at_ms": 1774624251478,
"fleet": { "online_count": 3, "total_count": 3, "avg_wes": 9.9, "fleet_tok_s": 79.0 },
"findings": [{
"node_id": "WK-99E9",
"hostname": "spark-c559",
"severity": "low",
"pattern": "wes_below_baseline",
"title": "WES below fleet average",
"detail": "WES 3.3 vs fleet average 9.9",
"value": 3.3,
"unit": "WES"
}]
}
```
## Key Metrics
| Field | Type | Description |
|-------|------|-------------|
| inference_state | string | "live" \| "idle-spd" \| "busy" \| "idle" |
| ollama_tokens_per_second | f32 | tok/s from 20-token probe (≤ every 10 min) |
| apple_soc_power_w | f32 | Combined CPU+GPU+ANE (Apple Silicon) |
| nvidia_power_draw_w | f32 | Board power (NVIDIA) |
| thermal_state | string | "Normal" \| "Fair" \| "Serious" \| "Critical" |
| penalty_avg | f32 | Thermal penalty (1.0 = no penalty) |
| ollama_ttft_ms | f32 | TTFT from probe baseline |
| vllm_avg_ttft_ms | f32 | TTFT from production histogram |
| vllm_requests_waiting | u32 | Queue depth |
## WES Formula
```
WES = tok/s / (Watts x ThermalPenalty)
```
Normal thermal (penalty=1.0): WES = tok/s / Watts = tok/W.
Color scale: >10 Excellent (emerald) · 3-10 Good (green) · 1-3 Acceptable (yellow) · <1 Low (red)