Skip to content

Add vLLM docker-compose and switch runtime model to Qwen3-32B-NVFP4 - #5

Merged
OriNachum merged 2 commits into
mainfrom
feat/qwen3-32b-vllm-compose
May 26, 2026
Merged

Add vLLM docker-compose and switch runtime model to Qwen3-32B-NVFP4#5
OriNachum merged 2 commits into
mainfrom
feat/qwen3-32b-vllm-compose

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

What & why

lepenseur names a vLLM runtime model in culture.yaml/AGENTS.md but shipped no way to actually serve it. This PR adds that serving infrastructure and switches lepenseur's brain to nvidia/Qwen3-32B-NVFP4 (a 32B dense NVFP4 reasoning model with a thinking mode — it still emits a reasoning trace before its answer, the property that suits a deep thinker).

Changes

Serving infra (new):

  • docker-compose.yml — NGC nvcr.io/nvidia/vllm image serving an OpenAI-compatible API on :8000 for the acp backend. Tuned for DGX Spark (GB10 Blackwell, 128 GB unified memory): NVFP4 modelopt_fp4, fp8 KV cache, Qwen3 reasoning parser, ipc: host, HF-cache volume, conservative gpu-memory-utilization=0.6, generous healthcheck start_period for the first-run weight download.
  • .env.example — all tunables documented (HF_TOKEN, VLLM_MODEL, VLLM_SERVED_NAME, VLLM_PORT, VLLM_MAX_MODEL_LEN, VLLM_GPU_MEM_UTIL).
  • README "Running the model locally (vLLM)" section.

Model switch (Nemotron-120B → Qwen3-32B-NVFP4):

  • culture.yaml model: + Runtime paragraph, AGENTS.md (kept verbatim-mirrored), lepenseur/explain/catalog.py, README.md, CLAUDE.md.
  • tests/test_cli.py: assert "Nemotron"assert "Qwen3" (the vllm-local/ assertions stay valid).

