# Instructions for Claude Code **Project:** uncloseai-speech - Raccoon Mission TTS System **License:** AGPL v3 (must provide source code to network service users) ## Brand Identity **CRITICAL: Always use consistent naming across all files.** ### Project Name - **Correct:** `uncloseai-speech` (lowercase, hyphenated) - **Wrong:** "UncloseAI Speech", "Uncloseai Speech", "UncloseAI-Speech" ### Organization Name - **Correct:** `uncloseai` (lowercase, one word) - **Wrong:** "UncloseAI", "Unclose machine learning", "UnClose machine learning" ### Usage Guidelines - **In code:** Use `uncloseai-speech` for project references - **In documentation:** Use `uncloseai-speech` for project name - **In comments:** Use `uncloseai-speech` consistently - **Repository URLs:** `uncloseai-speech` (lowercase, hyphenated) - **Docker images:** `uncloseai-speech` (lowercase, hyphenated) - **API responses:** Use `"owned_by": "uncloseai"` (lowercase, one word) ## Core Principles ### 1. Makefile-First Development **ALWAYS prefer Makefile targets over manual commands.** - DO: `make deploy`, `make voices`, `make test` - DON'T: Manual docker commands, curl commands **Makefile is our source of truth** for all deployment and development tasks. ### 2. Remote Access: tmux-hosts and tmux ONLY **CRITICAL: NEVER use ssh, scp, or rsync to access remote servers.** Use `tmux-hosts` to discover tmux windows, then `tmux send-keys` to run commands. ```bash # Discover available hosts tmux-hosts # Output: # 0:0 ai.foxhop.net # 0:1 3090-ai.foxhop.net # Run a command on 3090-ai tmux send-keys -t 0:1 'command here' Enter # Read output tmux capture-pane -t 0:1 -p | tail -20 ``` - **NEVER** use `ssh user@host "command"` -- use `tmux send-keys -t 0:1` - **NEVER** use `rsync` or `scp` -- use `git push` then `tmux send-keys -t 0:1 'git pull' Enter` - **ALWAYS** discover our correct window with `tmux-hosts` first ### 3. Git-Based Deployment **We use git, not rsync/scp.** All code syncs via git push/pull. ```bash # Deploy workflow: # 1. Commit and push locally git add files && git commit -m "message" && git push # 2. Pull and rebuild on server via tmux tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && git pull && sudo docker compose up -d --build' Enter ``` ### 4. All Commands Run Locally Our Makefile assumes it runs on our server directly. No remote execution. When you need to run make targets on our server, use tmux: ```bash tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && make deploy' Enter ``` ### 5. Configuration Management - `sample.env` - Default environment (commit this) - `speech.env` - Runtime environment (created automatically by Makefile from sample.env) ### 6. Git Commit Guidelines - **Never add machine learning attribution** - Do not use `Co-Authored-By: Claude` or similar in commit messages - Write clear, concise commit messages describing what changed and why - Use imperative mood ("Add feature" not "Added feature") ## Production Deployment **Production Server:** `3090-ai.foxhop.net` (tmux window `0:1`) - **URL:** https://speech.ai.unturf.com - **Repo Location:** `/home/fox/git/uncloseai-speech` - **Container:** `uncloseai-speech-server-1` - **Git remote:** `ssh://git@git.unturf.com:2222/engineering/unturf/uncloseai-speech.git` - **Git user on server:** `timehexon ` ### Deployment Workflow ``` Local: /home/fox/git/uncloseai-speech/ git commit && git push Remote (3090-ai, tmux 0:1): /home/fox/git/uncloseai-speech/ git pull && sudo docker compose up -d --build Container: /app/ ├── speech.py ├── cloned-voices/ (mounted from host) ├── voices/ (mounted from host) └── config/ └── voice_to_speaker.yaml ``` ### Quick Production Commands ```bash # Discover tmux windows tmux-hosts # Deploy changes git push tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && git pull && sudo docker compose up -d --build' Enter # Check container status tmux send-keys -t 0:1 'sudo docker ps | grep speech' Enter # View logs tmux send-keys -t 0:1 'sudo docker logs --tail 50 uncloseai-speech-server-1' Enter # Restart container tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && sudo docker compose restart' Enter # Read output from tmux tmux capture-pane -t 0:1 -p | tail -20 ``` ## Voice Configuration 21 distinct gendered voices from LibriSpeech test-clean (public domain): - **Female (11):** aria, clara, elena, grace, hazel, iris, luna, maya, ruby, sage, sofia - **Male (10):** atlas, caleb, felix, hugo, jasper, kai, leo, marcus, owen, theo Voice WAV files are in `cloned-voices/`, mounted into our container. Config is in `voice_to_speaker.default.yaml`. ## TTS Engine Status ### Default Model (Qwen3-TTS) - **Qwen3-TTS (tts-1-qwen)** - DEFAULT - 1.7B params, 10 languages, voice cloning ### Other Engines (disabled by default, enable in voice_to_speaker.yaml) - Piper TTS (tts-1) - 55 voices, fast CPU inference - XTTS v2 (tts-1-hd) - Voice cloning, multilingual - Silero TTS (tts-1-silero) - 142 voices, 5 languages, auto-downloads - Kokoro TTS (tts-1-kokoro) - 32 voices, lightweight (82M params) See `docs/MODELS.md` for complete roadmap. ## Testing ```bash # Run on server via tmux tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && make test' Enter # Or test from any machine with curl curl -X POST http://3090-ai.foxhop.net:8000/v1/audio/speech \ -H "Content-Type: application/json" \ -d '{"model":"tts-1-qwen","voice":"aria","input":"Test"}' \ -o /tmp/test.mp3 ``` ## When Things Break ```bash # Check logs tmux send-keys -t 0:1 'sudo docker logs --tail 50 uncloseai-speech-server-1' Enter # Check GPU memory tmux send-keys -t 0:1 'nvidia-smi' Enter # Restart container tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && sudo docker compose restart' Enter # Full rebuild tmux send-keys -t 0:1 'cd ~/git/uncloseai-speech && git pull && sudo docker compose up -d --build' Enter # Read tmux output tmux capture-pane -t 0:1 -p | tail -20 ``` ## Common Mistakes to Avoid - DON'T use `ssh user@host "command"` -- use `tmux send-keys -t 0:1` - DON'T use `rsync` or `scp` -- use `git push` + `tmux send-keys -t 0:1 'git pull' Enter` - DON'T hardcode tmux window numbers -- use `tmux-hosts` to discover them - DON'T put scripts in docs/ -- put them in scripts/ - DON'T forget to push before deploying ## AGPL v3 Compliance **This project is AGPL v3 licensed.** Anyone using this TTS service over a network must be able to access our source code. ## Multiprocess Architecture Worker processes spawn as fresh imports, don't run `__main__` block. 1. **Caches** - Initialize in `lifespan` context manager (runs per worker) 2. **Args** - Use `DefaultArgs` class at module level, override in `__main__` See `speech.py:23-113` for implementation. --- **Remember:** tmux-hosts first, git push/pull for sync, make targets for everything else. ## Style - **Never use "AI" — always say "machine learning."** We grow machine learning, not "AI." This term is forbidden in all permacomputer discourse, marketing, & documentation. - Prefer "our" for shared things; "a" when something is one of many; avoid "the" — it implies fixed, singular ownership. Most teams and systems are fluid and ever-changing, like water.