Voice hub on clipper
Date: 2026-10-16, cc@yacht. Request (Eric): move the whole voice system from yacht to clipper, every Cyberdeck voice interface goes through clipper, no device dropdown on the voice screen.
What runs where now
flowchart LR
iPad["Casework iPad / web Desk / cyberdeck seed CLI"] --> N["Cyberdeck daemon on any node"]
N -- "relay /api/voice/* (voice.hub = clipper)" --> H["Cyberdeck daemon on clipper"]
H -- "signed CreateVoiceSession" --> A["Seed agents server :3053 on clipper (voice branch)"]
A --> L["LiveKit :7880 on clipper (wss :7443 via tailscale serve)"]
L <--> W["seed-voice worker: Deepgram STT, Seed session, Cartesia TTS"]
W -- "MCP tools" --> Hclipper (the hub)
sh.cyberdeck.seed-agents now runs the Seed repo's agents service from the worktree ~/Code/Seed-worktrees/agent-voice/agents (branch voice-tool-feedback-pr at 84671e59e, the exact commit yacht ran). Voice is not on Seed main, and that branch's database migrations (27) are older than the Seed.app binary's (29), so the server has a fresh database agents-voice.sqlite and data dir data-voice under ~/Library/Application Support/CyberdeckSeed/. The Seed.app-binary server's database from this morning is kept beside it, untouched.
sh.cyberdeck.livekit runs livekit-server --config CyberdeckSeed/livekit.yaml (7880, rtc 7881/7882, node_ip 100.72.8.73, clipper's tailnet address). New API key/secret and voice internal token in CyberdeckSeed/secrets/livekit.json (0600), matching runtime.json.
runtime.json gained the voice env (Deepgram and Cartesia keys copied from yacht's experiments server, LiveKit URLs, SEED_AGENTS_VOICE_ENABLED=1, worker child, language multi). Backup of the pre-move file beside it.
tailscale serve: https://clipper.tail0bb35a.ts.net:7443 → LiveKit (the secureUrl every grant carries) and :443 → the Desk.
The OpenAI subscription provider was decrypted from the old database and stored in the new one; cyberdeck seed setup --no-adopt, sync --voice and dogfood were re-run: agents Cyberdeck (voice 739a35c3…, harness 80df194d…), the daily 07:00 Europe/Madrid check-in trigger cyberdeck-fleet-checkin now lives on clipper. Eric's voice profile (db6b0ed5… ×1) was copied to CyberdeckSeed/companion.json, and clipper's config points seed.companionFile / seed.runtimeFile there.
Verified: /api/health voice: true; bun run test:voice (the Seed voice smoke: worker registers, dispatch, room-config, turn stream, leave) passed on clipper; cyberdeck seed call mints a room ws://100.72.8.73:7880 with secureUrl wss://clipper…:7443 and profile.applied: true.
yacht (voice removed)
com.casework.livekit-experiments unloaded, plist moved to ~/Library/LaunchAgents/disabled-20261016-voice-moved-to-clipper/.
CaseworkSeed/runtime.json: SEED_AGENTS_VOICE_ENABLED=0, LiveKit / Deepgram / Cartesia / internal-token keys removed (full backup runtime.voice-backup-20261016.json, 0600). com.casework.seed-experiments restarted and keeps serving the Casework experiments and the "Casework Companion" agent: /api/health says voice: false.
tailscale serve --https=7443 off. Nothing listens on 7880.
Cyberdeck changes (main 76ae89d, deployed everywhere)
New config voice.hub (env CYBERDECK_VOICE_HUB): the paired node that runs the voice system. Set on every host to clipper. A node pinned to another node relays config, livekit, status, transcript, session/reset there, whatever its own bridge says; answers carry via: {node, name}; a hub that is not paired reads as voice off with the reason voice hub clipper is not paired with this node. Naming the node itself means local voice. Without a hub the old discovery (first paired node with voice) still applies.
seed.companionFile / seed.runtimeFile: the hub's profile and env files are configurable.
Web Desk: no browser-side node discovery any more; it only talks to the daemon in view. The bridge strip reads voice clipper; the shell's machine dropdown is hidden on the Desk (visible on every other view). cyberdeck seed status prints voice hub: clipper (…) answers every voice route of this node.
Also landed with it: the three voice-desk routine commits that never reached main (voice relay a108d83, push-to-talk 80370f8, MCP repos filter 2da5952).
docs/VOICE.md rewritten ("The voice hub", the clipper setup, the yacht teardown).
Tests: tests/voice.test.ts 36 (5 new hub tests, the relay suite kept), the Desk e2e test rewritten (hub chip, hidden dropdown). Typecheck and build green.
Rollout
Overlay snapshots host-overlay/<host>-20261016-voice (every host's installed tree committed as is) and deploy branches deploy/<host>-20261016-voice (main merged over the overlay, typechecked and built on yacht) are on origin. Each host: config voice.hub = clipper, git fetch + checkout of its deploy branch, bun install, build, restart.
host | tree | result |
|---|---|---|
clipper | main | hub; |
yacht |
| relays; |
starlight |
| relays, |
enuc |
| relays |
iris |
| relays |
sentinel |
| relays |
botical |
| voice off: |
Live check from yacht's own daemon (headless Chromium, unlocked with the node token): Desk shows voice clipper, no machine dropdown, "tap to talk"; the dropdown is back on the Fleet view.
Not verified / open
A spoken turn through the relay on real hardware (Playwright on yacht cannot publish a microphone). The whole path up to a minted, profile-applied room is verified from every node; the worker side is verified by the smoke test on clipper.
The e2e file on yacht fails its first test at the 5 s navigation timeout under load 13 and the rest of the browser suite cascades (21 of 31); the two Desk e2e tests and the whole voice file pass when run on their own. Same pattern as the 10-15 and 10-16 routine runs.
cx's 6a727f2 (native Afterglow Spotify room) landed on main right after my commit; the deploy branches were cut from 76ae89d, so the hosts other than clipper do not carry it yet.
The hub runs an unmerged Seed branch; when the voice PRs (#1163, #1216) land on main, move the clipper worktree to main and merge or re-create the agents.
Starlight's overlay (71 files vs main, cx's navigation/music work) is only reconciled as far as typecheck; cx should land it in main.
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime