Adds a stdlib HTTP control plane that wraps scripts/switch.sh so a harness
can POST /switch and block until the new model is serving. Introduces no new
orchestration logic — switch.sh stays the single source of truth (registry
lookup, down/up, readiness).
- tools/model-switch/server.py: GET /healthz|/status|/models, POST /switch
({slug}|{model}); registry-validated; /health readiness (works with or
without VLLM_API_KEY); single-flight lock; refuses to start unauthenticated
on a non-loopback bind.
- scripts/systemd/club3090-model-switch.service: host daemon unit.
- scripts/tests/test-model-switch.sh: hermetic HTTP/auth/validation contract.
- docs/EXAMPLES.md, .env.example: usage + config.
Mirrors the existing stdlib HTTP style (services/studio/*); zero new deps.
Experimental/opt-in per the repo's staging convention.
scripts/gpu-mode.sh `power-cap on` restarts nvidia-power-cap.service as
the single-source-of-truth enforcer, but the repo never shipped the unit
— so the path silently fell back to a direct `nvidia-smi -pl 230` and no
cap survived reboot.
Ship the Type=oneshot unit (250W both 3090s — the rtx-3090.yml
`power_cap_w_prefill` point; higher caps trigger GPU1 fall-off-bus on the
X670E rig). Ordered After=gpu-tune.service so on rigs where another
oneshot also sets -pl at boot, this unit is the last writer; After= on an
absent unit is a no-op, so the file stays portable. See #483.
Co-authored-by: Alex <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>