Files
Maven/deploy/maven-voice-tunnel.service
T
claude c5264deb46 Put mavwaked on workpc, where the microphone is (V-515)
mavwaked and mavenclient have been written, tested and deployed nowhere since
V-463 parked them. homesrv has a microphone because it is a laptop, but it is
in the wrong room. workpc is where he sits, and it has a fifine on card 0.

V-515 said this was a config line: "ipc.Dial already speaks
tcp://host:port?token=... so this is config, not protocol work". That premise
is wrong and it is worth writing down. Both mavwaked and mavenclient speak
internal/voice through voice.Dial, not internal/ipc. The netaddr token guards
the daemon-to-daemon IPC seam and never touches the voice wire. That wire is
plaintext with no auth at all, and voice/server.go says so: production binds
inside the wg tunnel, because "the wg layer IS the L0 floor".

workpc is not a wg peer. It sits on wlan0. So the floor here is ssh: mavend
publishes the voice port to homesrv loopback only (127.0.0.1:9110, since host
9100 is Vikunja's MCP), and a user unit on workpc forwards it over his key.
Nothing new is on the LAN. That mattered more than it looks: SurfaceVoice caps
acts at L0, so an unauthorized speaker could not run a destructive tool, but
L0 does not cap reading. A LAN bind would let anyone on the wifi hear his
facts, his notes and his calendar read back.

Two things the deployment found that no test could:

The vendored onnxruntime under deps/ has two copies and the stale one is
1.17.1. The Go binding asks for API 26, so silero refused to load until
1.26.0 was shipped instead. mavwaked logged it and kept running on the energy
threshold, which is the designed fallback working.

The fifine offers 2 channels at 44100 or 48000 and nothing else. mavwaked asks
arecord for 16kHz mono, so hw:0,0 dies on "Channels count non available"
before a frame is read. The unit uses plughw:0,0 so ALSA downmixes and
resamples.

Verified end to end through mavwaked's own -test mode, so no human had to
speak: a 2.43s Russian fixture reached mavend over the tunnel, was transcribed
on the workstation by CW2, routed intent=query, claimed by the calendar
source, and came back as 3.68s of piper audio.

There is still no wake word (V-487 stage two), so the loop runs open. Silero
is passed on purpose, since it declines white noise the energy floor accepts.
Barge-in is not, because its threshold is room-specific and this room has no
number yet.
2026-08-09 12:29:00 +04:00

41 lines
1.5 KiB
Desktop File

# maven-voice-tunnel — the ssh leg that carries the voice wire to homesrv.
#
# Runs on workpc, as a user unit (`systemctl --user`), beside mavgpud.service.
#
# WHY THIS EXISTS AT ALL. internal/voice is plaintext and unauthenticated.
# Its own server doc says production binds inside the wg tunnel, because "the
# wg layer IS the L0 floor". workpc is not a wg peer, it sits on wlan0. So ssh
# is the substitute floor: it authenticates with his key and encrypts the leg,
# and mavend's published port stays on homesrv loopback (127.0.0.1:9110).
# Nothing about this puts a Maven port on the LAN.
#
# Do not replace this with a LAN bind. SurfaceVoice caps acts at L0, so an
# unauthorized speaker could not run a destructive tool. It would still hear
# his facts, his notes and his calendar read back, and L0 does not cap reading.
#
# install: cp to ~/.config/systemd/user/ on workpc
# systemctl --user enable --now maven-voice-tunnel.service
[Unit]
Description=SSH tunnel to mavend's voice wire on homesrv
After=network-online.target
Wants=network-online.target
[Service]
# -N: no remote command, forwarding only.
# ExitOnForwardFailure: fail loudly rather than sit up with a dead forward,
# which is what makes Restart meaningful.
# ServerAlive*: a laptop that suspends drops the tunnel silently otherwise.
ExecStart=/usr/bin/ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o BatchMode=yes \
-L 127.0.0.1:9100:127.0.0.1:9110 \
kami@192.168.1.104
Restart=always
RestartSec=5
[Install]
WantedBy=default.target