A voice companion for Apiary agents, shaped like a dictation app: a menu-bar icon, a key you hold to talk, and nothing else on screen but a small glance panel.
Hold ⌥Space, speak, release. Your words are transcribed on this Mac (Apple's on-device speech, macOS 26), sent as text to the agent through the Apiary host's governed run endpoint, and the reply comes back spoken aloud and shown in the HUD. Voice never crosses the wire in either direction.
Hold ⌥⇧Space to talk about the image on your clipboard — a screenshot, a copied picture — attached to the run so the agent can see it.
Open mic (menu, ⌘M): no key at all. Silero VAD v5 (a 2 MB CoreML model on the Neural Engine, via FluidAudio) hears you start and stop; the streaming transcript sends itself at the end of your turn, and talking over the agent interrupts it (barge-in). Apple's voice processing (echo cancellation) keeps the agent from hearing itself through the speakers. A 1.5 s pre-roll means the first syllable isn't lost while the transcriber spins up. Still nothing leaves the Mac until you've finished a sentence — and then only the words.
The companion is the operator surface: it authenticates to the host as
you (the desktop's per-launch token locally), so what you say is an
instruction, unlike a chat mention, which the agent treats as data. Same
agent, same signed log, same budget — a different door. Runs are tagged
task_class: voice, so a manifest routing rule can send spoken exchanges to
a fast model:
routing:
rules:
- when: task.class == "voice"
use: fastRequires macOS 26 on Apple Silicon and a running Apiary desktop (it writes
~/.apiary/desktop.json, which is how the companion finds the host).
./scripts/bundle.sh
open build/apiary-voice.appFirst launch asks for microphone access. Pick an agent from the menu-bar menu (ratified agents only; the active one is chosen by default). Toggle "Speak replies", pick a voice, copy the last reply, stop speaking.
Settings… (⌘,) records both hotkeys live (click, press a combination
with at least one modifier; Escape cancels, Delete restores the default —
any key + modifiers works, since the app uses Carbon hotkeys) and picks the
folder that delivered images are saved to (default ~/Downloads/apiary- voice/). Changes apply immediately.
Remote host: APIARY_VOICE_HOST=https://… APIARY_VOICE_TOKEN=… (NIP-98
signing for hosts in nip98 mode is on the roadmap).
Text always shows in the HUD beside the spoken reply — some answers cannot
be spoken. Any image an agent hands back is saved to ~/Downloads/apiary- voice/ and opened in Quick Look immediately (agents don't produce images
yet; the delivery half is ready).
Sources/ApiaryVoice/: HotKey (Carbon hold-to-talk, no Accessibility
permission needed), Mic (one shared tap, fan-out sinks, pre-roll ring, echo cancellation), LiveTranscriber (mic streamed into SpeechAnalyzer while you talk — words appear as you speak), VAD (Silero v5 turn events for open mic), ApiaryClient (discovery, roster, AG-UI SSE
run), HUD (non-activating floating panel), Speaker
(AVSpeechSynthesizer), Visual (clipboard in, Downloads+Quick Look out), Settings (hotkey recorder + folder picker, UserDefaults),
AppDelegate (composition root; callbacks flow one way).