Tasks
July 6, 2026 · View on GitHub
Implementation backlog. Work continuously until every code-complete criterion passes. Do not stop after a single task or ship a subset as "done." The only work that legitimately waits is runtime rows that need the operator's container + GPU + HF token — record those as pending-operator in STATE.md with exact commands; never as a reason to stop coding.
- Product list: INVENTORY.md
- Architecture: ARCHITECTURE.md
- Mark done only in STATE.md with evidence (test or command output)
Task 1 — Catalog API + client model picker ✅
Goal: Settings download dialogs list models from the engine catalog API, not hardcoded arrays.
Touch:
src/server/GuideAntsApi/Endpoints/Settings/SettingsServiceLocalModelsEndpoints.cs—GET …/local-models/catalogsrc/client/src/services/api.ts—catalogOutcomesrc/client/src/pages/settings/editors/common/CatalogDownloadModelDialog.tsxsrc/client/src/pages/settings/editors/{EmbRuntimeManager,AsrModelManager,TtsModelManager}.tsx
Done when:
- Proxy returns engine
/admin/catalogfor Embeddings, SpeechTranscription, SpeechSynthesis - All three “Add model” dialogs use
CatalogDownloadModelDialog -
rg 'catalogEntries\s*=\s*\[' src/client/src/pages/settings/editors— no matches outside__tests__ - Client tests updated (
TtsModelManager.test.tsx, etc.)
Verify:
rg 'catalogEntries\s*=\s*\[' src/client/src/pages/settings/editors
cd src/client && npm test -- --run src/pages/settings/editors/speech-synthesis/__tests__/TtsModelManager.test.tsx
Task 2 — Download validator uses catalog ✅
Goal: .NET rejects download requests for ids not in the curated catalog before proxying to the engine.
Depends: Task 1
Touch:
src/server/GuideAntsApi/Endpoints/Settings/ServiceLocalModelDownloadValidator.csGuideAntsApi.Tests(or equivalent) — accept known id, reject unknown
Behavior:
POST …/local-models/downloadswithmodel_idnot in proxied catalog → 400 with clear message- Valid id (present in current manifest) → pass through to engine unchanged
Done when:
- Validator fetches or caches catalog ids per service
- Unit tests: reject
model_id: "whisper-large-v3", acceptqwen3_asr_0_6b - STATE row “Download validator” → pass
Task 3 — Full ASR manifest
Goal: asr-service/catalog/manifest.json contains both INVENTORY ASR rows with complete metadata.
Depends: Task 2 (recommended — downloads validated)
Touch:
docker/build/guideants-ai/asr-service/catalog/manifest.json- Copy field patterns from existing
qwen3_asr_0_6bentry; addcitrinet_asrper INVENTORY.md
Done when:
- Both ids present with
family,sourceRepos,requiredFiles,layout,gated,releaseStatus -
GET /asr/admin/catalogreturns 2 entries - Download + load + transcribe for each entry (operator or test) — update STATE per-model matrix
Verify:
rg '"id":' docker/build/guideants-ai/asr-service/catalog/manifest.json
# expect qwen3_asr_0_6b and citrinet_asr
Task 4 — Full TTS manifest
Goal: tts-service/catalog/manifest.json contains all 11 INVENTORY TTS rows.
Depends: Task 2
Touch:
docker/build/guideants-ai/tts-service/catalog/manifest.jsondocs/native-ai-migration/catalog/schema.model.jsonif new fields needed
Each entry must include: id, task: tts, family, voiceInput, displayName, sourceRepos, requiredFiles, targetDirectory, layout, format, gated, releaseStatus, default (one entry), capabilities where useful.
Done when:
- 11 entries — ids match INVENTORY.md
-
voiceInputcorrect per row (chatterbox→voice_pack, CustomVoice →builtin, VoiceDesign →instruct, etc.) -
pocket_ttshasgated: true - Composite entries (
miotts_1_7b,vevo2,vibevoice_1_5b) document allsourceRepos - JSON Schema validation passes
- Download starts for each id (gated: with HF token — document in STATE)
Task 5 — Catalog-driven UI configuration
Goal: TTS provider settings show the right controls for the active model — not a static voice enum.
Depends: Tasks 1, 4 (need full catalog metadata including voiceInput)
Touch:
docker/build/guideants-ai/tts-service/tts_service.py— implementGET /admin/voice-packSettingsServiceLocalModelsEndpoints.cs— proxy voice-pack to clientApplicationSettingsService.ServiceEditors.cs— dynamicVoiceNameoptions whenvoiceInput: voice_pack- Runtime metadata endpoint or catalog enrichment for
builtinspeaker lists — implemented via/local-models/voicesproxy to audiocppGET /v1/audio/voices - Instruct field in provider editor when
voiceInput: instruct - Remove:
ServiceEditorMetadataProvider.LocalTtsVoiceNames,SpeechSynthesisService.LocalTtsVoiceLanguageCodes
Done when:
- Active
chatterbox→ voice picker shows all voice-pack ids (54+) - Switching provider model to a
builtinentry changes UI to speaker picker (from runtime, not hardcoded) -
voice_designentry shows instruct field -
gatedmodel download UI shows token requirement - Synthesis succeeds with pack voice;
lang_codenot sent from .NET -
rg 'LocalTtsVoiceNames|LocalTtsVoiceLanguageCodes' src/server— no matches - Client/server tests for at least chatterbox + one
builtinfamily
Task 6 — Family-aware ASR/TTS runtime
Goal: Engine load and inference use the catalog entry’s family and voiceInput — every inventory row works.
Depends: Tasks 3, 4, 5
Touch:
docker/build/guideants-ai/asr-service/asr_service.py— load/transcribe perqwen3_asr,citrinet_asrdocker/build/guideants-ai/tts-service/tts_service.py— load/synthesize per all 11 families
Done when:
- No code path assumes Chatterbox for all TTS requests
- Each INVENTORY row: load + one inference — pass in STATE per-model matrix
- Wrong voice for active family → 4xx error, not fallback
- Operator notes or automated smoke recorded in STATE
This task is the definition of “services use the selection correctly.”
Task 7 — CI / drift checks
Goal: CI fails if manifests drift from INVENTORY or hardcoded lists reappear.
Depends: Tasks 5–6
Touch: scripts/native-ai-migration/verify-catalog-contract.ps1, CI workflow or pre-commit
Checks:
- Manifest entry ids == INVENTORY ids (per service)
- No
catalogEntries = [in client editors - No
LocalTtsVoiceNames/LocalTtsVoiceLanguageCodesin server - Document in RULES.md
Task 8 — Voice pack NOTICE + bootstrap
Goal: Legal/provenance docs and default bootstrap voice ids match current voice-pack manifest.
Depends: Task 5 (voice-pack API)
Touch:
docker/build/guideants-ai/voice-pack/NOTICE.mdsrc/server/GuideAntsApi/Resources/bootstrap/provider-stack-profiles/local-ai.json- Docker compose
GA_TTS_VOICE— derive from voice-pack default or remove
Done when:
- NOTICE describes actual clip provenance (not obsolete LibriVox-only story if manifest is Kokoro-synthetic)
- Bootstrap
VoiceNameis a valid pack id (e.g.af_alloy), noten_us_cv_001 -
check-voice-pack-attribution.pypasses
Dependency graph
Task 1 ✅
└─► Task 2 ✅
├─► Task 3 (ASR manifest — entries done; runtime pending)
└─► Task 4 (TTS manifest — entries done; runtime pending)
└─► Task 5 (UI config)
├─► Task 6 (runtime — BLOCKS “done”)
├─► Task 8 (NOTICE/bootstrap)
└─► Task 7 (CI)
Program complete: Task 6 matrix all pass + Task 7 CI green.