{"_id":"@anomalypoint/voice-box","_rev":"8-91cb6517a2bc3365a00bac81126c14ec","name":"@anomalypoint/voice-box","dist-tags":{"latest":"3.1.0"},"versions":{"1.0.0":{"name":"@anomalypoint/voice-box","version":"1.0.0","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","audio"],"author":{"name":"AnomalyPoint"},"license":"ISC","_id":"@anomalypoint/voice-box@1.0.0","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/index.js"},"dist":{"shasum":"a6f666c51c8e8e274b20b7cda5d2490eb591b173","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-1.0.0.tgz","fileCount":6,"integrity":"sha512-8QfHeKDohSiKJiI5oMcV4G8kJ3jxVFWMNfDQoaVXDSXtvyH9A0QDKTkVWW+FZ9e1npcQjsc5CvNBVhwFSfrm8Q==","signatures":[{"sig":"MEYCIQDHqPrrIIgyAiLU5SEt5KxOiSb3dscZWbEwF3yVXnJcIQIhAJOsMiLGJrYV9HHgw3IFRlGXGUrV/zjcEDod6m8oiO1R","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31326},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"0ed16f0be2cdd5a55fece44d9494f6a223c9c883","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepare":"npm run build"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP server for text-to-speech using OpenAI TTS with local audio playback","directories":{},"_nodeVersion":"20.19.4","dependencies":{"openai":"^6.6.0","speaker":"^0.5.5","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","dotenv":"^17.2.3","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_1.0.0_1762148137626_0.44433352682022886","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@anomalypoint/voice-box","version":"1.0.1","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","audio"],"author":{"name":"AnomalyPoint"},"license":"ISC","_id":"@anomalypoint/voice-box@1.0.1","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/index.js"},"dist":{"shasum":"95d8db9ec4ee8cea4a368c8a453306888b971479","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-1.0.1.tgz","fileCount":6,"integrity":"sha512-wlG0JIQjPHUmvWcbEvKpfNBjcl6F6Z25Qsw5+UJVqWxmxZPJqHfm6aje8uLQnYvaDn/LMXx0r46EtGrgAnS1Jw==","signatures":[{"sig":"MEYCIQC0gGtow49gqN4I75sYdmCom6xzNV++EvRQrI1aTzXPGAIhALBERY0YyvV2TrOBHXBq8THmMZOOY4ZDKMhqRVMo2O67","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32277},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"1d248b6a18092b64e8cb50ddce8d58edd033a683","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepare":"npm run build"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"MCP server for text-to-speech using OpenAI TTS with local audio playback","directories":{},"_nodeVersion":"22.13.0","dependencies":{"openai":"^6.6.0","speaker":"^0.5.5","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","dotenv":"^17.2.3","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_1.0.1_1762452037045_0.43112091351720094","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@anomalypoint/voice-box","version":"1.0.2","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","audio"],"author":{"name":"AnomalyPoint"},"license":"ISC","_id":"@anomalypoint/voice-box@1.0.2","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/index.js"},"dist":{"shasum":"8de9fbc94585fee496d3767b9c25d7c2dabc0712","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-1.0.2.tgz","fileCount":6,"integrity":"sha512-XjCPOoTPo0ePL385f96EsZm4wtERCWLyvasQtRiMCiMRhaPmTVYnl+aIB60DTbqykupfmk9bz7by9G1Kuxd1ow==","signatures":[{"sig":"MEYCIQDw2jJ71102+FnBk8Hs+j/yIbs1oBiWGiBODELBUaPLmAIhAKcgcjFw6lvFiguSuEJ3Hpo4mvK6jy9BdZoXXRfNkMsK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32279},"main":"dist/index.js","type":"module","types":"./dist/index.d.ts","gitHead":"60a5af64655bb6bfa55fb8ea70e477a5a350b03e","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepare":"npm run build"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"MCP server for text-to-speech using OpenAI TTS with local audio playback","directories":{},"_nodeVersion":"22.13.0","dependencies":{"openai":"^6.6.0","speaker":"^0.5.5","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","dotenv":"^17.2.3","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_1.0.2_1762452527574_0.3388516859514057","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@anomalypoint/voice-box","version":"2.0.0","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"author":{"name":"AnomalyPoint"},"license":"MIT","_id":"@anomalypoint/voice-box@2.0.0","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box#readme","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/cli.js","voice-box-mcp":"dist/mcp-bin.js"},"dist":{"shasum":"4e177942852a4e891997fd357865d3b12907af61","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-2.0.0.tgz","fileCount":54,"integrity":"sha512-BR4/qYZ5bLU3wC91PB+qoTfGOzNGvtJkOEE1SKxX21p1uV5ZSjcr/IeLkhct23L6xsuyQgy1bwc3dSnUl8Cgiw==","signatures":[{"sig":"MEQCIHj+UA9sJ7nsOFr8fbXfC1KMAmk7VRwP3ZTNwi0JeqRnAiAiVZI6B/8RGtym5oohjShFVmG2NOcUH+9nS0LRoPyUrQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":244598},"main":"dist/cli.js","type":"module","engines":{"node":">=18.17.0"},"gitHead":"1314904122631b09fe75b72d8e3fb7770f5dd799","scripts":{"dev":"tsx src/cli.ts","test":"node --import tsx --test \"src/**/*.test.ts\"","build":"tsc -p tsconfig.build.json && node scripts/copy-assets.mjs","start":"node dist/cli.js","doctor":"node dist/cli.js doctor","dev:mcp":"tsx src/cli.ts mcp","prepare":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","directories":{},"_nodeVersion":"22.13.0","dependencies":{"zod":"^3.25.0","openai":"^6.6.0","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_2.0.0_1785352825984_0.4089216453171707","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@anomalypoint/voice-box","version":"3.0.0","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"author":{"name":"AnomalyPoint"},"license":"MIT","_id":"@anomalypoint/voice-box@3.0.0","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box#readme","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/cli.js","voice-box-mcp":"dist/mcp-bin.js"},"dist":{"shasum":"fcf31974712866078b93fa2291741cbf0a74cffc","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-3.0.0.tgz","fileCount":54,"integrity":"sha512-LU5UYI9MTsdrmYEm3OceWm704szqu6xsZKB9zZOiCVSJMIDwTc6aWsF6MVkE2dXlfH1Ax7bcq+OI5/cPHXu52g==","signatures":[{"sig":"MEUCIQC7VJhGw2cb8uX7yncJArkVohWCGzT/2UbJYdcwB+ihoAIgf/edGgZMfYG9T+Tc695sDcChjvQkhhCLDIY65+PV9vA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":279157},"main":"dist/cli.js","type":"module","engines":{"node":">=18.17.0"},"gitHead":"90102318771d32f736856abdc0ff5de71549a34a","scripts":{"dev":"tsx src/cli.ts","test":"node --import tsx --test \"src/**/*.test.ts\"","build":"tsc -p tsconfig.build.json && node scripts/copy-assets.mjs","start":"node dist/cli.js","doctor":"node dist/cli.js doctor","dev:mcp":"tsx src/cli.ts mcp","prepare":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","directories":{},"_nodeVersion":"22.13.0","dependencies":{"zod":"^3.25.0","openai":"^6.6.0","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_3.0.0_1785451987538_0.3777441441782532","host":"s3://npm-registry-packages-npm-production"}},"3.0.1":{"name":"@anomalypoint/voice-box","version":"3.0.1","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"author":{"name":"AnomalyPoint"},"license":"MIT","_id":"@anomalypoint/voice-box@3.0.1","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box#readme","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/cli.js","voice-box-mcp":"dist/mcp-bin.js"},"dist":{"shasum":"48f2ca264b4cfe26255a438cbb08e18161c28b8b","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-3.0.1.tgz","fileCount":54,"integrity":"sha512-kF41y6itlqkL63tllX8Qtm/63ZOAEomhTvTX25ksOAeYQBMUmgTH7sTT9m+MisvEqtrRtq/dMf9iBrCdn86dRg==","signatures":[{"sig":"MEUCIQCHm7hvJmLeeXGlWq+X1AaXQ3zNTCSo9RshNzf8L7LLJQIgbU+lBtAYtM6l3tzyKBGpyLeR5iPfiCneVAwfMNOgjTo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":279682},"main":"dist/cli.js","type":"module","engines":{"node":">=18.17.0"},"gitHead":"86c2ab1d8369fe7722d7655a02aa2b0f46e7f237","scripts":{"dev":"tsx src/cli.ts","test":"node --import tsx --test \"src/**/*.test.ts\"","build":"tsc -p tsconfig.build.json && node scripts/copy-assets.mjs","start":"node dist/cli.js","doctor":"node dist/cli.js doctor","dev:mcp":"tsx src/cli.ts mcp","prepare":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","directories":{},"_nodeVersion":"22.13.0","dependencies":{"zod":"^3.25.0","openai":"^6.6.0","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_3.0.1_1785465953237_0.9524383969277375","host":"s3://npm-registry-packages-npm-production"}},"3.0.2":{"name":"@anomalypoint/voice-box","version":"3.0.2","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"author":{"name":"AnomalyPoint"},"license":"MIT","_id":"@anomalypoint/voice-box@3.0.2","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"homepage":"https://github.com/AnomalyPoint/voice-box#readme","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"bin":{"voice-box":"dist/cli.js","voice-box-mcp":"dist/mcp-bin.js"},"dist":{"shasum":"6745f8f09937140cc3f7f41144c05c236523a811","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-3.0.2.tgz","fileCount":54,"integrity":"sha512-6vm8XjZmnxm4r4azKKHNHlariWF016oma9tUyT4Jyq1k8ku7gH7nVa/AXSIaayyXxTCVXOM7IwJqCZKh0PfOJA==","signatures":[{"sig":"MEQCIC7TFK6AyezcBgMW8Rk7U8Z6tqnpVOryszMHnOZddEYrAiACcBzMfF8v6jWzN7SP23mZFnbwB+ibEa9gm+o9Fz9ZOQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":282233},"main":"dist/cli.js","type":"module","engines":{"node":">=18.17.0"},"gitHead":"ba66caa7e9d8f5a39b4730c13120a40729ca8cb6","scripts":{"dev":"tsx src/cli.ts","test":"node --import tsx --test \"src/**/*.test.ts\"","build":"tsc -p tsconfig.build.json && node scripts/copy-assets.mjs","start":"node dist/cli.js","doctor":"node dist/cli.js doctor","dev:mcp":"tsx src/cli.ts mcp","prepare":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"repository":{"url":"git+https://github.com/AnomalyPoint/voice-box.git","type":"git"},"_npmVersion":"10.9.2","description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","directories":{},"_nodeVersion":"22.13.0","dependencies":{"zod":"^3.25.0","openai":"^6.6.0","@modelcontextprotocol/sdk":"^1.20.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.20.6","typescript":"^5.9.3","@types/node":"^24.9.1"},"_npmOperationalInternal":{"tmp":"tmp/voice-box_3.0.2_1785473951556_0.784990129028672","host":"s3://npm-registry-packages-npm-production"}},"3.1.0":{"name":"@anomalypoint/voice-box","version":"3.1.0","description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","type":"module","main":"dist/cli.js","bin":{"voice-box":"dist/cli.js","voice-box-mcp":"dist/mcp-bin.js"},"scripts":{"build":"tsc -p tsconfig.build.json && node scripts/copy-assets.mjs","dev":"tsx src/cli.ts","dev:mcp":"tsx src/cli.ts mcp","start":"node dist/cli.js","doctor":"node dist/cli.js doctor","test":"node --import tsx --test \"src/**/*.test.ts\"","typecheck":"tsc --noEmit","prepare":"npm run build","prepublishOnly":"npm run typecheck && npm test"},"keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"author":{"name":"AnomalyPoint"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/AnomalyPoint/voice-box.git"},"homepage":"https://github.com/AnomalyPoint/voice-box#readme","bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"publishConfig":{"access":"public"},"engines":{"node":">=18.17.0"},"dependencies":{"@modelcontextprotocol/sdk":"^1.20.2","openai":"^6.6.0","zod":"^3.25.0"},"devDependencies":{"@types/node":"^24.9.1","tsx":"^4.20.6","typescript":"^5.9.3"},"_id":"@anomalypoint/voice-box@3.1.0","gitHead":"5e36a09feb4994de5a8b910bfa5f2e28cdbdc2e4","_nodeVersion":"22.13.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-TySNeBvNZqytiYS8NCgd2d0GczgCUVTZ/aVTBW1VUJa4pmcwke29OoAq7m1SpkoxSDjk4i234RZNlavy6D203w==","shasum":"e9401bcb8a90f1e4cc365edb0fd925e14b828e76","tarball":"https://registry.npmjs.org/@anomalypoint/voice-box/-/voice-box-3.1.0.tgz","fileCount":57,"unpackedSize":341860,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCbHSHKQfBggTNReSo0Kr5LRpBSol7HGolZD3Fx9Eet/QIgG6WPKxk5/fDXWI6EaW8KsMuS1VD0FQTmJGMLV+OPEmA="}]},"_npmUser":{"name":"elmspace","email":"ash@anomalypoint.com"},"directories":{},"maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/voice-box_3.1.0_1785863968567_0.14273254855056727"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-03T05:35:37.507Z","modified":"2026-08-04T17:19:28.892Z","1.0.0":"2025-11-03T05:35:37.834Z","1.0.1":"2025-11-06T18:00:37.212Z","1.0.2":"2025-11-06T18:08:47.771Z","2.0.0":"2026-07-29T19:20:26.144Z","3.0.0":"2026-07-30T22:53:07.699Z","3.0.1":"2026-07-31T02:45:53.380Z","3.0.2":"2026-07-31T04:59:11.704Z","3.1.0":"2026-08-04T17:19:28.726Z"},"bugs":{"url":"https://github.com/AnomalyPoint/voice-box/issues"},"author":{"name":"AnomalyPoint"},"license":"MIT","homepage":"https://github.com/AnomalyPoint/voice-box#readme","keywords":["mcp","model-context-protocol","text-to-speech","tts","openai","elevenlabs","voice","ai-agents","claude-code","audio"],"repository":{"type":"git","url":"git+https://github.com/AnomalyPoint/voice-box.git"},"description":"Local voice control panel for AI agents. Give each agent its own voice, queue and manage what they say, with OpenAI or ElevenLabs TTS.","maintainers":[{"name":"elmspace","email":"ash@anomalypoint.com"}],"readme":"# Voice Box\n\n[![npm version](https://img.shields.io/npm/v/@anomalypoint/voice-box.svg)](https://www.npmjs.com/package/@anomalypoint/voice-box)\n[![npm downloads](https://img.shields.io/npm/dm/@anomalypoint/voice-box.svg)](https://www.npmjs.com/package/@anomalypoint/voice-box)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\n**A local voice control panel for AI coding agents.**\n\nVoice Box lets Claude Code, Cursor, Claude Desktop and other MCP clients talk to you out\nloud — and gives you a control panel to manage them. Each agent gets its own voice, every\nutterance goes through one queue so agents never talk over each other, and you can mute,\nskip, or reassign any of them from a browser tab.\n\nEverything runs on your machine. The only thing that leaves it is the text you choose to\nhave spoken, sent to whichever TTS provider you configured.\n\n---\n\n## Why\n\nRunning several agents at once means several voices at once. Voice Box puts a single\ndaemon in charge of the speaker: agents register with it, their messages are queued\nfairly, and you stay in control of who sounds like what.\n\n- **No native dependencies.** Nothing compiles at install time.\n- **No ffmpeg required.** Audio plays through a player your OS already has.\n- **Multi-agent by design.** One playback lane, round-robin fairness, per-agent mute.\n- **Two providers.** OpenAI TTS and ElevenLabs, chosen per agent.\n- **Keys in one place.** Not duplicated into every project's MCP config.\n\n---\n\n## Requirements\n\n- **Node.js 18.17+**\n- **An audio player** — already present on virtually every system:\n  - macOS: `afplay` (built in, nothing to do)\n  - Windows: PowerShell (built in, nothing to do)\n  - Linux: one of `mpv`, `ffplay`, `mpg123`, or `cvlc` — e.g. `sudo apt install mpv`\n- **Recommended: `mpv`** (`brew install mpv` / `apt install mpv`). Voice Box drives it\n  over its control socket, which is what enables **instant mid-word pause** and **live\n  volume changes** on audio that is already playing. Without mpv everything still works —\n  pause just waits for the current sentence to finish, and volume applies from the next\n  message. If mpv is installed, Voice Box picks it automatically.\n- **An API key** for [OpenAI](https://platform.openai.com/api-keys) or\n  [ElevenLabs](https://elevenlabs.io/app/settings/api-keys)\n\nRun `npx @anomalypoint/voice-box doctor` to check all of this at once.\n\n---\n\n## Quick start\n\n**1. Open the control panel.** This starts the daemon and opens your browser:\n\n```bash\nnpx @anomalypoint/voice-box\n```\n\n**2. Add an API key** in Settings (the gear button). The key is verified against the\nprovider before it is saved, so a typo fails immediately rather than mysteriously later.\n\n**3. Point your MCP client at Voice Box.**\n\n<details open>\n<summary><b>Claude Code</b></summary>\n\n```bash\nclaude mcp add voice-box -- npx -y @anomalypoint/voice-box@latest mcp\n```\n\nAdd `-s user` to make it available in every project.\n</details>\n\n<details>\n<summary><b>Claude Desktop / Cursor / other MCP clients</b></summary>\n\nAdd to `claude_desktop_config.json`, `.cursor/mcp.json`, or your client's equivalent:\n\n```json\n{\n  \"mcpServers\": {\n    \"voice-box\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@anomalypoint/voice-box@latest\", \"mcp\"]\n    }\n  }\n}\n```\n</details>\n\n> There is deliberately **no `env` block**. Keys live in the control panel, so you\n> configure them once instead of pasting them into every project.\n\n**4. Ask your agent to speak.** It registers itself automatically, picks up an unused\nvoice, and tells you where to change it.\n\n---\n\n## The control panel\n\n`npx @anomalypoint/voice-box` opens it at `http://127.0.0.1:4517`.\n\nThe panel is a console: one channel strip per agent, each with a little CRT screen\nshowing that agent's **face** — generated from its identity, glowing in its channel\ncolor. Faces blink, make eye contact with your cursor, animate while their agent is\nspeaking, and fall asleep when it goes offline. A green LED means the agent is\nconnected; a hollow red one means offline (the strip stays fully readable either way).\n\nEach strip carries the agent's queue, its full spoken history, and its controls\n(rename, voice, preview, volume fader, mute, and its own **PAUSE**). The transport bar\non top always shows what is playing, with pause/resume, skip, and clear-queue. Queued\nmessages carry **#1/#2/#3 badges in true play order** (the order the scheduler will\nactually serve them, across agents and priorities), with **PLAY NOW** and **REMOVE**\non each. Every history entry has **REPLAY**; replays go through the same single\nplayback lane, so they never talk over an agent. On narrow windows the strips collapse\nto one, with agent chips to flip between them. Settings (provider keys, audio backend,\nmaster volume) live in an overlay.\n\n**Pause each agent, or everything.** Every strip's own PAUSE lets that agent finish\nits sentence, then holds its queue while the other agents keep talking — nothing held\nthis way ever expires. The transport PAUSE stops the whole lane: instantly mid-word\nwhen mpv is driving playback (and it resumes exactly where it stopped), or at the end\nof the current sentence on the built-in players. While paused, agents keep queueing\nand you can replay older messages — they play immediately, and resume returns to the\nlive queue where it left off. Volume changes reach audio that is **already playing**\nwhen mpv is installed; otherwise they apply from the next message (the fader tells you\nwhich, LIVE or NEXT). A watchdog recovers playback automatically if a player process\never hangs, so the queue can never silently wedge.\n\n---\n\n## How agents get their identity\n\nThis is the part that keeps a long-running setup tidy.\n\n- A **profile** is persistent: name, voice, project, mute state. It survives restarts.\n- A **session** is one live MCP process, bound to a profile.\n\nWhen an agent connects, the MCP process already knows its working directory and process\nid, so it **claims a profile automatically** — no cooperation from the model required:\n\n1. If a profile for that project is free, it is reused, keeping the name and voice you\n   assigned. Restarting an agent creates nothing new.\n2. If another agent is already using it, a new one is minted (`my-project #2`) with the\n   next unused voice, so the two are audibly distinguishable.\n3. If an agent crashes or is force-quit, its slot is released automatically — Voice Box\n   checks whether the process is still alive rather than relying on a polite goodbye.\n\n**Speaking never requires registering first.** The `voice_register` tool only *renames*\nthe profile an agent already has, and it is keyed on project + name, so calling it\nrepeatedly can never fan out into duplicates.\n\n**You own voice assignment.** Once you pick a voice in the panel, agents cannot override\nit.\n\n---\n\n## Tools exposed to agents\n\n| Tool | Purpose |\n| --- | --- |\n| `speak` | Say something out loud. Returns as soon as it is queued, not when playback finishes. |\n| `voice_register` | Give this agent a display name, e.g. its persona. |\n| `voice_status` | Check the queue, and whether this agent is muted. |\n\n`speak` accepts an optional `priority` (`low`/`normal`/`high`/`urgent`) and `wait`\n(`none`/`accepted`/`played`).\n\n### Getting the most out of it\n\nAdd something like this to your `CLAUDE.md` so voice is used well rather than constantly:\n\n```markdown\nUse the voice-box `speak` tool at key moments — starting a task, finishing one,\nhitting a problem, or asking a question. Keep it to a sentence or two of natural\nspeech. Put detail (code, paths, errors, lists) in your text reply instead, since\nspeech cannot be skimmed. Do not narrate every step.\n```\n\n---\n\n## Queue behaviour\n\nOne utterance plays at a time, because there is one pair of speakers.\n\n- **Fair ordering.** Priority band first, then round-robin across agents. One chatty\n  agent cannot monopolise the speaker.\n- **Stale messages expire.** Default TTL is 120s. \"Working on this now\" heard four\n  minutes later is worse than silence.\n- **Muting is free.** Enforced before synthesis, so a muted agent costs nothing in API\n  credits.\n- **Backpressure is per-agent.** An agent that queues faster than the speaker is held\n  briefly; other agents are never blocked by it.\n- **Crashed agents are cleaned up.** Their pending routine messages are dropped.\n\nAll of it is tunable in `~/.voice-box/config.json`.\n\n---\n\n## CLI\n\n```\nvoice-box                    Start the daemon and open the control panel\nvoice-box mcp                Run the MCP stdio server (what MCP clients invoke)\nvoice-box status             Show agents and the queue as text\nvoice-box speak <text>       Queue something to say, for testing\nvoice-box keys set <p>       Store an API key (read from stdin, not argv)\nvoice-box token --rotate     Replace the panel auth token\nvoice-box doctor --selftest  Diagnose the install and play a test tone\nvoice-box start|stop|restart Manage the daemon\nvoice-box logs [-n N]        Show the daemon log\n```\n\n---\n\n## Configuration\n\nEverything lives in `~/.voice-box/` (mode `0700`):\n\n| File | Contents |\n| --- | --- |\n| `config.json` | Settings and agent profiles. Contains no secrets — safe to share in a bug report. |\n| `secrets.json` | API keys, mode `0600`. |\n| `daemon.json` | Runtime pid, port, and auth token. Removed on clean shutdown. |\n| `token` | Panel auth token, mode `0600`. Persists across restarts. |\n| `history.jsonl` | What was spoken. |\n| `cache/` | Synthesized audio, content-addressed and pruned automatically. |\n\nEnvironment variables always take precedence over stored keys:\n\n```bash\nOPENAI_API_KEY=...  ELEVENLABS_API_KEY=...\n```\n\nSet `VOICE_BOX_HOME` to relocate the directory, or `VOICE_BOX_AGENT_NAME` in an MCP\nconfig to pin an agent's name.\n\n> On Windows, file permissions are inherited from your user profile — `chmod` is a no-op\n> there, so the `0600` protection described above does not apply.\n\n---\n\n## Privacy and security\n\n- The HTTP server binds **`127.0.0.1` only**. There is no setting to change that.\n- Requests are authenticated with a 256-bit token stored at `~/.voice-box/token`\n  (mode `0600`) and rejected if the `Host` or `Origin` header does not match\n  loopback — which blocks DNS-rebinding attacks from a malicious web page. The token\n  persists across restarts so an open panel tab keeps working; rotate it any time\n  with `voice-box token --rotate`.\n- The panel receives your API key **only as a masked hint** (`sk-…a1b2`). The raw key\n  never leaves the daemon.\n- Logs pass through a redaction filter, so a key cannot be written to disk by accident.\n- The only network calls are to the TTS provider you configured.\n\n---\n\n## Troubleshooting\n\n**No sound.** Run `voice-box doctor --selftest`. On Linux, install one of the players\nlisted under Requirements.\n\n**\"No text-to-speech provider is configured.\"** Add a key in Settings, or set\n`OPENAI_API_KEY` before starting the daemon.\n\n**The daemon will not start.** Run `voice-box daemon` in a terminal to see the error\ndirectly, or `voice-box logs`.\n\n**A stale agent is listed.** Use the FORGET button on its strip (shown once it is\noffline).\n\n**Pause doesn't stop mid-word.** That needs mpv (`brew install mpv`), then\n`voice-box restart`. Without it, pause takes effect at the end of the current\nsentence.\n\n**Port 4517 is taken.** Voice Box tries 4517–4527 automatically. Pin one with\n`daemon.port` in `config.json`.\n\n---\n\n## Upgrading from 1.x\n\nVoice Box 2.0 is a clean break.\n\n| 1.x | 2.0 |\n| --- | --- |\n| `args: [\"-y\", \"@anomalypoint/voice-box@latest\"]` | add `\"mcp\"` as a final argument |\n| `env: { OPENAI_API_KEY }` in the MCP config | remove it; set the key in the panel |\n| `text_to_speech` tool | `speak` |\n| `voice` and `model` tool arguments | removed — voice is assigned in the panel |\n| ffmpeg required | no longer used |\n\n---\n\n## Development\n\n```bash\nnpm install\nnpm run build\nnpm test\nnpm run dev          # runs the CLI from source\n```\n\nNo bundler and no CDN: the control panel is plain HTML, CSS, and ES modules, served\nstraight from the package, and works offline.\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","readmeFilename":"README.md"}