Repository navigation
Releases
v0.9.11 — Voice, truthfully
GUS v0.9.11 — "Voice, truthfully"
Four fixes from Glenn's 2026-11-12 call logs:
- Provider failures name the backend the config actually points at. An "openai"-shaped config pointed at Meta's API used to report every failure as "OpenAI returned no text". The label is now derived from the configured base URL at construction: "Meta (muse-spark-1.3) returned no text" — provider display name + model id, for every who-based message (refused / unreadable / no text). A BYOK config pointed at OpenAI still says OpenAI; a local endpoint keeps the class name.
- An empty model reply is retried once before it may fail a job. If the retry answers, its text is returned with token usage summed across both attempts; if it is empty too, the correctly-named error is thrown. Covered for the OpenAI-compatible provider and Anthropic.
- The Shield state is visible in calls. The voice session state carries shieldMode ("fast" when the voice Shield-scan switch is on, "off" when it is off), and the Mac app renders a chip in the in-call strip next to Mute — "Shield: fast scan", or a red "Shield: OFF".
- GUS no longer hears himself. In a built-in (local recognizer + local synthesizer) call, while GUS is speaking — plus a 0.6 s tail — the microphone feeds the recognizer nothing and any in-progress partial is discarded, exactly like the mute path. Accepted tradeoff: in a built-in call you can no longer barge in by talking over GUS (Mute and End Call still work); endpoint calls keep energy barge-in, unchanged.
Suite: 320/320, tsc clean. Swift compiles first on the iMac build, as with 0.9.0–0.9.10.
v0.9.10 — Fast voice scans
Voice turns no longer wait on the full Shield review. With the Settings → Voice Shield-scan switch ON, a spoken turn's ingress scan now runs in Agent-Shield's fast mode (deterministic patterns only; the semantic LLM stage is skipped) — ~1–2s against the full review's ~7–12s, measured live. The verdict, the signed receipt, and every block/flag consequence are unchanged; typed chat, Telegram, and the panel keep the full semantic review. Each voice turn's record names the scan it got (shieldFastMode), alongside the existing scan-skipped-by-operator stamp for switch-off turns. Suite 317/317.
Draft release — the DMG is attached and the release published by the operator per the usual drill.
v0.9.9 — Voice you can test
GUS v0.9.9 — "Voice you can test"
Draft release — DMG + .sha256 to be attached by the operator, then published.
What's new:
- ONE Call button: the top bar's duplicate is removed; the chat composer's Call button is the only one (Invite remains a placeholder).
- Prominent Mute: big, labeled ("Mute"/"Unmute"), in the in-call strip, red while muted. Same capture-drop behavior as 0.9.8.
- Test Connection buttons in Settings → Voice (one for STT, one for TTS): probe the form's CURRENT unsaved values — reachable or not, round-trip latency, and whether the configured model is in the endpoint's model list. No save → call → fail → re-edit loop.
- Test mic and speaker in Settings → Voice: live mic level while you talk, a test sentence through the selected TTS engine (built-in voice or the endpoint), and — for built-in STT — a dictation trial that shows what the recognizer heard AND a speed verdict for this Mac (real time / borderline / too slow, with an endpoint nudge when slow), measured from the end of the phrase to the finished transcript.
- Voice Shield-scan operator toggle (Settings → Voice, ON by default): off skips ONLY the voice channel's ingress Shield scan (faster turns, no injection scan of spoken words); every skipped turn is recorded as scan-skipped-by-operator in voice-turns.jsonl. Other channels, the secret-guard, Governor caps, approvals, and vault rules are untouched.
- Local (built-in Apple Speech + system voices) remains the default engine for both halves; existing voice.json files are never rewritten by the new fields.
Suite: 313/313 passing, tsc clean.
v0.9.8 — Voice, smoothed
GUS v0.9.8 "Voice, smoothed" — the 0.9.7 field call answered end-to-end but took 8–16 s of brain time to say "Hi", and the call controls had two gaps. This release works on all three.
One Call button. The top bar's Call was a Desktop-1 placeholder, disabled unconditionally since before Call GUS shipped — it read as permanently greyed out next to the working composer button. Both places now carry one shared VoiceCallButton: same label, same action, no disabled state.
Mute. An in-call Mute button next to End Call: while muted, capture buffers are dropped whole — nothing reaches the recognizer, no chunks are posted to the session (room noise can't open a sentence or trigger barge-in), any in-progress partial is discarded, and the hearing line reads "Muted". Unmuting restarts listening. The dog-barking control: one click, mid-call.
Latency staging. A turn's record (voice-turns.jsonl) now splits jobMs into queueMs (the serial chain's wait), shieldMs (the ingress scan, timed in the ChannelHost), modelMs and hops (the job's model calls, timed in the CommServer) — all measured at the real seams and delivered back with the reply.
The voice fast lane. A voice chat job is stamped on its job record and steered to a spoken-length answer: a brevity note on the runtime prompt (appended after the Shield scan, which still scans the spoken words exactly as spoken), a 320-token reply budget applied to the Governor reservation and the provider request alike, and a runtime shape of primary call + one continuation carrying a final-call note. A turn that actually invokes tools past that leaves the lane and takes the normal unbounded path — tool use is never broken by the lane. Approvals, the kill phrase, and the ingress scan are unchanged.
Spoken filler. A turn whose job is still running 2.5 s after it started processing queues one "Just a second." segment through the same speech path — barge-in-droppable, at most once per turn, never recorded as a turn.
Suite: 303/303. Draft — publish from the iMac after building GUS-0.9.8.dmg and attaching it here.
v0.9.7 — Voice that answers
GUS v0.9.7 — "Voice that answers"
The 0.9.6 field call heard Glenn fine — the hearing line counted sixteen sentences — and still never spoke: the app's recognizer only ever delivered a transcript on a FINAL Speech-framework result, and nothing ever ended a sentence's audio, so finals essentially never arrived and no transcript ever completed a turn. This release ends sentences, opens the call by speaking, and meets the operator at the macOS settings walls instead of dying on them.
What's new
- The recognizer ends sentences. Partial results are on; the app tracks the sentence in progress and, when its words have been stable ~0.9 s and the mic has been quiet ~0.9 s, calls
endAudio()to force the final — which is POSTed as the transcript exactly as before. A ~50 s backstop banks a long partial before Apple's per-task limit, and an error trailing a delivered final now restarts the ears instead of closing the call. An error with nothing recognized keeps the loud close. - The call opens by speaking. Every call starts with one greeting segment — "Hi — I'm GUS, running on your machine. What would you like me to do?" — as a speak-text segment for built-in TTS or one synthesis through a chosen endpoint, so the speech-out path proves itself in the first second. It's a segment, not a turn (no job, no record), and barge-in cuts it like any speech.
- The Dictation/Siri wall gets a door. Before a built-in call opens (and again if a call falls back to built-in), the app checks speech readiness: never-asked raises the system's own authorization popup; denied raises an in-app prompt with a button to the Speech Recognition privacy pane; authorized-but-unavailable (Dictation/Siri off) raises a prompt with buttons to the Dictation and Siri Settings panes. GUS still can't flip those switches — nobody's app can — but nobody has to go hunting for them either.
Suite: 292/292. Attach GUS-0.9.7.dmg + .sha256 to publish.
v0.9.6 — Voice, built in
GUS v0.9.6 — "Voice, built in"
The 0.9.5 field call heard Glenn fine and still never spoke: every turn died at an unreachable LAN speech endpoint, so no transcript ever existed. A call no longer depends on Docker or the LAN.
What's new
- Built-in speech is the default. Each voice half has an engine in Settings → Voice — Built-in or Endpoint. The app transcribes with the Speech framework (on-device where supported) and speaks with AVSpeechSynthesizer. Existing voice.json files keep their endpoint URLs but migrate to built-in engines on upgrade.
- Endpoints stay — as probed extras. At call start a chosen endpoint is probed (~2.5s); if it doesn't answer, the call resolves to built-in for that call only, the state carries the notice "Speech service unreachable — using built-in voice for this call.", and the setting on file is never rewritten.
- Transcript-driven sessions. In built-in STT mode the app POSTs each final transcript to the session; it takes the identical turn a transcribed utterance takes — Shield scan, speech acts, caps, receipts, approval read-back, kill phrase. Empty transcripts are recorded loudly in voice-turns.jsonl (with the new
sttpath marker) and job nothing. PCM still streams for the hearing ledger; VAD closes job nothing in this mode. - Speak-text segments. In built-in TTS mode replies queue as text segments the app speaks itself; barge-in stops the synthesizer and drops the queue exactly like audio playback. End Call and the kill path stop it too.
- Settings → Voice gains Transcription (STT) and Speech (TTS) Built-in/Endpoint pickers; endpoint URL/model/voice fields remain. New
NSSpeechRecognitionUsageDescriptionin the app bundle.
Suite: 288/288 (7 new: engine config parsing + voiceConfigured, transcript-driven turn, empty-transcript record, local-TTS zero-synthesis proof, probe fallback replaying the 0.9.5 failure).
Glenn's drill: pull, build the DMG, attach GUS-0.9.6.dmg + .sha256 to this draft, publish, Check for Updates, and call — speak right away for the preflight. First call will ask for Speech Recognition permission (new in this release). No Docker, no OMEN, no endpoints needed.
GUS v0.9.5 — GUS publishes GUS
GUS v0.9.5 — GUS publishes GUS
Includes everything in v0.9.4 (voice gain normalization, the lower speech threshold, durable voice-turn records) — v0.9.4 was tagged but never released; install this one instead and skip straight past it.
New: the GitHub publish pack. GUS can now publish his own releases as a job: a control-plane tool takes a tag and the built DMG + checksum pair, verifies the pair locally before any network call, uploads both to the existing draft release using the vaulted publisher key (the key never leaves the control plane), publishes, and verifies the result by reading the release back. Every publish parks for a one-time operator approval in Enforcing mode; under Permissive it proceeds as a recorded let-through.
- Suite: 281/281
Attach GUS-0.9.5.dmg and GUS-0.9.5.dmg.sha256 before publishing (the in-app updater requires both).
GUS v0.9.4 — Louder, and on the record
GUS v0.9.4 — Louder, and on the record
Field report from the first v0.9.3 call: the microphone worked, but the call was quiet — the loudest speech barely cleared the level that counts as speech, so the three utterances were fragments, the transcription service returned empty text for each, and every turn ended in silence. Worse, the reason lived only in the call's memory and was discarded at hangup.
- Utterances are gain-normalized before transcription — a quiet microphone is lifted to a level the transcription service can actually hear (peak-targeted, gain-capped, DC-safe)
- The speech threshold drops from 600 to 350, so quieter speech opens utterances instead of being treated as room noise
- Every voice turn is now written to a durable record (voice-turns.jsonl in the state folder) — transcript, outcome, and the exact failure text when a turn fails
- The finished call's turns stay readable in the session state after hangup, until the next call starts
- Suite: 265/265
Attach GUS-0.9.4.dmg and GUS-0.9.4.dmg.sha256 before publishing (the in-app updater requires both).
GUS v0.9.3 — The microphone, rebuilt
GUS v0.9.3 — The microphone, rebuilt
Field reports from the first live calls: on some Macs the call heard nothing at all — the capture path was built on a format the audio engine reported before it started, and on a real machine that can mean a call that listens to silence forever.
- Capture rebuilt: the microphone tap now runs in the engine's true native format, and the call's audio converter is built from the first real audio buffer, not a pre-start guess
- Voice processing removed from the call path (echo is handled by the interrupt thresholds instead)
- A call now preflights its microphone: if only silence arrives, the call refuses to start within a second and says so plainly — no more fake listening
- If sound reaches the app but the converter produces nothing, the call closes and names the converter as the failure
- The hearing line's "mic" now measures the raw microphone signal before conversion, so mic-vs-level isolates any remaining fault
- Suite: 258/258
Attach GUS-0.9.3.dmg and GUS-0.9.3.dmg.sha256 before publishing (the in-app updater requires both).
GUS v0.9.2 — Hearing, diagnosed
GUS v0.9.2 — Hearing, diagnosed
A patch for the first live calls: some microphones produce a stream whose constant electrical offset reads as endless speech to the call's sentence detector, so a sentence never ends and is never answered.
- Sentence detection is now offset-proof: signal energy is measured around the stream's own baseline, so a constant offset reads as the silence it is
- New hearing line in the call UI: live mic level, the level GUS actually receives, peak, how long the current sentence has been open, and how many sentences have been heard — the call now shows its own diagnosis
- If a microphone produces no usable audio (a converter/voice-processing clash), the call restarts its audio once without voice processing and says so, instead of listening forever
- Suite: 258/258
Attach GUS-0.9.2.dmg and GUS-0.9.2.dmg.sha256 before publishing (the in-app updater requires both).