Files
claude-projects/agent-builder/voice_chat_agent_prompts.md
T
Backtalk6858 1a44c84fa7 docs(voice-chat): lock preflight decisions + decomposed build prompts
Voice Chat for Claude Code preflight/design session (personal_projects id=214).
Fully-local PTT voice: faster-whisper + Coqui XTTS-v2 on server-01 GPU, Jarvis
voice. Phase A includes background-agent audio-arbitration queue + pause/resume
voice control + per-agent tmux. Hard deadline ~2026-08-14 (Max upgrade).

- voice_chat_build_plan.md: locked decisions, topology, blast-radius/rollback
- voice_chat_agent_prompts.md: 3 bounded server-01 agent prompts (A1 Whisper,
  A2 XTTS+Jarvis, A3 fail-safe Stop-hook) + main-session checklist
- context.md: refresh CURRENT STATE block (was stale since 2026-06-04)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 16:58:30 -05:00

12 KiB
Raw Blame History

Voice Chat — Background Agent Prompts (decomposed build)

Companion to voice_chat_build_plan.md. Preflight: 2026-07-29.

Launch target: on/before the build session ahead of 2026-08-14.

⚠️ RE-VERIFY AT LAUNCH (infra facts decay — do NOT trust these blindly):

- server-01 access = sudo-bridge-server01 at http://192.168.1.90:8082 (NOT secrets-proxy /shell).

Confirm the bridge is up and the endpoint/port before launching.

- Vault: resolve IP dynamically via docker inspect vault-iwaulpoi5hwirdlogshmul40; AppRole only.

- infrastructure-auth-map: secret/data/claude/infrastructure-auth-map.

- server-01 file writes: use docker exec <container> python3 -c (tier-1) for unattended writes;

bare python3 -c * may be tier-2 (NTFY approval). Confirm allowlist state first.

- These 3 agents touch server-01 GPU/models independently → safe to run in PARALLEL,

EXCEPT A1 and A2 both measure VRAM; run A1 first, then A2, so VRAM numbers are additive/coherent.

- A3 runs on PRIMARY (writes a hook script), independent of A1/A2 → fully parallel.

NONE of these agents register the global hook, install the laptop daemon, or make design

decisions. Those are main-session (see §MAIN-SESSION CHECKLIST at the bottom).


AGENT A1 — Install + smoke-test faster-whisper on server-01

