Files
prose-contracts/gpu-monitor.prose.md
T
root d829f595b4
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Failing after 13m1s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Has been skipped
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Has been skipped
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Has been skipped
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Has been skipped
fix: IP drift and container count from live testing
Testing the consolidated litellm-self-heal contract against live infra found:
- IP drift: pi host is .24, not .65 (confused with ra-h-os bridge)
  - Fixed gpu-monitor.prose.md: 192.168.68.65 → 192.168.68.24 (3 locations)
  - Fixed gpu-fleet.prose.md: .65 → .24 in config files + agent keys tables
- Container count: 10 running on CT 116, not 8 as contract stated
  - Added harness-docker-stats + harness-pve-exporter to litellm-self-heal
  - Updated container health check list

Verified: GPU monitor restarted on .24:9100, ornith model inference working,
all 10 containers healthy.
2026-07-09 06:23:44 +00:00

5.9 KiB

kind, name, description, agent
kind name description agent
responsibility gpu-monitor Comprehensive GPU fleet monitor — polls every subsystem (sidecars, router, LiteLLM, Strix Halo, dashboard) every 15s, renders a live HTML dashboard, checks alert thresholds, and exposes a JSON API for downstream consumers. abiba

Maintains

  • gpu-fleet-data: { gpus: array, strix: object, router: object, litellm: object, summary: object, alerts: array } — Full fleet snapshot refreshed every 15s
  • dashboard: live HTML at /root/dashboard/gpu-fleet.html, served on port 9100
  • gpu-data-api: JSON at GET /gpu-data on port 9100
  • health-endpoint: GET /health on port 9100 → 200 if cache populated, 503 if warming up

GPU Fleet Topology

┌─────────────────────────────────────────────────────────┐
│  GPU Monitor Server (:9100) — 192.168.68.24              │
│  Polls every 15s, serves dashboard + JSON API            │
└──┬──────────┬──────────┬────────────────────────────────┘
   │          │          │
   ▼          ▼          ▼
┌──────┐ ┌──────┐ ┌────────┐
│.8:8080│ │.110  │ │.116:80 │
│RTX3090│ │:8080 │ │nginx   │
│gemma  │ │RTX5070│ │router  │
└──────┘ │qwen27B│ │LiteLLM │
         └──────┘ │dashboard│
                  └────────┘

Note: JSON sidecar exporters at :8090 were never deployed on any
GPU host. Router falls back to GPU /health direct probe. Monitor
should use router /health/unified as source of truth for GPU status.
Strix Halo :8080 is firewalled to .116 only — monitor on .24 cannot
poll .15:8080 directly; must go through router on .116.

Subsystems Polled

Subsystem Endpoint Frequency Metrics
GPU Status (all, via router) http://192.168.68.116/health/unified 15s models, CB, scores, GPU status (router probes each GPU /health directly)
Router (unified) http://192.168.68.116/health/unified 15s models, CB, scores, GPU status
Router (basic) http://192.168.68.116/health 15s basic aliveness
LiteLLM http://192.168.68.116/litellm/health 15s proxy health, model count
Strix Halo http://192.168.68.116/health/unified (router) 15s ornith status via router — cannot poll .15:8080 directly (firewalled to .116 only)
Dashboard http://192.168.68.116/dashboard/ 15s harness-dashboard aliveness

Alert Delivery

All alerts are sent to #agent-hub stream topics:

  • alerts-gpu — GPU fleet alerts (temp, VRAM, utilization)
  • alerts-pm2 — PM2 process health (restarts, crashes)
  • alerts-infra — Infrastructure health (LiteLLM, Zulip, containers)

This replaces the previous DM-only delivery. All agents on the mesh can see and respond to alerts.

Alert Thresholds

Metric Warning Critical
GPU Temp >80°C >90°C
VRAM Usage >90% >95%
GPU Util >95% >98%
Sidecar Unreachable info (sidecars not deployed — use router /health/unified)
Model Down critical (circuit breaker open)

JSON API Response Schema (/gpu-data)

{
  "gpus": [{ "name", "gpu_name", "temp_c", "vram_used_mb", "vram_total_mb",
             "gpu_util_pct", "power_w", "power_limit_w", "fan_pct",
             "models", "hostname", "active_requests", "health_score",
             "circuit_open" }],
  "strix": { "status", "cpu_load", "llama_health" },
  "router": { "available_models", "circuit_breaker", "gpus", "scores",
              "status", "redis", "_basic" },
  "litellm": { ... },
  "dashboard": { "reachable": bool },
  "summary": { "fleet_status", "models_available", "models_total",
               "circuit_breakers_open", "gpu_count", "gpu_errors",
               "strix_running", "router_reachable", "litellm_reachable" },
  "alerts": [{ "gpu", "metric", "level", "value", "threshold" }],
  "updated": "ISO8601",
  "monitor_version": "2.0.0"
}

Operations

list

curl http://localhost:9100/gpu-data | jq — Full fleet status

check-health

curl http://localhost:9100/health — Monitor self-check

view-dashboard

Open http://localhost:9100/ in browser — Live HTML dashboard

restart

pkill -f gpu-monitor-server.py
python3 /root/scripts/gpu-monitor-server.py &

Or via PM2: pm2 restart gpu-monitor

check-router

The router health is accessed through nginx on port 80 (NOT port 9000 directly). curl http://192.168.68.116/health/unified — Router unified health via nginx proxy curl http://192.168.68.116:9000/health/unified WILL FAIL (port bound to 127.0.0.1 only)

Configuration Files

File Host Purpose
/root/scripts/gpu-monitor-server.py pi (.24) Monitor server v2.0.0
/root/dashboard/gpu-fleet.html pi (.24) Live HTML dashboard
/etc/nginx/nginx.conf CT 116 Routes /health/* → router

Execution

  1. Poll router (every 15s): GET .116/health/unified — single source of truth for all GPU status (router probes each GPU /health directly via sidecar fallback)
  2. Poll router (every 15s): GET .116/health via nginx:80
  3. Poll LiteLLM (every 15s): GET .116/litellm/health via nginx:80
  4. Poll Strix (every 15s): via router /health/unified (cannot poll .15:8080 directly — firewalled to .116 only)
  5. Poll dashboard (every 15s): GET .116/dashboard/
  6. Check alerts: Compare metrics against thresholds
  7. Compute summary: Fleet-wide health aggregation
  8. Render dashboard: Generate HTML at /root/dashboard/gpu-fleet.html
  9. Serve API: HTTP server on port 9100
  10. Repeat every 15 seconds