# 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 AI", "UnClose AI" ### 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) ### Examples ```python # Correct description='uncloseai-speech API Server' owned_by = "uncloseai" # Wrong description='UncloseAI Speech API Server' owned_by = "UncloseAI" ``` ```markdown # Correct # uncloseai-speech **Raccoon Mission:** Rescue abandoned TTS models and integrate them into uncloseai-speech # Wrong # UncloseAI Speech **Raccoon Mission:** Rescue abandoned TTS models and integrate them into UncloseAI Speech ``` ## Core Principles ### 1. Makefile-First Development **ALWAYS prefer Makefile targets over manual commands.** - ✅ DO: `make deploy`, `make voices`, `make test` - ❌ DON'T: Manual ssh commands, docker commands, curl commands **When adding new functionality:** 1. Add it to the Makefile first 2. Document it in `make help` 3. Test it works from scratch 4. Only then modify other files if needed **Makefile is the source of truth** for all deployment and development tasks. ### 2. Work Locally, Deploy Remotely - **Local development:** `/home/fox/git/uncloseai-speech/` - **Remote server:** `ai.foxhop.net` (configured in `vars.sh`, gitignored) - **Never create remote directories manually** - let Makefile handle it - **Always test from scratch** - `make clean` then `make deploy` ### 3. Configuration Management - `vars.sh` - Deployment secrets (gitignored, never commit) - `vars.sh.example` - Template for users (commit this) - `sample.env` - Default environment (commit this) - `speech.env` - Runtime environment (created automatically by Makefile) **Key environment variables:** - `WORKERS` - Number of uvicorn workers (default: 1 for GPU models like Qwen3-TTS) - Use 1 for GPU-bound models to avoid VRAM duplication across workers - Increase for CPU-bound models like Piper (e.g., WORKERS=4) **Never view or log secrets** - source them and use them. ### 4. Git Commit Guidelines - **Never add AI 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") ### 5. Documentation Requirements When adding features, update ALL relevant docs: - `Makefile` help text - `docs/MODELS.md` for new TTS engines - `docs/MIRRORS.md` for binary downloads - `docs/AUDIT.md` for file changes - This file (`docs/CLAUDE.md`) for new patterns ## Common Tasks ### Full Deployment from Scratch ```bash # 1. Clean everything make clean # 2. Deploy (commit, push, pull on server, rebuild container) git push && tmux send-keys -t 0:1 'cd ~/uncloseai-speech && git pull && sudo docker-compose up --build -d' Enter # 3. Download voices (Piper + XTTS samples) make voices # 4. Test make test make test-xtts ``` ### Adding a New TTS Engine 1. Document it in `docs/MODELS.md` first 2. Add download target to Makefile (e.g., `voices-silero`) 3. Implement engine wrapper in `speech.py` or `src/engines/` 4. Add test target (e.g., `test-silero`) 5. Update `make voices` to include it 6. Test full cycle: commit, push, pull on server, rebuild, test ### Debugging Issues ```bash make logs # Tail live logs make logs | grep ERROR # Filter errors ``` Never use raw docker/ssh commands - extend Makefile if needed. ## File Organization ### Scripts vs Docs - `scripts/` - Executable utilities (add_voice.py, download_samples.sh, etc.) - `docs/` - Documentation ONLY (no executable code) - Dockerfiles, startup.sh - Root level (build artifacts) - Makefile - Root level (primary interface) **Never put executable scripts in docs/ directory.** ### Current Structure (as of 2025-11-09) ``` uncloseai-speech/ ├── Makefile # PRIMARY INTERFACE - always update first ├── vars.sh # Secrets (gitignored) ├── vars.sh.example # Template ├── speech.py # Main server (will refactor to src/) ├── openedai.py # API models ├── voice_to_speaker.default.yaml # Voice config ├── docs/ │ ├── CLAUDE.md # This file │ ├── AUDIT.md # Repository audit │ ├── MODELS.md # TTS engines │ └── MIRRORS.md # Binary mirror strategy ├── scripts/ │ ├── add_voice.py │ ├── say.py │ ├── test_voices.sh │ └── download_samples.sh ├── Dockerfile ├── docker-compose.yml └── startup.sh ``` ## TTS Engine Status ### Default Model (Qwen3-TTS) - ✅ **Qwen3-TTS (tts-1-qwen)** - DEFAULT - 1.7B params, 10 languages, voice cloning, 97ms latency ### 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) ### Why Qwen3-TTS is Default - State-of-the-art quality with voice cloning - Actively maintained by Alibaba - Apache 2.0 license (commercial-friendly) - 10 languages: Chinese, English, Japanese, Korean, German, French, Russian, Portuguese, Spanish, Italian - Fast first-packet latency (97ms) - Easy voice cloning from 3-second samples See `docs/MODELS.md` for complete roadmap and detailed model documentation. ## Production Deployment **Production Server:** `3090-ai.foxhop.net` - **URL:** https://speech.ai.unturf.com (proxied via ai.foxhop.net) - **Repo Location:** `/home/fox/uncloseai-speech` - **Container:** `uncloseai-speech_server_1` (image: `uncloseai-speech:local`) - **tmux access:** Use `tmux-hosts` to discover window mappings, then `tmux send-keys -t 0:1 'command' Enter` - **Current mapping:** window `0:1` is `3090-ai.foxhop.net` (verify with `tmux-hosts`) ### Deployment Workflow **We use git, not rsync.** Commit locally, push, pull on server, rebuild. ``` Local: /home/fox/git/uncloseai-speech/ ↓ git commit && git push Remote (3090-ai.foxhop.net): /home/fox/uncloseai-speech/ ↓ git pull && sudo docker-compose up --build -d Container: /app/ ├── speech.py ├── voices/samples/ (cloned-voices mounted) └── config/ └── voice_to_speaker.yaml ``` ### Quick Production Commands ```bash # Use tmux-hosts to see available tmux windows tmux-hosts # Push changes and deploy git add -A && git commit -m "message" && git push tmux send-keys -t 0:1 'cd ~/uncloseai-speech && git pull && sudo docker-compose up --build -d' 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 ~/uncloseai-speech && sudo docker-compose restart' Enter ``` ## Testing Philosophy **Full stack testing workflow:** 1. Commit and push changes 2. Pull on server and rebuild: `git pull && sudo docker-compose up --build -d` 3. Wait for model to load (check logs) 4. Test via curl or browser **Never assume** - always test from scratch after changes. ## Raccoon Mission Values 1. **Resilience** - Assume upstream dies, plan mirrors 2. **Simplicity** - Makefile > manual commands 3. **Documentation** - Write docs before code 4. **Liberation** - Keep TTS libre (AGPL v3) 5. **Unification** - All TTS engines, one API ## AGPL v3 Compliance **This project is AGPL v3 licensed.** The key obligation: anyone who uses this TTS service over a network must be able to access the source code. ### What This Means Unlike regular GPL, AGPL closes the "SaaS loophole". If you run uncloseai-speech as a service (even without distributing binaries), users have the right to request source code. ### Requirements for Operators When running uncloseai-speech as a network service, you must provide: - Complete source code of the running version - Any modifications you've made - Build instructions ### How to Comply 1. **Link in API response** - Add source URL to `/v1/models` or root endpoint 2. **Link in documentation** - Include repository URL in service docs 3. **Host source code** - Keep your fork in a public git repository ### Example Implementation ```python # In API responses "source_code": "https://github.com/uncloseai/uncloseai-speech" ``` ### Why AGPL? - Ensures forks remain open source - Community improvements flow back to the project - Prevents proprietary TTS services from using our work without sharing back - Aligns with Raccoon Mission: **Keep TTS libre** ## Common Mistakes to Avoid ❌ DON'T create directories with raw ssh ✅ DO add Makefile target for deployment ❌ DON'T use rsync - we use git ✅ DO commit, push, pull on server, then rebuild with docker-compose ❌ DON'T put scripts in docs/ ✅ DO put scripts in scripts/, reference from docs ❌ DON'T hardcode paths/hosts ✅ DO use vars.sh variables ❌ DON'T forget to commit and push before deploying ✅ DO commit, push, pull on server, rebuild container ## When Things Break 1. Check logs: `tmux send-keys -t 0:1 'sudo docker logs --tail 50 uncloseai-speech_server_1' Enter` 2. Check GPU memory: `tmux send-keys -t 0:1 'nvidia-smi' Enter` 3. Restart container: `tmux send-keys -t 0:1 'sudo docker-compose restart' Enter` 4. Rebuild: `git pull && sudo docker-compose up --build -d` 5. Check voice files: `tmux send-keys -t 0:1 'ls voices/samples/' Enter` ## Multiprocess Architecture (uvicorn workers=4) **Key pattern:** Worker processes spawn as fresh imports, don't run `__main__` block. **Solutions implemented:** 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. ## Future Refactoring (Planned) - Move `speech.py`, `openedai.py`, `audio_reader.py` → `src/` - Create engine abstraction layer in `src/engines/` - Unified voice config with engine selection - Binary mirror implementation (MinIO on ai.foxhop.net) See `docs/AUDIT.md` for detailed refactoring plan. --- **Remember:** Makefile first, documentation second, code third. Test from scratch every time. 🦝 **Raccoon Mission:** Keep TTS libre, rescue abandoned models, unify all engines.