Voice hub on clipper
2026-10-16: the whole Cyberdeck voice system moved from yacht to clipper; every node relays its voice routes there (config voice.hub); the Desk has no machine dropdown.

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" --> H

clipper (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 6a727f2 (cx's commit on top of mine)

hub; voice: ready, profile applied

yacht

736846a

relays; cyberdeck seed call minted via clipper with secureUrl and profile

starlight

b508466 (its 54-file overlay merged with main; two typecheck fixes: route params for Data/Cmux, duplicate AfterglowFrame import; AfterglowFrame/Term/App conflicts taken from main)

relays, configured: true, via clipper

enuc

5990b8c

relays

iris

279c522

relays

sentinel

a7c0936

relays

botical

f06552a (dist built on yacht and copied; public ssh, Tailscale is logged out there)

voice off: voice hub clipper is not paired with this node. Needs tailscale up on botical (the login link is printed by tailscale status there), then pairing with clipper.

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