Commit Graph
33 Commits
Author SHA1 Message Date
394ec87dae fix(ai-studio): derive ComfyUI paths from MODEL_DIR + make gpu-mode portable (#493)
setup-ai-studio.sh's director download honored MODEL_DIR, but the ComfyUI
assets (image/video/audio) defaulted to a hardcoded /mnt/models/comfyui — so
any rig whose models don't live under /mnt failed mid-download with
"mkdir: Permission denied" (sumo Discord report, 2026-06-27). Two more walls
behind it: the disk-space preflight checked the hardcoded /mnt path and had no
override (an idempotent resume under-threshold was blocked), and gpu-mode.sh —
which setup calls at step 3 — hardcoded CLUB3090_DIR=/opt/ai/github/club-3090,
breaking on any other clone.

- New services/comfyui/comfyui-paths.sh: derive COMFYUI_ROOT / COMFYUI_MODELS_DIR
  as a "comfyui" sibling of MODEL_DIR (read from repo-root .env when unset).
  Backward-compatible on the rig (/mnt/models/huggingface -> /mnt/models/comfyui);
  explicit overrides respected. Sourced by setup-ai-studio.sh,
  download_studio_models.sh, and gpu-mode.sh so the download target, the disk
  check, and the container mounts all agree.
- setup-ai-studio.sh: disk check uses the derived path; add SKIP_DISK_CHECK=1 to
  bypass the free-space preflight independently of SKIP_DOWNLOAD.
- gpu-mode.sh: auto-detect CLUB3090_DIR from the script's real location (resolving
  the /usr/local/bin symlink), overridable via env — removes the hardcoded path.
- The 3 legacy hardcoded download scripts (flux2/hunyuan_llava/models) honor
  COMFYUI_MODELS_DIR.
- New test-comfyui-paths.sh guards the derivation; docs/ai-studio config note.

Full suite green (59/59).


Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-27 13:08:07 +05:00
a839f34604 gpu-mode: align power-cap default 230W -> 250W (completes #483) (#489)
The nvidia-power-cap.service unit shipped in #485 caps both cards at 250W (rtx-3090.yml prefill operating point), but gpu-mode.sh's comments, echoes, and the service-missing fallback (-pl 230) all still said 230W. Align them so the messaging + fallback match the unit.


Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-26 21:11:49 +05:00
47ac38385a Director placement lever: CPU / GPU0 / GPU1 (c3 Settings) (#473)
* Director placement lever: env-driven CPU / GPU0 / GPU1 (backend)

The studio director's GPU/CPU placement is now a single lever,
STUDIO_DIRECTOR_DEVICE (gpu0 | gpu1 | cpu, default gpu0), read from the rig
.env by gpu-mode's start_studio_director and translated into the compose
env (-ngl + CUDA_VISIBLE_DEVICES + device_ids):

- gpu0 (default): -ngl 99, GPU0 — fast craft (~50-100 tok/s), ~4.6 GB,
  coexists with the image lanes. Unchanged from before.
- gpu1: -ngl 99, GPU1 — only when GPU1 has room (NOT during a video render;
  GPU1 is the DisTorch DiT donor).
- cpu: -ngl 0, CUDA_VISIBLE_DEVICES="" — frees ~4.6 GB off GPU0 (lifts the
  single-card Wan window 121→161 frames) at ~single-digit tok/s craft.

Compose now reads ${DIRECTOR_NGL:-99} + ${STUDIO_DIRECTOR_CUDA-0} (no-colon
so an explicit empty value = CPU survives). Default (no override) preserves
current GPU0 behaviour exactly.

Live-validated: CPU mode starts with GPU0 full (gemma12b), adds 0 MiB VRAM
to GPU0, serves on :8090, generates (~5 tok/s CPU). The c3 Settings field
that writes STUDIO_DIRECTOR_DEVICE follows in the next commit.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* c3 Settings: Director placement (CPU / GPU0 / GPU1) + CPU thread cap

Exposes the director-placement lever in the c3 Settings modal so users pick
GPU0 (fast, default) / GPU1 / CPU without hand-editing the .env.

- services.py: director_device() reads STUDIO_DIRECTOR_DEVICE from the repo
  .env (default gpu0, validates the value); set_repo_env_var() upserts a key
  in place (preserves other lines, no duplicates, creates the file if absent).
- app.py: SettingsScreen gains a "Director placement" Select; apply_settings
  persists the choice to the repo .env (the SHARED config gpu-mode reads —
  distinct from c3-settings.json for MODEL_DIR/HF_TOKEN). Applies on the next
  ai-studio start.
- compose: CPU thread cap — -t ${DIRECTOR_THREADS:-8} bounds CPU use so the
  director doesn't starve OWUI's embedder/reranker (also CPU). The ~2.6 GB
  GGUF loads into system RAM (mmap'd; resident in page cache, not run from SSD).
- tests: +6 data-layer (TestDirectorPlacement) + 1 headless apply-settings
  round-trip (persists STUDIO_DIRECTOR_DEVICE, idempotent re-apply). Full
  suite green (728), settings/director subset 13/13.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* tests: fix stale scene names in gpu-mode-list EXPECT

The scene catalog renamed its dispatch keywords to qwen27b / gemma-31b,
but the test's EXPECT spot-check map still referenced the old 27b / gemma
short names — so the JSON-shape assertion had been red on master. Point
EXPECT at the canonical names the catalog now emits.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* studio: run director in chat scene as the catalog-support layer

Bring the uncensored director up in the `chat` scene (honoring the
STUDIO_DIRECTOR_DEVICE placement knob), framing chat as the supporting-
infra home — OWUI + LiteLLM + Qdrant + SearXNG + director — for ad-hoc
Catalog models launched via `switch.sh --owui`.

A CPU-placed director uses no GPU, so it's the always-on path: it survives
scene switches and stays live in OWUI. New _director_evict_if_gpu helper
frees only a GPU-resident director when a dual-card LLM scene claims the
cards; mode_off stops it outright. Also brings mode_gemma_int8 in line with
its dual-card siblings (it was missing the studio teardown entirely).

Docs: requirements.md gains a "Chat scene — the Catalog-support layer"
section + reframes director placement around the unified knob / c3 Setting;
video.md note synced.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* studio: disable director thinking on CPU only (latency)

The uncensored director is an "Aggressive" reasoning fine-tune that emits
a full <think> trace before every answer. On GPU that's cheap and the
trace lands in reasoning_content (content stays clean), so leave it on.
On CPU (~14 tok/s) the trace dominates latency, so gpu-mode now passes
`--jinja --reasoning off` for the cpu placement only — forcing the
template's enable_thinking=false (this fine-tune ignores /no_think and
--reasoning-budget 0, but honors --reasoning off).

Wired via a new DIRECTOR_THINK_ARGS compose param (empty on GPU). Live:
CPU director now answers in one pass, no reasoning trace, craft quality
intact (full cinematic spec, finish=stop).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* c3: Containers-pane director start honors placement + enumerate sidecars

Two consistency fixes for the Containers tab:

1. Starting studio-director from Containers now honors STUDIO_DIRECTOR_DEVICE
   instead of falling back to the GPU0/thinking-on compose default. New
   director_compose_env() mirrors gpu-mode's start_studio_director translation
   (NGL/CUDA/GPU/THINK_ARGS), injected as an `env K=V …` prefix on the compose
   up cmd (process env wins over --env-file). cpu → -ngl 0 + --reasoning off.

2. The nested studio sidecars (director/gallery/orchestrator/image-shim/
   step-voice/tts) now enumerate when STOPPED, so they're startable rows — not
   only visible while running. New STUDIO_SIDECARS map is the single SoT for
   resolving the container-name → services/studio/<sub>/ project (fixing the
   director↔enhancer name mismatch that previously returned None → docker
   restart, which fails on a fresh install).

+8 tests (director_compose_env cpu/gpu, director resolves to enhancer with the
env prefix, sidecar enumeration). Live: c3 service_start plan starts the director
CPU + no-think (argv -ngl 0 --reasoning off, GPU0 free, clean generation).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

---------

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-25 09:01:46 +05:00
e8b7fa1317 Lazy-load step-voice + scene-wire it into ai-studio (#471)
* Lazy-load the step-voice service + scene-wire it into ai-studio

Make the premium-voice lane "just work" in the studio without pre-pinning
GPU1: the step-voice container is now part of the ai-studio scene, but the
~14 GB Step-Audio-EditX model loads on first use instead of at boot, and is
evicted before a video render so it never OOMs against the LTX/Wan DiT
(both want GPU1, the DisTorch donor is ~21.9 GB).

server.py — lazy lifecycle (STEP_VOICE_LAZY=1, default):
- model loads on the FIRST /clone or /edit (lock-guarded), not at import →
  the container boots at ~0 GB GPU, so the OWUI voice lane appears as soon
  as ai-studio starts it (the pipe gates the lane on :8193 reachability).
- new POST /unload frees the model from GPU; an idle-unload timer
  (STEP_VOICE_IDLE_UNLOAD_S, default 300 s) reclaims GPU1 automatically.
- /health reports {ready, loaded, lazy}; transcribe+clone moved off the
  event loop into the worker. STEP_VOICE_LAZY=0 restores eager boot.

build_studio_pipe.py / studio_pipe.py — deterministic voice⊕video mutex:
- video lanes (ltx/sulphur/10eros/wan) POST /unload before submitting the
  render, so a freshly-used voice model can't collide with the video DiT.

gpu-mode.sh — scene wiring:
- start_step_voice in mode_ai_studio (lazy → cheap); stop_step_voice
  wherever stop_comfyui is called (every LLM scene + mode_off) so GPU1 is
  freed for a dual-card model. ai-studio --list-modes row + helpers added.

docker-compose.yml — STEP_VOICE_LAZY + STEP_VOICE_IDLE_UNLOAD_S env,
restart policy note (scene-managed), header rewritten for lazy behaviour.

Live-validated via the real compose (--build bakes server.py): lazy boot
loaded:false @ ~4 MiB GPU1, first /clone loads (~13 GB) + clean audio,
POST /unload frees back to ~0, reload clean; gemma12b on GPU0 untouched.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

* ai-studio scene: start qdrant (OWUI's vector DB) + list it

Every model scene starts qdrant (start_service qdrant) but mode_ai_studio
didn't — it predates OWUI's Qdrant vector-DB wiring. So in ai-studio OWUI
ran without its vector store started by the scene (document RAG / web-search
embeddings would have no backend on a clean ai-studio launch from mode_off).

Add start_service qdrant to mode_ai_studio and qdrant:6333 to its
--list-modes service/port row, so it actually starts AND shows up in c3's
ai-studio scene preview alongside studio-step-voice.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

---------

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-25 07:14:35 +05:00
19ccf3a0bc Add gemma12b single-card gpu-mode scene + litellm route (#469)
New `gpu-mode gemma12b` scene (alias gemma-12b) serves
vllm/gemma-12b-single-int8-mtp on :8038 — Gemma 4 12B (gemma4_unified
arch) AutoRound INT8 + bf16 KV + MTP n=2, single card (frees the other
GPU). Stops all dual models + ai-studio on entry; the single-card stop
is folded into the shared stop_all_gemma helper so every other model
scene auto-evicts it, with an explicit line in mode_gemma_int8 (the one
mode that doesn't call stop_all_gemma).

Wires it end-to-end: --list-modes TSV + JSON row (c3 Operate picks it
up), :8038 status probe, all-off detection chain, usage help, and a
litellm gateway route gemma-4-12b-int8 -> :8038.

Live-validated: boots and serves gemma-4-12b-int8 on :8038, coherent
completion direct and through the litellm gateway (:4000).

Note: the gemma4_unified image tag is ephemeral (arch-preview) — pin a
digest before treating this scene as durable.


Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-25 05:22:01 +05:00
noonghunna 33a1f71c81 gpu-mode: rename model scenes to qwen27b / qwen35b-a3b / gemma-31b
More descriptive scene names (the bare 27b/gemma were ambiguous). New canonical
names in the dispatch + the --list-modes TSV (what c3 Operate displays) + help;
OLD names kept as aliases so `gpu-mode 27b` / `gemma` / `35b-a3b` (+ a3b/35b)
still work — zero broken muscle memory.

  27b      → qwen27b      (alias: 27b)
  35b-a3b  → qwen35b-a3b  (alias: 35b-a3b, a3b, 35b)
  gemma    → gemma-31b    (alias: gemma)

c3 reads --list-modes dynamically + invokes scenes by that name, so it shows
the new names and runs `gpu-mode qwen27b` with no code change. deckard unchanged.
bash -n clean; --list-modes carries the new names.
2026-06-24 21:20:14 +00:00
noonghunna 9f1f3a9e37 gpu-mode: add the 35b-a3b scene (parity with 27b/gemma/deckard)
qwen3.6-35b-a3b-autoround had a litellm route (:8051) + was serveable via c3
Run·Catalog, but had no gpu-mode SCENE — so it never appeared in c3's Operate
scene list, unlike the other three LLMs.

Adds the full scene: A3B_DUAL_DIR, start/stop_35b_a3b_dual helpers (on the
production slug vllm/qwen-35b-a3b-dual, dual/autoround-int4/fp8.yml, :8051),
mode_35b_a3b, the `35b-a3b|a3b|35b` dispatch, the --list-modes TSV row (so it
shows in c3 Operate), the :8051 status probe, and a help line. Cross-mode stops:
every model mode (27b/gemma/deckard/ai-studio/off) now stops 35b-a3b so a switch
doesn't OOM — and mode_27b was also missing stop_deckard, fixed here too. litellm
:8051 route already correct.

Live-validated: `gpu-mode 35b-a3b` stops the running model + starts
vllm-qwen36-35b-a3b-dual on :8051; --list-modes --json carries the scene;
bash -n clean; no undefined start/stop/mode calls remain.
2026-06-24 21:14:14 +00:00
noonghunna 2b17aa5070 gpu-mode: fix gpu-mode gemma (undefined fn aborted before start) + litellm port
Switching to gemma stopped 27b but never started gemma. Root cause: `set -e`
+ mode_gemma_int8 called three functions deleted when the dflash/awq gemma
scenes were pruned (stop_gemma_dflash / _dflash_int8 / _awq) — the first
undefined call (`stop_gemma_dflash: command not found`) aborted the function
*after* the 27b teardown but *before* start_gemma_int8. Exactly the reported
"27b unloads, gemma fails to load".

- mode_gemma_int8: drop the 3 undefined calls; add the DEFINED stop_gemma_int8
  (clean re-switch). Live-validated: `gpu-mode gemma` now starts
  vllm-gemma-4-31b-mtp-int8 on :8032 and serves.
- Finish the partial prune: remove the 3 dead/unreachable gemma modes
  (mode_gemma_dflash / _dflash_int8 / _awq — 0 dispatch refs) that referenced
  the same deleted functions, + the orphaned GEMMA_DUAL_AWQ_DIR. No dangling
  refs remain; bash -n clean.
- litellm: gemma-4-31b-autoround route :8030 → :8032 (the :8030 gemma-mtp scene
  was pruned; the live scene serves :8032). End-to-end OWUI→litellm→gemma = 200.
2026-06-24 20:32:37 +00:00
noonghunnaandClaude Opus 4.8 3fc26857f2 studio: consolidate image/video into one ai-studio gpu-mode scene
Replace the separate `image-studio` / `video-studio` / `comfyui` scenes with
a single `ai-studio` scene: ComfyUI holds both GPUs always, and image / video /
audio are picked as *lanes* in OWUI rather than gpu-mode switches. Removes the
gemma-12b chat brain from the studio bundle (kept on disk, just unwired) and
points OWUI's DEFAULT_MODELS at the qwen director.

- gpu-mode.sh: `mode_ai_studio` replaces the two studio modes; drop the gemma
  start/stop + the GPU0-pin split; preflight now reads the shared manifest.
- scripts/lib/studio-models.tsv: single source-of-truth model manifest (modality,
  label, root, rel_path, size, installer) consumed by both gpu-mode preflight and
  the c3 cockpit, so the two can't drift.
- download_{director,video,audio,ace_step,stable_audio,studio}_models.sh: idempotent
  fetchers; download_studio_models.sh orchestrates "grab everything".
- setup-video-studio.sh + repointed setup-image-studio.sh → `gpu-mode ai-studio`.
- litellm: drop the gemma-4-12b :8069 route; comfyui compose/entrypoint GPU-pin
  comments corrected (no scene sets the pin now).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EfF565T9eSLaqGzidyJ1Pm
2026-06-23 23:43:12 +00:00
noonghunnaandClaude Opus 4.8 757c1daba3 studio: preflight the models before starting (gpu-mode + cockpit)
gpu-mode only STARTS the studio bundle; the models are fetched by
setup-image-studio.sh. So `gpu-mode image-studio` (or the cockpit, which calls
gpu-mode) on a box that skipped the installer booted broken services. Gate both
paths on the models being present.

- gpu-mode: preflight_studio_models() runs at the top of mode_image_studio /
  mode_video_studio — checks the director GGUF (both) + the Ideogram set (image),
  and on a miss prints `Fix: bash scripts/setup-image-studio.sh` and refuses to
  start, instead of tearing down the LLMs then booting weightless containers.
  Mirrors preflight_compose_deps; skip with STUDIO_NO_PREFLIGHT=1.
- cockpit: the studio guard now checks studio_ready() = comfyui-local image AND
  the director GGUF on disk (was image-only), so it catches a missing director
  BEFORE the scene-switch confirm. Cached flag renamed _comfyui_ready →
  _studio_ready; STUDIO_DIRECTOR_REL kept in lock-step with the setup download +
  the gpu-mode preflight.

Full cockpit suite 706 passed; bash gates 56/0.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PoXV1FuKmTiDPB15qQvLjB
2026-06-23 01:13:34 +00:00
noonghunnaandClaude Opus 4.8 cae021d6ea cockpit/gpu-mode: comfyui engine label, drop power-cap strip + solo scene, list studio sidecars
Four changes from review:
1. comfyui shows engine "comfyui" (not the generic "studio") — both running
   (_docker_ps_stack_containers) and stopped (_merge_known_services); other GPU
   rig services / studio stacks stay "studio".
2. Orchestration: remove the bottom Power-cap strip — the cap already shows on the
   GPU cards at the top ("(cap NNNW)"), so the strip duplicated it. populate_power_cap
   keeps caching the per-GPU cap for the cards; the [c] menu still adjusts it.
3. gpu-mode: remove the standalone `comfyui` scene (mode_comfyui + dispatch + TSV
   row + usage help) — comfyui runs via image-studio / video-studio now. test EXPECT
   + cockpit _STUDIO_SCENES updated.
4. Containers now lists the STOPPED studio sidecars (studio-director/-gallery/
   -orchestrator/-image-shim/-tts) + comfyui: _stopped_studio_containers reads
   `docker container ls -a` for scene-managed service/stack containers that exist but
   aren't running and aren't top-level services/ dirs (engines excluded as noise).
   [s] on them uses service_start_or_restart — compose-up for a real service dir,
   `docker restart` for an existing sidecar (its dir name ≠ container name).

Full cockpit suite 702 passed; bash gates 56/0.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PoXV1FuKmTiDPB15qQvLjB
2026-06-23 00:33:32 +00:00
noonghunnaandClaude Opus 4.8 9b73a4ccfd stack: remove retired ollama service entirely
Ollama was dropped from serving 2026-05-10 (Qwen/Gemma route through LiteLLM
directly), but its services/ollama/ compose dir was kept "for manual spin-up" —
so the cockpit Containers tab (which lists every services/*/docker-compose.yml)
surfaced it as a stopped service that nothing in the stack starts. Remove it.

- Delete services/ollama/.
- gpu-mode.sh: drop the 9 defensive `stop_service ollama` calls, the :11434
  status readout, and fix the stale `chat` usage-help line (it listed Ollama +
  omitted SearXNG; the authoritative scene TSV was already correct).
- services/openwebui: drop the dead OLLAMA_BASE_URL env; set ENABLE_OLLAMA_API
  =false so Open WebUI doesn't probe a now-dead :11434 on boot.
- cockpit services.py: drop ollama from the supporting-service docstring/comment
  examples (it's no longer a known service).

The SERVICES=() array already excluded ollama, so no scene behaviour changes.
bash gates 56/0; cockpit container/known-service tests green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PoXV1FuKmTiDPB15qQvLjB
2026-06-22 22:02:32 +00:00
noonghunnaandClaude Opus 4.8 7bca67cbde gpu-mode: collapse the gemma scenes to just 'gemma'
gemma-int8 was a literal alias for gemma (same INT8 PTH container :8032), and
gemma-mtp (the bf16/32K/no-overlay fallback) isn't needed as a scene.  Keep only
the 'gemma' scene (INT8 PTH KV, 262K, vision, :8032 — mode_gemma_int8).

Removed: the gemma-int8 + gemma-mtp TSV rows, their dispatch cases + help lines,
mode_gemma (the bf16 fallback mode) and start_gemma_mtp.  Kept stop_gemma_mtp /
stop_gemma_int8 / stop_all_gemma — mode_off + the other gemma modes call them to
defensively tear down a stray bf16/int8 gemma container (the bf16 compose stays
serveable via its catalog slug).

test-gpu-mode-list EXPECT trimmed; repo gates 56/0.  Cockpit untouched (the scene
table is data-driven — the dropped scenes just disappear from --list-modes).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 17:44:02 +00:00
noonghunnaandClaude Opus 4.8 5fb22527c2 gpu-mode scenes: regroup (serving→models), drop bigmodel + diffusiongemma
Scene-catalog cleanup for the Orchestration tab (maintainer-directed):

- Regroup: 'serving' group → 'models'; 'chat' moves serving→ops (browser-chat
  infra, no GPU model); 'diffusiongemma' moves studio→models (it IS a model).
  Groups are now models / studio / ops.  gpu-mode's plain + --json renders are
  data-driven, so this is a TSV edit + the contract comment.
- Remove 'bigmodel': it was ~redundant with 'off' (both stop everything).  Its one
  useful extra — the freed VRAM/RAM readout — is folded into mode_off; the cache
  drop was marginal (Linux auto-reclaims page cache; nothing for VRAM) and the
  llama-server hint belongs in docs.
- Remove the 'diffusiongemma'/'dgemma' SCENE (TSV/dispatch/help/mode_/start_): a
  niche dLLM whose scene duplicated the catalog slug vllm/diffusiongemma-dual (the
  way to serve it).  stop_diffusiongemma is KEPT — mode_off + the studio modes
  call it to defensively clear a stray dgemma container.
- Cockpit scene filter switched from "ops-except-off" to a deny-list of the COMMAND
  modes (power-cap / prune / prune-all) so 'chat' (now ops) still shows; off/chat +
  models/studio scenes appear, the command-modes don't.

Updated test-gpu-mode-list EXPECT/GROUPS + the cockpit filter test.  Repo gates
56/0; cockpit suite 673 (+1 skip) unchanged (cockpit code untouched by the
gpu-mode.sh scene removals).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 17:37:09 +00:00
noonghunnaandClaude Opus 4.8 38227cea93 c3 Orchestration: power-cap menu, remove prune, move cap-sweep to Doctor
Reworks the Orchestration tab's control set per maintainer direction:

- Power cap → a MENU ([c] opens PowerCapMenuScreen) instead of a stateful on/off
  toggle: [d] apply default cap (230W) · [u] clear cap (uncap to hw default) ·
  [m] custom wattage (type a value).  Each choice routes through the standard
  confirm gate.  gpu-mode.sh power-cap now ALSO accepts a numeric wattage (applied
  to both cards, validated against each card's [min,max]); power_cap_set(<W>)
  builds it.  (The menu blurs its Input on open + uses priority shortcut bindings
  so d/u/m reach the screen — a focused Input otherwise swallows printable keys.)
- Prune / prune-all REMOVED from the cockpit (was Orchestration-only): binding,
  action, palette entry, help/footer text, the prune() service method + its tests.
  `gpu-mode prune[-all]` stays on the CLI for manual cleanup.
- Power-cap SWEEP [w] moved Orchestration → Doctor (a tuning/diagnostic bench, not
  a live-estate control): context-gate → tab-doctor, action guard updated, surfaced
  in the Doctor hint + help.
- Help/docstrings refreshed (Orchestration + the stale Doctor help line now lists
  the real v/V/R/F verbs + the relocated [w]).

Scene start/stop path unchanged (⏎ → reconcile-gated scene_switch → gpu-mode
<mode>).  +3 power-cap tests (menu→default/clear/custom, cap-sweep on Doctor),
power_cap_set custom-wattage + reject-invalid tests; per-tab check_action updated.
Suite: serve-cockpit 670 (+1 skip), tui-core 66.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-22 16:17:59 +00:00
noonghunnaandClaude Opus 4.8 d09a063317 Phase 2b: add --json/CLI contracts to 7 stack scripts (additive)
Data-layer contracts the cockpit (and any jq user) consumes — all strictly
additive (existing human output byte-identical), full guard suite green (54/54):
- registry-emit.sh --json : {variants,defaults,profiles{engines,models,hardware,drafters}}
- tools/kv-calc.py --fit <slug|model> --card <gpu> --json : structured fit verdict
- gpu-mode.sh --list-modes [--json] : scene catalog (serving/studio/ops)
- estate_cli.py report-state/diagnose --json : structured estate read
- pull.sh --profile-like --dry-run --json : structured swap_path (not a message blob)
- health.sh CONTAINER= : Doctor probes any engine container (was qwen36-27b-hardcoded)
- switch.sh --explain <slug> [--json] : joined registry/engine/model/hw/drafter + fit + bench

Built + adversarially reviewed via workflow. The review caught a real
switch<->kv-calc seam defect (switch fed hyphenated 'rtx-3090', kv-calc matched
only 'rtx3090' -> fit silently 'unavailable' on the 3090 rig); fixed: kv-calc
accepts hyphenated hardware-profile ids + hyphen-strip fallback; switch surfaces
kv-calc's structured verdict regardless of RC and renders its real keys; both
tests now exercise the seam. No shared-module edits.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-18 08:43:00 +00:00
ae91f70bef docs: relocate Studio docs into docs/ai-studio/ + add overview & audio (#386)
Groups all Club 3090 AI Studio docs under docs/ai-studio/ and fills the
gaps (no front-door overview; audio undocumented; image doc stale).

- NEW docs/ai-studio/README.md — the high-level overview: the director-driven
  flow, the full 8-lane matrix, lanes-vs-modes, the shared substrate
  (director/gallery/orchestrator/shim/tts/step-voice/gpu-mode), the VRAM
  truth, productization framing.
- NEW docs/ai-studio/audio.md — voices (Kokoro narration), premium voice
  (Step-Audio-EditX clone+edit), music (ACE-Step), SFX (Stable Audio). Notes
  the future Understand pillar (ASR/diarize/separate) kept in private design.
- docs/ai-studio/image.md (was IMAGE_STUDIO.md) — REFRESHED to the current
  lanes: HiDream-O1 + Ideogram-4 + Chroma + the native-button shim (the old
  doc still described the retired gemma-12b image-studio mode).
- docs/ai-studio/video.md (was VIDEO_STUDIO.md) — TRIMMED to video-only;
  image/audio sections moved to their own docs; cross-links added.
- Rewrote every reference across the repo (~13 files: root README, FAQ, docs
  index, gpu-mode.sh, the pipe builder + studio service composes/py) to the
  new paths. docs/README.md index gains the overview + audio entries.

LOCAL_AI_PRIMER.md stays at docs/ (general). The realtime voice-agent design
stays private until built.

Co-authored-by: noonghunna <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
2026-06-12 03:18:57 +05:00
noonghunnaandClaude Opus 4.8 a63f3a391c studio: integrated voices for video — Kokoro TTS + layer-aware audio mixdown
Phase 3a of the Studio audio plan: a voiceover layer for the video lanes
(not a dedicated audio mode). Add a "voiceover: …" / 'narration: "…"' /
"say: …" directive to the message and the pipe generates a voice and mixes
it over the rendered clip.

New service services/studio/tts/ (:8192, aiohttp):
- Kokoro-82M (ONNX) on CPU — never touches the GPUs, ~1-2 s to synth a
  sentence, zero VRAM pressure (better than the original "small TTS on
  GPU0" plan). Runs after the render.
- Layer-aware ffmpeg mixdown, Path A: keep LTX/Sulphur's native ambient as
  the bed, mix the voice over it, DUCK the bed under the voice
  (sidechaincompress), loudness-normalize the master (loudnorm -16 LUFS),
  cap audio to the clip length. Structured around an ordered layer list so
  generated music / SFX (the future audio-studio) slot in without a rewrite
  — only the voice layer is filled today. Honours the pro sound-design order
  (bed -> SFX -> voice -> mix) the user flagged.

Pipe v0.9.0:
- _narration() parses the spoken line out of the message (and strips it from
  the video prompt / duration parse); _narrate() POSTs /narrate after the
  render (both single-clip and long-clip paths); silent-clip fallback if the
  TTS service is down. Valves: enable_narration, tts_url, narrate_voice.
- gpu-mode video-studio starts studio-tts.

Two gotchas found + fixed: os.replace /tmp->/output is cross-device (use
shutil.move); sidechaincompress ends when the shorter input (the voice) runs
out, truncating the mux — apad the voice so the sidechain spans the clip,
then -t caps to the video duration.

Validated on the rig: /tts 1.7 s CPU; /narrate mixes the voice over a real
LTX-audio clip, ducked + normalized, duration-matched. Model files
(kokoro-v1.0.onnx + voices-v1.0.bin) obtained separately into
models/tts/kokoro/ — see docs/VIDEO_STUDIO.md "Integrated audio".

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 23:46:22 +05:00
noonghunnaandClaude Opus 4.8 468d9de0b2 studio: fix OWUI native 🖼️ image button via ComfyUI reverse-proxy shim
OWUI's native image button sends plain text to Ideogram-4, which is trained
on structured JSON captions and renders an "Image blocked by safety filter"
placeholder for off-schema input. OWUI's own image-prompt-generation can't
fix it: it returns {"prompt":"<string>"} and nesting the Ideogram JSON inside
that string defeats the task models (gemma-12b 0/3, qwen-4b 1/3 valid escapes).

Add services/studio/image-shim/ (:8191) — a transparent ComfyUI reverse-proxy.
OWUI's COMFYUI_BASE_URL points at it and OWUI image-prompt-generation is turned
off, so the raw prompt reaches the shim. The shim proxies everything through
(including the /ws progress socket) EXCEPT POST /prompt: there it reads the
plain-text prompt node, asks the director (qwen :8090) for a rich Ideogram-4
JSON caption, and rewrites the node — escaping done in Python (reliable), so the
model never produces nested JSON. Retries the director once; populated-caption
fallback if it's unusable. Blast radius = image gen only; OWUI title/tag/etc.
task-generation is untouched (this is a ComfyUI proxy, not a task-model override).

Wiring:
- gpu-mode video-studio + image-studio start the shim; image-studio also starts
  the director (qwen GPU0 ~4.6GB) it depends on.
- services/openwebui/imagegen.env: COMFYUI_BASE_URL -> :8191,
  ENABLE_IMAGE_PROMPT_GENERATION=false (fresh deploys; existing volumes set it in
  the DB / Admin -> Images).
- docs/VIDEO_STUDIO.md "Native image button" + README image-shim row.

Validated on the rig end-to-end through the shim's /prompt: plain "a mountain
landscape at sunrise" / "a serene lake" / a logo all render clean (the director
crafts the caption); shim passthrough (/system_stats, /history, /view) + /ws relay
work; OWUI container reaches the shim at the configured base_url.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 22:04:09 +05:00
noonghunnaandClaude Opus 4.8 0bb33c80b5 fix(gpu-mode): stop gemma-4-12b chat in video-studio + comfyui modes
mode_video_studio and mode_comfyui both claim to free the GPUs for
all-GPU rendering, but called only stop_all_gemma — which covers the
31B vLLM gemmas (mtp/int8), not the gemma-4-12b llama.cpp chat brain
that image-studio pins to GPU1. So an image-studio -> video-studio (or
-> comfyui) switch left gemma-4-12b resident: ~14 GB stuck on GPU1.

Measured on the rig: after `gpu-mode video-studio` GPU1 still held
13988 MiB (gemma PID unchanged across the switch). A video render's
DisTorch donor needs ~21.9 GB on GPU1 -> 14 + 21.9 = OOM. The bug only
bites the cross-mode path (image-studio is the only mode that starts
the 12b chat), which is exactly the path the unified-Studio switching
work exercises.

Fix: add stop_gemma_12b_chat to both modes, matching what
mode_diffusiongemma and mode_image_studio's siblings already do.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 19:26:17 +05:00
noonghunnaandClaude Opus 4.8 6ef96ffc44 studio: in-chat 60s+ via orchestrator (auto-chain segments -> one video)
Wires the proven extend-chain into the chat flow. The OWUI pipe can't ffmpeg or
read the output dir, so a small host-side orchestrator service owns the chaining:

- services/studio/orchestrator/ (Dockerfile python+ffmpeg, orchestrator.py, compose):
  async job API on :8190. POST /extend {prompt,lane,segments,frames} -> job_id;
  GET /job/<id> -> {status,progress,filename}. Renders seg1 t2v -> extracts last
  frame -> i2v segN -> ffmpeg-concat -> one mp4 in ComfyUI's output dir (gallery-served).
  No GPU (ComfyUI does the work); always-on sidecar.
- Pipe: parses a duration from the user's text ('a 40-second ...'); >15s -> calls the
  orchestrator, streams 'segment k/N', returns one combined video. Falls back to a
  single capped clip if the orchestrator is unreachable. <=15s unchanged.
- gpu-mode video-studio now starts the orchestrator too.
- docs/VIDEO_STUDIO.md + README: orchestrator in the diagram + 'Longer videos' section.

Validated end-to-end: 2-segment job via the orchestrator API -> 20.1s combined clip,
clean join (forest-path neutral prompt). Builds on the seamless-join finding from
extend_chain. Capped at max_seconds (default 120s / 12 segments).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 17:49:49 +05:00
noonghunnaandClaude Opus 4.8 86f7e5e835 studio: video lane (LTX-2.3 / Sulphur) — Director pipe, gallery, gpu-mode, docs
Brings the chat-driven video studio into the repo (was ad-hoc /tmp + manual
containers). Open WebUI -> a 'director' LLM crafts a casual prompt into a
cinematic spec -> ComfyUI renders text/image->video with audio on LTX-2.3
(stock) or Sulphur (uncensored), the 22B DiT split across both 3090s via
DisTorch.

New:
- services/studio/build_studio_pipe.py (+ generated studio_pipe.py): the OWUI
  Function. Two lanes x t2v/i2v. Craft-and-go (no approval gate) + conversational
  refine: it shows the crafted prompt and carries it forward so a follow-up
  ('make it night') evolves it. Single-stage 8-step graph (the 2-stage dev path
  injects a lattice-mesh artifact on this hardware) in workflows/.
- services/studio/gallery/: always-on nginx (:8189) over ComfyUI's output dir, so
  media + links survive ComfyUI being down (with HTTP Range for video seeking).
- services/studio/enhancer/: the director LLM (:8090, GPU0), OpenAI-compatible.
- scripts/gpu-mode.sh: 'video-studio' mode = ComfyUI (both GPUs) + director +
  gallery + Open WebUI as one unit.
- docs/VIDEO_STUDIO.md (+ index): architecture, lanes, the measured length ceiling
  (10s crisp / 15s cap / 20s collapses), VRAM split, model manifest, uncensored note.

Measured on 2x 3090: default 241 frames (~10s), hard-capped 361 (~15s) — a 20s
single pass silently corrupts. VRAM is not the limiter (weights on GPU1 ~22GB;
GPU0 compute ~14GB). The uncensored capability is in the model weights (Sulphur
DiT + director); point the pipe's chat_model valve at a stock LLM to craft via an
aligned model, the DiT still renders uncensored.

Refs #475 (gpu-mode video-studio), #477 (commit the studio). Pipe/gallery
live-validated; director crafting + frame sweep verified.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 17:21:21 +05:00
noonghunnaandClaude Opus 4.8 f8ad9a01c1 gpu-mode: add dgemma mode (DiffusionGemma 26B-A4B dLLM, dual-card)
Adds `gpu-mode dgemma` (alias `diffusiongemma`): stops all other GPU models
(it's TP=2, both cards — shared 8199 slot with deckard) then launches the
DiffusionGemma compose (base.yml, PORT=8199) + wires it into Open WebUI.
Mirrors mode_deckard. Also stops it in mode_off.

Dual-card, so before switching to another model run `gpu-mode off` first
(single-card modes don't individually stop it — noted in usage). The mode
launches whatever base.yml is on the tree (the official :gemma image once
the dgemma image-adoption PR lands).

Validated live on 2x RTX 3090: `gpu-mode dgemma` stops peers, recreates the
container, starts services, owui-registers :8199, serves. bash -n clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 05:46:30 +00:00
noonghunnaandClaude Opus 4.8 1cee8eb43d gpu-mode: add deckard mode (uncensored 40B, dual-card)
`gpu-mode` is a fixed mode dispatcher; there was no way to launch the
newly-promoted Deckard-40B through it. Add a `deckard` mode mirroring the
27b/gemma pattern:

- DECKARD_DIR + start_deckard/stop_deckard helpers (compose_at on the
  piehsoft-q6k/mtp.yml compose; MODEL_DIR resolves from .env via --env-file,
  same as the vLLM modes).
- mode_deckard: stops all other GPU models (Deckard layer-splits across both
  cards), boots Deckard on :8199, brings up the support services, and wires it
  into Open WebUI via the switch.sh --owui helper (best-effort; Deckard isn't
  in the LiteLLM gateway config).
- stop_deckard added after every `stop_all_27b` call site (all 10 GPU-exclusive
  modes) so switching AWAY from Deckard frees both cards first.
- usage() + dispatch case arm.

Live-validated: `gpu-mode deckard` boots the piehsoft-q6k project, container
healthy on :8199 serving deckard-40b, mount /mnt/models/huggingface, OWUI
connection recognized. bash -n clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-10 01:04:50 +00:00
noonghunnaandClaude Opus 4.8 9981b28698 Add image-studio bundle P1: Ideogram-4 + gemma-12b chat + gpu-mode mode
Wires the committed services/comfyui + services/openwebui scaffold into a
seamless image-gen + chat bundle (coexisting on a 2-GPU box):

- services/comfyui/download_ideogram4.sh: fetch the Ideogram-4 fp8 set
  (2 transformers + Qwen3-VL-8B enc + flux2 VAE) into the ComfyUI models tree
- services/comfyui: opt-in COMFYUI_CUDA_VISIBLE_DEVICES GPU pin (entrypoint guard;
  empty default = all GPUs, preserves current behavior)
- services/openwebui: pin :v0.9.6; image-gen wired via imagegen.env (env_file,
  PersistentConfig — fresh-volume); default chat -> gemma-4-12b :8069 (LiteLLM alt)
- scripts/gpu-mode.sh: `image-studio` mode — ComfyUI/Ideogram-4 on GPU0 +
  gemma-4-12b chat on GPU1 (compose_at_env passes env through sudo); :8069 status
- scripts/setup-image-studio.sh: one-shot build + download + bring-up

Config-validated (docker compose config, bash -n, gpu-mode usage); test suite
40/42 (2 failures pre-existing, unrelated). Docs (IMAGE_STUDIO.md + deltas) and
live cutover validation to follow on this branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-09 03:15:51 +00:00
noonghunnaandClaude Opus 4.8 87190f90fa gpu-mode: add power-cap on/off/status controls
Both 3090s normally run capped at 230W (quiet/cool), enforced at boot by
the enabled nvidia-power-cap.service oneshot. The cap suppresses benchmark
TPS — a documented artifact (e.g. an ik_llama "+18-20%" result that was
really just 230W vs 370W) — so maintainers need a quick way to uncap for a
true-TPS bench, then re-cap.

Adds `gpu-mode power-cap <on|off|status>` (alias: `powercap`):
- on:  restart nvidia-power-cap.service (reusing the service as the single
       source of truth for 230W). restart, NOT start: the unit is already
       active from boot, and `start` on a RemainAfterExit oneshot is a no-op
       that would silently fail to re-apply. Falls back to direct
       `nvidia-smi -pl 230` if the service is missing.
- off: read each card's Default Power Limit from nvidia-smi and apply it.
       Defaults differ per card here (GPU0 370W, GPU1 420W), so the value is
       read, never hardcoded; nvidia-smi has no reset flag. Session-scoped:
       a reboot or driver reload re-caps via the service (never disabled).
- status: print per-GPU enforced/default/min/max limits.

Also surfaces a one-line per-card cap state in `gpu-mode status` and echoes
the resulting enforced limit after on/off. Errors loudly (no nvidia-smi, no
sudo) in the script's existing style.

Live-tested on the rig: status -> off (370/420) -> status -> on (230/230),
verified each transition with `nvidia-smi -q -d POWER`; left at 230W.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-06 10:13:35 +00:00
noonghunna 04c3d0d7aa gpu-mode.sh: align with dual prune — drop dead 27b modes, gemma -> int8 default (#280)
Match gpu-mode.sh to the #279 dual prune: remove the 27b-turbo/27b-dflash/27b-dflash-noviz modes (they launched deprecated composes; defensive stop_ helpers kept), and repoint Gemma so gemma -> vllm/gemma-int8 default (:8032, 262K+vision), new gemma-mtp -> bf16 32K fallback (:8030), gemma-int8 kept as alias. bash -n clean; suite 38/38.
2026-05-31 18:09:36 +05:00
noonghunnaandClaude Opus 4.8 45686808cb Prune Gemma vLLM variants (9->3) and pin survivors to v0.21.0
Every gemma-4-31b vLLM compose pinned a purged Docker Hub nightly
(e47c98ef / bf610c2f), un-bootable for fresh users (#250, #167 class).
Prune the 9-variant set to 3 and repoint survivors onto the immutable
stable release tag vllm/vllm-openai:v0.21.0 (never :latest).

Survivors: vllm/gemma-mtp (bf16 dual, default), vllm/gemma-int8 (int8-PTH
dual), vllm/gemma-mtp-tp1 (fp8 single). Dropped: gemma-dflash,
gemma-dflash-int8, gemma-int8-tq3, gemma-bf16, gemma-awq; the 262K path
folds into gemma-int8 via a CTX env override. Gemma is decoupled from the
shared Qwen nightly profiles via a new vllm-gemma-stable engine profile;
Qwen nightly profiles are untouched.

Diagnose decoupling: the pruned gemma dflash patch dirs doubled as the
diagnose tool's cross-model disk-source proxies for two Qwen overlays
(vllm-pr41703-dflash, vllm-pr42102-dflash-kv-quant). Those capabilities
are image-baked in the pinned nightly, not mountable files, so mark them
image_baked and have diagnose skip the disk-source check for image-baked
overlays. Runtime-neutral (no Qwen compose mounts them).

switch.sh launcher: handle the new VLLM_IMAGE engine-pin export (the twin
loop in launch.sh had it; switch.sh did not -> "unexpected engine pin
export"), and guard the VLLM_NIGHTLY_SHA echo for the image-only stable
profile (was unbound under set -u).

Validated on 2x RTX 3090 (Ampere, v0.21.0): full scripts/tests/*.sh suite
35/0; live boots of gemma-mtp (bf16) and gemma-int8 serve coherent output,
qwen vllm/dual regression-clean. gemma-mtp-tp1 (fp8_e4m3) is correctly
SM-gated (required_sm=9.0) -- confirmed Ampere-incompatible (Triton
"fp8e4nv not supported on sm_86"), a documented 32 GB+/Hopper variant;
beellama remains the single-card gemma path on Ampere.

Refs #451, #250, #167.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-05-29 07:59:42 +05:00
noonghunnaandClaude Opus 4.7 b23846ea36 fix: post-PR-A compose-path fixes for gpu-mode.sh + 2 patch READMEs
PR-A (#231) inserted the <quant>/ layer; two compose-path references
outside the doc sweep were left stale:

- scripts/gpu-mode.sh (the rig mode-switcher, symlinked into
  /usr/local/bin) cd'd into the dual/ topology dir and -f'd bare
  filenames (turbo.yml, docker-compose.yml, ...) that PR-A moved under
  <quant>/. Repointed DUAL_27B_DIR / GEMMA_DUAL_DIR at the autoround-int4
  quant dir (mount-safe — same cd-into-compose-dir invocation switch.sh
  uses), added GEMMA_DUAL_AWQ_DIR for the awq mode, and renamed the two
  ex-docker-compose.yml defaults (qwen -> fp8-mtp.yml, gemma -> bf16-mtp.yml).
  All 13 mode targets verified to resolve; bash -n clean.
- vllm-pr40798 / vllm-pr40914 patch READMEs cited dual/int8-tq3.yml (the
  pre-PR-A name). Commit 6182922 split int8-tq3 into the tq3-* family; the
  READMEs describe "TQ3 KV + MTP n=3" = tq3-mtp.yml (whose tombstone header
  cites #40914) -> dual/autoround-int4/tq3-mtp.yml.

Surfaced (not fixed here — PR-B's registry-derivation eliminates it):
launch.sh LAUNCH_VARIANT_COMPOSE[vllm/gemma-mtp] points at a non-existent
dual/autoround-int4/fp8-mtp.yml; gemma dual default is bf16-mtp.yml (the
registry is correct). test-launch-compat doesn't sweep launch.sh paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-26 17:11:20 +00:00
noonghunnaandClaude Opus 4.7 9e5f200449 fix(#169): distinct default container_name per llama.cpp/ik single variant
All llama.cpp + ik single composes shared one default container_name, so a
second variant hit a docker "name in use" conflict (ESTATE_CONTAINER override
existed but was undocumented). Give each non-base variant a distinct default:

- llamacpp/mtp           → llama-cpp-qwen36-27b          (base, unchanged)
- llamacpp/mtp-vision    → llama-cpp-qwen36-27b-vision
- ik/iq4ks-mtp           → ik-llama-qwen36-27b           (base, unchanged)
- ik/iq4ks-mtp-vision    → ik-llama-qwen36-27b-vision
- ik/iq4ks-two-stage     → ik-llama-qwen36-27b-two-stage

The base names (mtp / iq4ks-mtp = the default workhorses) are kept so existing
hardcoded refs and benchlocal `docker logs <base>` keep working.

launch.sh: track the two renamed variants in LAUNCH_DEFAULT_CONTAINER, and add
the missing ik-llama/iq4ks-two-stage entry (it fell back to the wrong default
container before). gpu-mode.sh: comment-only update for the new naming.

Audit (all clear): the autodetect globs in preflight/soak/switch/health/update
are prefix-anchored (`^llama-cpp-qwen36-27b`, no end anchor) and gpu-mode uses
`== llama-cpp-*`, so the suffixed names still match — verified.

Ports still default to 8020 (concurrency uses ESTATE_PORT, per the issue's own
example) — documented with a "run two variants at once" snippet in SINGLE_CARD.

Validated: `docker compose config` resolves each distinct name; all names still
match the autodetect glob; bash -n + test-launch-compat pass.

Closes #169.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-23 22:14:58 +00:00
noonghunnaandClaude Opus 4.7 db9c5e1bb9 gpu-mode status: probe :8020 + detect engine on :8030
Post-v0.8.3 the llama.cpp profile family lands containers on :8020
(llamacpp/default/mtp) and :8030 (llamacpp/mtp-vision). The status block was
missing :8020 entirely and hardcoded :8030 as "gemma-mtp / Gemma 4 31B".

Add :8020 probe, and on :8030 detect the active container so the label tracks
whichever engine (vLLM Gemma vs llama.cpp Qwen) is actually serving.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-20 02:30:31 +00:00
noonghunnaandClaude Opus 4.7 9cd854dbcb fix(gpu-mode): mode_off tears down estate-managed instances
Before this fix, gpu-mode off only stopped services it knew about
(stop_all_27b vLLM variants, stop_all_gemma vLLM variants, stop_comfyui,
and the SERVICES array). Instances booted via launch.sh --estate or
--estate-file persist via Docker `restart: unless-stopped` and so kept
running after gpu-mode off — appearing to "auto-restart". The user had
to know about launch.sh --down-estate to clean them up.

New stop_estate function:
- Reads ~/.club3090/estate.yml (constant ESTATE_YAML)
- No-ops if file missing, launch.sh unavailable, or estate list empty
- Otherwise calls launch.sh --down-estate <yaml> which cleanly removes
  each estate-managed container + its docker network

Called from mode_off only — keeps blast radius small. Other mode
switchers (mode_27b, mode_gemma, etc.) aren't touched on purpose:
estate instances and gpu-mode classic services can in principle share
a rig at TP=1 + small contexts, so the user should choose explicitly
whether to keep them up when switching gpu-mode targets. mode_off is
the "stop everything" intent — clearly should include estate.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-15 22:18:09 +05:00
noonghunnaandClaude Opus 4.7 00366a58d7 reorg: services/ consolidation + gpu-mode under git + ComfyUI + pin tracker + path updates
Release / release (push) Failing after 53s
The dev rig had grown across three home dirs (`/opt/ai/compose/`, `/opt/ai/github/`,
`/home/wasif/`) and three repos (single-3090, dual-3090, club-3090). Disk-out
on `/` (97% used) forced a cleanup; rather than just prune, we consolidated
the layout across the whole stack while we were at it. This commit captures
what landed inside this repo.

Services consolidation:
- services/{ollama,openwebui,litellm,qdrant,searxng}/ migrated in from
  /opt/ai/compose/<svc>/ (zero functional change — same docker-compose.yml).
- services/litellm/config.yaml rewritten: explicit routes for current
  primaries (qwen3.6-27b-autoround → :8010, gemma-4-31b-autoround → :8030).
  Removed `* → ollama/*` wildcard.
- services/comfyui/ migrated in (was /opt/ai/compose/comfyui/) — wired into
  gpu-mode with full mutex against vLLM/SGLang.

scripts/gpu-mode.sh under git:
- Was a loose /opt/ai/gpu-mode.sh outside any repo. Symlinked at
  /usr/local/bin/gpu-mode.
- Five Gemma 4 31B modes added: gemma, gemma-dflash, gemma-int8,
  gemma-dflash-int8, gemma-awq.
- One ComfyUI mode (mutex with all LLM serving).
- prune / prune-all subcommands (safe image prune; aggressive variant adds
  build cache --keep-storage 5GB + dangling networks).
- gpu-mode status now shows Docker disk + /var/lib/docker + /tmp sizes.
- compose_at() passes --env-file <repo>/.env so MODEL_DIR resolves
  regardless of which compose dir gpu-mode cd's into. Fixes the recurring
  "MODEL_DIR not set, defaulting to ../../../../../models-cache" warning.
- stderr no longer swallowed by compose_at() (real errors surface).
- Cross-model VRAM mutex: every Qwen mode stop_all_gemma + stop_comfyui
  and vice-versa.

scripts/maintenance/ — new hygiene-tools subdir:
- list-image-pins.sh: engine-agnostic pin auditor. Scans every compose's
  `image:` line, groups by `<repo>:<tag>`, flags pin-drift (multiple tags
  per repo), ranks composes by patch surface.

Pin tracking:
- docs/UPSTREAM.md gains a "Pinned images" section: table of every pinned
  image, why each pin exists, retirement candidate criteria.
- docs/NIGHTLY_BUMP_RUNBOOK.md (new): 7-step procedure for bumping pinned
  engine images (scope → branch → patch survival → boot → verify-full +
  verify-stress → bench delta → land → retire). Engine-specific notes
  for vLLM nightly hashes, llama.cpp digest pinning, SGLang variants.

Path updates from the engine + model dir consolidation:
- /opt/ai/vllm-src/ → /opt/ai/engines/vllm/primary/
  (in setup.sh, INTERNALS.md, several patch READMEs, docs/HARDWARE.md,
   docs/FAQ.md, docs/DUAL_CARD.md, docs/UPSTREAM.md, models/qwen3.6-27b/
   CHANGELOG.md)
- /mnt/models/gguf/qwen3.6-27b/ → /mnt/models/huggingface/qwen3.6-27b-gguf/
  (in models/qwen3.6-27b/llama-cpp/{compose/single/*.yml, recipes/*.sh,
   README.md}, docs/engines/LLAMA_CPP.md)

CHANGELOG.md narrative gap fill:
- 2026-05-10 entry for this reorg.
- 2026-05-09 entry for compose convention formalization (topology
  promoted to dir level, profile schema, Status enum + Caveats, cliff
  CI swap, Discord launch).
- 2026-05-08 entry for Gemma 4 INT8 PTH unblock + 262K validation.
- 2026-05-07 entry for power-cap-sweep campaign + HARDWARE.md cross-rig
  charts + cross-rig benchmark rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-10 16:57:03 +00:00