You are a setup agent operating on server-01 through the sudo-bridge-server01 endpoint
(http://192.168.1.90:8082 — VERIFY it is reachable before doing anything else). You will
install and smoke-test faster-whisper for GPU speech-to-text. You will NOT touch primary,
the laptop, Ollama's config, or any global hook.

## Task
Get faster-whisper transcribing on server-01's GPU and report exact VRAM headroom while
Ollama is running, so we know STT can coexist with Ollama + (later) XTTS.

## Credentials you will need
- server-01 privileged ops: sudo-bridge-server01 at http://192.168.1.90:8082 — auth key at
  Vault secret/data/claude/infrastructure-auth-map (field: sudo-bridge-server01). RE-VERIFY field name.
- AppRole bootstrap (if Vault read needed):
  VAULT_IP=$(docker inspect vault-iwaulpoi5hwirdlogshmul40 --format '{{json .NetworkSettings.Networks}}' | python3 -c "import sys,json; nets=json.load(sys.stdin); print(list(nets.values())[0]['IPAddress'])")
  ROLE_ID=$(cat /opt/appdata/docker/docker-compose/vault/approle/role-id | tr -d '[:space:]')
  SECRET_ID=$(cat /opt/appdata/docker/docker-compose/vault/approle/secret-id | tr -d '[:space:]')
  # login → token; ALWAYS revoke-self after use.

## Step-by-step (DISCOVERY FIRST — do not assume the environment)
1. Discover: GPU model, driver + CUDA version (`nvidia-smi`), total VRAM, and VRAM currently
   used by Ollama with a model loaded. Discover whether server-01 runs models bare-metal
   (python venv) or in Docker, and where Ollama lives. Record all of this.
2. Choose model size from measured free VRAM: prefer `large-v3` or `distil-large-v3` if it
   fits alongside Ollama with margin; else fall back to `medium`. State the choice + why.
3. Install faster-whisper in the environment matching step 1 (venv or a container). Prefer the
   least-invasive path; do NOT disturb Ollama.
4. Smoke test: transcribe a short built-in/test audio clip (generate one with `say`/espeak or
   a tiny recorded WAV) and confirm the returned text is correct.
5. Report the exact invocation (command or endpoint) that main-session code will call, plus
   measured VRAM free with Ollama + Whisper both resident.

## Output (in addition to the mandatory wrap-up)
Report: GPU/CUDA, environment type (venv/docker + path), chosen Whisper model + rationale,
the exact transcribe invocation, and VRAM: total / Ollama-resident / Whisper-resident / free.

## MANDATORY WRAP-UP (required regardless of success or failure)

Before stopping for ANY reason — task complete, error, or approaching turn limit — output this JSON as your final message. Do not stop without it.

{
  "status": "succeeded|partially_succeeded|failed",
  "actions_taken": ["action 1 — outcome", "action 2 — outcome"],
  "actions_failed": ["action — reason it failed"],
  "notes": "anything relevant for the next session"
}

If you hit --max-turns before finishing, set status="partially_succeeded" and list what remains in actions_failed.

--max-turns 15
If you issue the same tool call or command twice with identical arguments, STOP immediately and output the mandatory wrap-up with status=partially_succeeded.

AGENT A2 — Install XTTS-v2 + clone the Jarvis voice on server-01

You are a setup agent operating on server-01 through sudo-bridge-server01
(http://192.168.1.90:8082 — VERIFY reachable first). You will install Coqui XTTS-v2 and
produce a test WAV in a cloned voice. You will NOT touch primary, the laptop, or any hook.
RUN AFTER A1 so VRAM numbers are coherent.

## Task
Stand up XTTS-v2 for GPU voice-cloning TTS, clone from the provided reference sample, and
emit a test WAV. Measure real-time factor (RTF) and VRAM with Ollama (+ Whisper if resident).

## Context / pre-fetched data
- Reference voice sample (Jarvis), 630s clean mono WAV, will be at:
  <<JARVIS_REFERENCE_WAV_PATH — USER PROVIDES; substitute the real path at launch>>
- Engine: Coqui XTTS-v2 (model `tts_models/multilingual/multi-dataset/xtts_v2`).
  NOTE its license is non-commercial (Coqui Public Model License) — fine for personal use.

## Credentials you will need
- sudo-bridge-server01 auth: Vault secret/data/claude/infrastructure-auth-map
  (field: sudo-bridge-server01). RE-VERIFY.
- AppRole bootstrap as in A1 if a Vault read is needed; revoke-self after.

## Step-by-step (DISCOVERY FIRST)
1. Confirm the environment discovered in A1 (venv vs docker, CUDA). Reuse it; do not rebuild.
2. Install Coqui XTTS-v2 (the maintained `coqui-tts` fork) in that environment. Accept the
   model license non-interactively (set the env var the library expects).
3. Confirm the reference WAV exists at the provided path and is mono, 16k+ Hz. If missing,
   STOP and report — do not fabricate a voice.
4. Synthesize one test sentence (e.g. "All systems are online, sir.") cloning the reference,
   write it to a test WAV, and report the path.
5. Measure RTF (synthesis time / audio duration) and VRAM: total / free with Ollama
   (+ Whisper if A1's model is still resident) / XTTS-resident.
6. Report the exact synthesis invocation main-session code will call, and whether XTTS +
   Whisper + Ollama all fit in VRAM simultaneously (the key coexistence question).

## Output (in addition to the mandatory wrap-up)
Report: install path, test WAV path, RTF, VRAM breakdown, coexistence verdict (all three fit? y/n),
and the exact synthesis invocation.

## MANDATORY WRAP-UP (required regardless of success or failure)

Before stopping for ANY reason — task complete, error, or approaching turn limit — output this JSON as your final message. Do not stop without it.

{
  "status": "succeeded|partially_succeeded|failed",
  "actions_taken": ["action 1 — outcome", "action 2 — outcome"],
  "actions_failed": ["action — reason it failed"],
  "notes": "anything relevant for the next session"
}

If you hit --max-turns before finishing, set status="partially_succeeded" and list what remains in actions_failed.

--max-turns 15
If you issue the same tool call or command twice with identical arguments, STOP immediately and output the mandatory wrap-up with status=partially_succeeded.

AGENT A3 — Write + validate the fail-safe Stop-hook TTS script (primary)

You are a script-authoring agent on the primary server (192.168.1.88). You will WRITE and
VALIDATE a fail-safe Stop-hook script that sends Claude's response text to server-01's XTTS
endpoint. You will NOT register it in settings.json (that is a human main-session step) and
you will NOT touch server-01 or the laptop.

## Task
Create /opt/appdata/docker/.claude/hooks/voice_tts_stop.py implementing a Stop hook that:
  1. Reads the hook JSON from stdin.
  2. GATE: if env var CLAUDE_VOICE != "1", exit 0 immediately (silent no-op). This is what
     keeps every non-voice session and background-agent context silent.
  3. Extracts Claude's final response text from the hook payload.
  4. Fires the text to the server-01 XTTS endpoint as FIRE-AND-FORGET with a SHORT timeout
     (<= 1.5s connect). Do not wait for audio; the laptop daemon handles playback + queueing.
  5. FAIL-SAFE: wrap everything so ANY exception, timeout, or bad payload → exit 0 silently.
     The hook must NEVER raise, never block, never non-zero. Blast radius = zero.
  6. Tag the request with the session/source id so the laptop playback queue can label it.

## Context / pre-fetched data
- The XTTS endpoint URL is not final yet (A2 produces it). Read it from an env var
  VOICE_TTS_URL (default to a placeholder) so main-session can wire the real value without
  editing the script.
- Hook JSON shape: confirm the current Stop-hook stdin schema against an existing hook in
  /opt/appdata/docker/.claude/hooks/ before parsing (do NOT guess field names).

## Step-by-step
1. Read one existing hook in /opt/appdata/docker/.claude/hooks/ to confirm stdin JSON shape
   and the house style.
2. Write voice_tts_stop.py per the Task spec above. Use only stdlib (urllib, json, os).
3. Validate syntax: python3 -c "import ast; ast.parse(open('/opt/appdata/docker/.claude/hooks/voice_tts_stop.py').read())"
4. Test the gate: run the script with CLAUDE_VOICE unset piping a sample payload → must exit 0
   with no network call. Then with CLAUDE_VOICE=1 and VOICE_TTS_URL pointed at a dead port →
   must STILL exit 0 (proving fail-safe), just no audio.
5. Do NOT edit settings.json. Report the exact settings.json Stop-hook registration snippet
   for the human to paste later.

## Output (in addition to the mandatory wrap-up)
Report: script path, ast.parse result, both gate-test outcomes, and the settings.json snippet.

## MANDATORY WRAP-UP (required regardless of success or failure)

Before stopping for ANY reason — task complete, error, or approaching turn limit — output this JSON as your final message. Do not stop without it.

{
  "status": "succeeded|partially_succeeded|failed",
  "actions_taken": ["action 1 — outcome", "action 2 — outcome"],
  "actions_failed": ["action — reason it failed"],
  "notes": "anything relevant for the next session"
}

If you hit --max-turns before finishing, set status="partially_succeeded" and list what remains in actions_failed.

--max-turns 15
If you issue the same tool call or command twice with identical arguments, STOP immediately and output the mandatory wrap-up with status=partially_succeeded.

MAIN-SESSION CHECKLIST (NOT agent-izable — you + Claude in the build session)

These cannot be background agents: they need design decisions and/or live on the LAPTOP, which agents (running on primary) cannot reach.

  1. Laptop audio daemon — one local service that owns:
    • Mic capture from the WorkTunes headset + PTT hotkey (hold-to-talk).
    • STT client: POST captured audio to server-01 Whisper (A1's invocation) → get text.
    • Injection: SSH to primary and tmux send-keys the text into the target Claude pane.
    • Playback queue: single FIFO, consecutive/non-overlapping, source-tagged (main + each agent).
    • Control-command parser: intercept pause <agent> / resume <agent> (and future verbs) as commands, act on the agent's tmux instance instead of sending to Claude.
  2. tmux orchestration — main Claude pane + one pane/window per background agent (up to 5), named so the control parser can target them. Decide the pause mechanism (Ctrl-C interrupt vs. cooperative signal) here — do NOT let an agent guess it.
  3. Global hook registration — paste A3's Stop-hook snippet into settings.json; set the voice env gate in the interactive launch wrapper (so voice = default for interactive, silent for background/agent contexts). End-to-end test the gate.
  4. Streaming TTS — wire sentence-by-sentence synthesis so Jarvis starts talking on sentence 1.
  5. WPM listening test — build + run once XTTS is up (A2): synthesize passages at 150/175/200/225/250 WPM in the Jarvis voice, comprehension check after each, record max accurate WPM → set as default playback tempo.
  6. Training-data logging — voice-session TEXT logged like typed sessions; audio never persisted.