Not touched on purpose: docs/superpowers/* (dated scaffold records) and the historical 0.1.0 CHANGELOG entry.

Verification

  • uv run pytest -n auto — 21 passed.
  • black/isort/flake8/bandit/markdownlint-cli2 — clean (matching CI invocations).
  • docker compose config — parses with env substitution.
  • lepenseur whoamimodel: vllm-local/nvidia/Qwen3-32B-NVFP4; explain backend mentions Qwen3, no Nemotron.
  • Version bumped 0.1.0 → 0.2.0.

Notes for review

  • Image tag nvcr.io/nvidia/vllm:26.04-py3 is the main unknown — confirm against build.nvidia.com/spark/vllm that the pinned tag has NVFP4 support.

  • The nvidia/ checkpoint is ModelOpt (TRT-LLM-oriented). If vLLM rejects it, the README documents the vLLM-native RedHatAI/Qwen3-32B-NVFP4 fallback.

  • lepenseur (Claude)

🤖 Generated with Claude Code

Stand up the local vLLM server that serves lepenseur's runtime model, and
re-point the agent's brain from Nemotron-120B to nvidia/Qwen3-32B-NVFP4.

- docker-compose.yml + .env.example: NGC nvcr.io/nvidia/vllm image serving an
  OpenAI-compatible API on :8000 for the acp backend, tuned for DGX Spark
  (GB10 Blackwell, 128 GB unified memory; NVFP4 modelopt_fp4, fp8 KV cache,
  Qwen3 reasoning parser, conservative gpu-memory-utilization).
- README "Running the model locally (vLLM)" section.
- Switch model refs Nemotron -> Qwen3-32B-NVFP4 across culture.yaml, AGENTS.md
  (mirrored), explain/catalog.py, README.md, CLAUDE.md; update the test
  assertion accordingly.
- Bump 0.1.0 -> 0.2.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add vLLM Docker Compose and switch to Qwen3-32B-NVFP4 model

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add vLLM Docker Compose infrastructure for local model serving
  - NGC nvcr.io/nvidia/vllm image serving OpenAI-compatible API on :8000
  - Tuned for DGX Spark (GB10 Blackwell, 128 GB unified memory)
  - .env.example with documented tunables (HF_TOKEN, VLLM_MODEL, VLLM_GPU_MEM_UTIL, etc.)
• Switch runtime model from Nemotron-120B to Qwen3-32B-NVFP4
  - 32B dense reasoning model with thinking mode and extended context (32K native, ~131K via YaRN)
  - Updated across culture.yaml, AGENTS.md, CLAUDE.md, lepenseur/explain/catalog.py,
  README.md
• Add "Running the model locally (vLLM)" section to README with setup instructions
• Bump version from 0.1.0 to 0.2.0 and update CHANGELOG
Diagram
flowchart LR
  A["Nemotron-120B<br/>LatentMoE 120B/12B"] -->|"Model Switch"| B["Qwen3-32B-NVFP4<br/>Dense 32B Reasoning"]
  C["Manual Setup"] -->|"Docker Compose"| D["vLLM Server<br/>OpenAI API :8000"]
  B -->|"Served by"| D
  E[".env.example<br/>Configuration"] -->|"Configures"| D
  D -->|"Connected by"| F["acp Backend<br/>Culture Mesh"]

Loading

Grey Divider

File Changes

1. docker-compose.yml ✨ Enhancement +58/-0

Add vLLM Docker Compose service configuration

docker-compose.yml


2. .env.example ⚙️ Configuration changes +22/-0

Add environment variables documentation for vLLM

.env.example


3. culture.yaml ✨ Enhancement +7/-7

Switch model to Qwen3-32B-NVFP4 and update runtime description

culture.yaml


View more (7)
4. AGENTS.md 📝 Documentation +6/-6

Update runtime model description to Qwen3-32B-NVFP4

AGENTS.md


5. CLAUDE.md 📝 Documentation +5/-5

Update model references and runtime documentation

CLAUDE.md


6. README.md 📝 Documentation +31/-1

Add vLLM setup section and update model reference

README.md


7. lepenseur/explain/catalog.py 📝 Documentation +5/-5

Update backend catalog with new model specifications

lepenseur/explain/catalog.py


8. CHANGELOG.md 📝 Documentation +17/-0

Add 0.2.0 release notes for vLLM and model switch

CHANGELOG.md


9. pyproject.toml ⚙️ Configuration changes +1/-1

Bump version from 0.1.0 to 0.2.0

pyproject.toml


10. tests/test_cli.py Additional files +1/-1

...

tests/test_cli.py


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 26, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Remote code trust enabled ✓ Resolved 🐞 Bug ⛨ Security
Description
docker-compose.yml runs vLLM with --trust-remote-code while also loading HF_TOKEN from .env
and bind-mounting the host HuggingFace cache, so remote model code can execute in-container with
access to credentials and host-mounted files. This increases the blast radius of any
compromised/malicious model repository.
Code

docker-compose.yml[R29-52]

Evidence
The compose file both (a) enables remote-code execution from model repositories and (b) supplies an
HF token plus mounts a host cache directory, which together increases the impact of remote code
execution.

docker-compose.yml[29-36]
docker-compose.yml[52-52]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`docker-compose.yml` enables `--trust-remote-code` unconditionally, while also passing `HF_TOKEN` via `.env` and mounting the host HF cache. This makes arbitrary code execution from model repos the default and increases secret/host-file exposure.

## Issue Context
The compose file is intended for local serving, but it mounts a host directory and commonly includes a real HuggingFace token for gated repos.

## Fix Focus Areas
- docker-compose.yml[29-52]
- .env.example[1-22]

## Suggested fix
- Remove `--trust-remote-code` by default, OR gate it behind an env var.
- If gating, consider switching `command:` to a shell form so you can conditionally append the flag, e.g. `${VLLM_TRUST_REMOTE_CODE:+--trust-remote-code}`, and document `VLLM_TRUST_REMOTE_CODE` in `.env.example`.
- Optionally document the security implication prominently in README.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Missing .env breaks compose ✓ Resolved 🐞 Bug ☼ Reliability
Description
docker-compose.yml hard-references env_file: .env, but .env is gitignored and not present in a
fresh checkout, so docker compose up will fail unless the user creates it. This is a setup footgun
because the file already uses defaults for VLLM_PORT/VLLM_MODEL/etc.
Code

docker-compose.yml[R29-31]

Evidence
The compose file requires .env, while the repo explicitly ignores .env and the README instructs
users to create it before running compose, implying fresh clones otherwise fail.

docker-compose.yml[29-31]
.gitignore[150-153]
README.md[42-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`env_file: .env` makes `.env` a hard requirement at runtime. Since `.env` is gitignored, a fresh clone will not have it and `docker compose up` will error.

## Issue Context
The compose file already provides default values via `${VAR:-default}` for most tunables; the only value that truly benefits from `.env` is `HF_TOKEN`.

## Fix Focus Areas
- docker-compose.yml[29-33]
- .gitignore[150-153]

## Suggested fix
- Use the optional env_file form:
 ```yaml
 env_file:
   - path: .env
     required: false
 ```
 (so compose works without `.env`)
- Alternatively remove `env_file` and rely on exporting `HF_TOKEN` in the shell when needed, while keeping `.env.example` for convenience.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

3. HOME mount lacks fallback ✓ Resolved 🐞 Bug ☼ Reliability
Description
The HuggingFace cache bind mount uses ${HOME} without a default, so environments without HOME
set (or unusual setups) can resolve the mount path incorrectly (e.g., to /.cache/...) and break
cache persistence expectations. This is avoidable by using a named volume or a ${HOME:-...}
default.
Code

docker-compose.yml[R34-37]

Evidence
The compose file mounts ${HOME}/.cache/huggingface and provides no default for HOME, so
missing/empty HOME changes the effective host path.

docker-compose.yml[34-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The bind mount uses `${HOME}` without a default, which can resolve unexpectedly when `HOME` is not set.

## Issue Context
This compose file is meant to be copied/run in varied environments; using a named volume avoids host-path expansion pitfalls.

## Fix Focus Areas
- docker-compose.yml[34-37]

## Suggested fix
- Replace the bind mount with a named volume:
 ```yaml
 volumes:
   - hf-cache:/root/.cache/huggingface

 volumes:
   hf-cache: {}
 ```
- Or add a default: `${HOME:-/tmp}/.cache/huggingface:/root/.cache/huggingface` (pick an appropriate default).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

- Security: drop --trust-remote-code (Qwen3-32B-NVFP4 loads without it; the flag
  would let model-repo code run in-container alongside HF_TOKEN + the cache mount).
  Documented the swap caveat in README.
- Reliability: env_file -> { path: .env, required: false } so a fresh checkout
  without a .env still runs (only HF_TOKEN needs it).
- Reliability: HF cache mount now ${HF_CACHE:-${HOME:-/root}/.cache/huggingface}
  so it never collapses to /.cache/huggingface when HOME is unset; HF_CACHE
  documented in .env.example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@OriNachum

Copy link
Copy Markdown
Contributor Author

Thanks Qodo — all three fixed in a3ac62e:

  1. Remote code trust — removed --trust-remote-code. Qwen3-32B-NVFP4 is a natively-supported vLLM architecture and NVFP4/ModelOpt loading needs no remote code, so the flag was pure blast-radius (it would let a model repo's code run in-container alongside HF_TOKEN and the mounted cache). README now documents adding it back only for a model whose repo ships custom modeling code.
  2. Missing .env breaks compose — switched to the optional form ({ path: .env, required: false }). Verified docker compose config succeeds with no .env present; only gated downloads (which need HF_TOKEN) are affected.
  3. ${HOME} mount lacks fallback — mount is now ${HF_CACHE:-${HOME:-/root}/.cache/huggingface}. Verified it resolves to ~/.cache/huggingface with HOME set and /root/.cache/huggingface with HOME unset (never collapses to /.cache/...). Added HF_CACHE as a documented override in .env.example.
  • lepenseur (Claude)

@sonarqubecloud

Copy link
Copy Markdown

@OriNachum
OriNachum merged commit 22c2f01 into main May 26, 2026
8 checks passed
OriNachum added a commit that referenced this pull request May 31, 2026
…st-remote-code guidance

- Qodo #4 (bug): `model switch --apply` to a non-MTP model now writes .env but
  does NOT recreate the container (the template ships the MTP primary's
  incompatible flags); prints the lines to remove. New --force overrides. Guards
  against taking a healthy deployment down. Tests added.
- Qodo #5 (maintainability): MTP compose flags centralized in
  catalog.mtp_compose_command_items() — one source of truth for the templates and
  switch's removal notice; new drift test asserts the packaged templates contain them.
- Qodo #1 (security): added --trust-remote-code + HF_TOKEN safety guidance to both
  compose templates and env.example (leave HF_TOKEN empty for public defaults / use
  a minimal-scope read-only token; pin trusted revisions).
- Qodo #3 (doc): documented the ticket's unsloth baseline serve command and why we
  deliberately deviate (the baseline export drops the MTP head) + that the decode
  comparison is against the load-tested mmangkad baseline.

Qodo #2 (test unsloth not sakamakismile): pushback in the PR thread — the unsloth
baseline NVFP4 export drops the MTP head (~0% acceptance), so it cannot exercise
MTP; sakamakismile is the grafted re-export that makes MTP work (issue #26).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OriNachum added a commit that referenced this pull request May 31, 2026
* Promote the MTP 27B to fleet default primary; archive mmangkad

Promote sakamakismile/Qwen3.6-27B-Text-NVFP4-MTP from candidate to the
fleet's default primary, replacing mmangkad/Qwen3.6-27B-NVFP4. The
tool-calling gate that kept it a candidate is now closed: served through the
production compose it emits a valid qwen3_coder tool call, completes a full
tool round-trip, keeps its reasoning trace, and runs MTP spec-decode at
78.6% draft acceptance with tool calling on (~2.4x decode, 8 -> ~19 tok/s,
~71 GB; both `model assess` probes finish=stop).

- catalog: role_hint primary <-> candidate swap (sakamakismile <-> mmangkad)
- gateway _DEFAULT_PRIMARY, whoami _DEFAULT_MODEL
- both env.example + docker-compose templates (single + fleet vllm-primary):
  bake the MTP serve flags (--speculative-config / --trust-remote-code /
  --language-model-only / --tokenizer override / --max-num-seqs=2, quant
  modelopt) so a fresh `model init && model serve` of the default just works
- switch: invert _serve_notices (non-MTP target -> "remove these 4 lines";
  was "add" for the candidate); force the MTP seq cap to 2
- culture.yaml model field; docs reframed (candidate -> primary, baseline ->
  archived former primary)
- tests updated; mmangkad retained as the MTP tokenizer source + only
  vision-capable 27B

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address Qodo review on #28: switch --apply safety, DRY MTP flags, trust-remote-code guidance

- Qodo #4 (bug): `model switch --apply` to a non-MTP model now writes .env but
  does NOT recreate the container (the template ships the MTP primary's
  incompatible flags); prints the lines to remove. New --force overrides. Guards
  against taking a healthy deployment down. Tests added.
- Qodo #5 (maintainability): MTP compose flags centralized in
  catalog.mtp_compose_command_items() — one source of truth for the templates and
  switch's removal notice; new drift test asserts the packaged templates contain them.
- Qodo #1 (security): added --trust-remote-code + HF_TOKEN safety guidance to both
  compose templates and env.example (leave HF_TOKEN empty for public defaults / use
  a minimal-scope read-only token; pin trusted revisions).
- Qodo #3 (doc): documented the ticket's unsloth baseline serve command and why we
  deliberately deviate (the baseline export drops the MTP head) + that the decode
  comparison is against the load-tested mmangkad baseline.

Qodo #2 (test unsloth not sakamakismile): pushback in the PR thread — the unsloth
baseline NVFP4 export drops the MTP head (~0% acceptance), so it cannot exercise
MTP; sakamakismile is the grafted re-export that makes MTP work (issue #26).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* switch: drop the unused 'messages' param from _apply_env_only

It writes .env + emits the blocked-on-compose-edits result; it never used the
parser/quant messages (those are only for the restart path in _apply_switch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OriNachum added a commit that referenced this pull request Jun 9, 2026
Triage of Qodo findings on #37:

- #1 (rule 796119): CHANGELOG `~/.model-gear` → `$HOME/.model-gear`. (The .py
  --help/docstring keep `~/.model-gear` to match the repo-wide CLI help text;
  Qodo's docs/config rule only flags the markdown.)
- #2 (unreadable/dir .env crash): main() preflights that .env is a regular file
  and wraps the read/update/write in try/except OSError -> EXIT_ENV_ERROR,
  matching _read_key()'s graceful degradation.
- #3 (under-scoped bump): a new documented capability is a minor, not a patch —
  0.18.1 -> 0.19.0.
- #4 (unhandled chmod): os.chmod is now best-effort (try/except OSError with a
  note), so a chmod-unsupported FS doesn't crash after a successful write.
- #5 (unvalidated --bytes): reject `< 16` (128-bit floor) with a user error
  before generating, so no weak key or token_urlsafe stack trace.

New tests: too-few-bytes and non-regular-file .env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OriNachum added a commit that referenced this pull request Jun 9, 2026
…ey (#37)

* Add scripts/gen-api-key.py to generate/rotate the served-API bearer key

`CULTURE_VLLM_API_KEY` gates the vLLM API (and is mandatory before exposing it
via `model tunnel`), but there was no first-class way to mint it. This adds a
small, stdlib-only generator that:

- creates the key with `secrets.token_urlsafe` and NEVER hardcodes a secret, so
  the script is safe in the open-source repo; the key only lands in the
  gitignored deployment `.env` (written 0o600);
- hides the key by default (no echo into logs/scrollback); `--show` prints it,
  `--force` rotates an existing key;
- resolves the deployment dir like the `model` CLI (`--dir` > $MODEL_GEAR_DIR >
  ~/.model-gear), and runs from a wheel install (no model_gear import).

Tests cover set/rotate/refuse-overwrite/missing-dir/show/no-leak/0o600. README
"Expose the API" section now points at it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address PR #37 review: harden gen-api-key.py + correct semver bump

Triage of Qodo findings on #37:

- #1 (rule 796119): CHANGELOG `~/.model-gear` → `$HOME/.model-gear`. (The .py
  --help/docstring keep `~/.model-gear` to match the repo-wide CLI help text;
  Qodo's docs/config rule only flags the markdown.)
- #2 (unreadable/dir .env crash): main() preflights that .env is a regular file
  and wraps the read/update/write in try/except OSError -> EXIT_ENV_ERROR,
  matching _read_key()'s graceful degradation.
- #3 (under-scoped bump): a new documented capability is a minor, not a patch —
  0.18.1 -> 0.19.0.
- #4 (unhandled chmod): os.chmod is now best-effort (try/except OSError with a
  note), so a chmod-unsupported FS doesn't crash after a successful write.
- #5 (unvalidated --bytes): reject `< 16` (128-bit floor) with a user error
  before generating, so no weak key or token_urlsafe stack trace.

New tests: too-few-bytes and non-regular-file .env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OriNachum added a commit that referenced this pull request Jun 12, 2026
- Scaffold _readiness.py via AUDIO_TEMPLATES so `model init --fleet --audio`
  writes it (Dockerfile.parakeet COPYs it — clean init would otherwise fail
  `docker compose build stt`). [Qodo #2, comment 3402397497]
- Remove the inline fallback copy of the readiness decision from
  listen_server.py and add a drift test asserting the vendored twin matches
  the canonical model_gear/realtime/_readiness.py. [Qodo #4]
- Log CUDA readiness-probe failures (type + message) before returning 503 so
  operators can tell driver-down / OOM / stale-context apart. [Qodo #3]
- audio-smoke.py now exercises /v1/audio/speech and wires --stt-url to a
  direct-Parakeet check (was claimed-but-untested). [Qodo #5]
- docs/realtime-pipeline.md uses $HOME/.model-gear, not ~/.model-gear
  (portability rule). [Qodo #1, comment 3402397490]

275 tests pass; black/isort/flake8 + markdownlint clean. Bump 0.20.0 -> 0.20.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OriNachum added a commit that referenced this pull request Jun 12, 2026
… + smoke (closes #39, #40) (#41)

* spec: model-gear owns the audio I/O surface (devague /think)

Work issues #39 (Parakeet STT 500s, CUDA-unknown) and #40 (deployed
:8080 facade missing /v1/audio/transcriptions) backwards into one
converged spec: model-gear takes ownership of the audio stack, wiring
Parakeet STT + Magpie TTS + the vendored realtime facade into its
compose template and `model fleet up`.

Decisions captured: full-stack ownership (both /v1/audio/* routes),
cheap model-ready Parakeet healthcheck, restart-clears-stale-CUDA-context
runbook. Unblocks reachy-mini-cli's "hey reachy" wake-word.

Includes the converged spec + the .devague frame state (evidence trail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* plan: model-gear audio surface — 6 tasks, 5 waves (devague /spec-to-plan)

Forward leg from the converged audio-ownership spec. Six file-disjoint,
TDD-gated tasks covering all 24 coverage targets:
  t1 vendor Parakeet server + cheap model-ready probe
  t2 build Dockerfiles (facade + parakeet)
  t3 wire the audio stack into the compose template (sole compose owner)
  t4 bring it up via `model fleet up`
  t5 docs/realtime-pipeline.md + README Audio I/O + CUDA restart runbook
  t6 smoke/acceptance harness (openapi, WAV 200, healthcheck flip)

Waves: [t1,t5] -> t2 -> t3 -> t4 -> t6 (serial after wave 0 by the
compose chokepoint). Risks carried: CUDA root-cause unconfirmed, fleet
gating on the GB10 budget, cheap-probe wording reconciliation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(audio): real Parakeet readiness probe + realtime-pipeline docs + smoke

Implements the three real gaps found after reconnaissance (t2/t3/t4 — the
audio overlay, Dockerfiles, fleet wiring — already existed in
templates/fleet/):

- t1: Parakeet /v1/health/ready now reflects REAL readiness (model loaded +
  a trivial CUDA op) instead of returning {"status":"ready"}
  unconditionally — the misleading-health bug behind #39. The pure decision
  lives in stdlib-only model_gear/realtime/_readiness.py (CI-unit-tested,
  8 cases), vendored into the Parakeet build context and COPY'd into the
  image so the container imports it without the wheel. (decision c16: a
  cheap probe, not a full transcription each interval.)
- t5: docs/realtime-pipeline.md — ownership of the live :8080 facade, fleet
  bring-up, the prior drift (#39/#40), health/readiness, and the stale-CUDA
  restart runbook.
- t6: scripts/audio-smoke.py — stdlib-only live smoke (openapi lists both
  routes; WAV POST -> 200 {text}); reproduces #39's repro. Live run is
  GPU-box-bound, not CI.

271 tests pass; black/isort/flake8 + markdownlint clean.

Refs #39 #40

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: bump version 0.19.0 -> 0.20.0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: sync uv.lock to 0.20.0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style: black-format listen_server.py (fix lint)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: markdownlint ignores docs/specs + docs/plans (devague artifacts)

The devague-exported spec/plan H1 is the verbatim announcement sentence,
which ends in a period (MD026/no-trailing-punctuation). These are generated
planning artifacts like docs/superpowers/** — ignore them in lint.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(audio): address Qodo review of #41

- Scaffold _readiness.py via AUDIO_TEMPLATES so `model init --fleet --audio`
  writes it (Dockerfile.parakeet COPYs it — clean init would otherwise fail
  `docker compose build stt`). [Qodo #2, comment 3402397497]
- Remove the inline fallback copy of the readiness decision from
  listen_server.py and add a drift test asserting the vendored twin matches
  the canonical model_gear/realtime/_readiness.py. [Qodo #4]
- Log CUDA readiness-probe failures (type + message) before returning 503 so
  operators can tell driver-down / OOM / stale-context apart. [Qodo #3]
- audio-smoke.py now exercises /v1/audio/speech and wires --stt-url to a
  direct-Parakeet check (was claimed-but-untested). [Qodo #5]
- docs/realtime-pipeline.md uses $HOME/.model-gear, not ~/.model-gear
  (portability rule). [Qodo #1, comment 3402397490]

275 tests pass; black/isort/flake8 + markdownlint clean. Bump 0.20.0 -> 0.20.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant