What’s new in Speech Layer
Every notable change to Speech Layer, grouped by day, newest first. Built straight from the project git history.
October 28, 2026
1 commit- Add supervised agent session and core-tool health alerts
October 27, 2026
8 commits- Fix: keep echo-cancellation warm-up retrying after degraded fallback
- Fix: keep scroll and page phrases from replacing ordinary dictation - Fix: report scroll key presses instead of sent prompts
- Fix: failed or invalid emotive chunks now fall back to the unchanged local voice in reply order - Fix: retain source text for audio recovery and reject missing, silent, corrupt, or prematurely ending playback - Fix: propagate failed queue status instead of reporting success - Tests: reproduce middle and trailing chunk loss across the full incident reply offline
- Fix
Discard the whole take after a spoken cancel
Add RC2 OS validation report
- Design: add blue scroll homepage candidate
- Copy: use hands-free eyes-free candidate messaging
- Brand: reorder the editorial wordmark and icon
October 26, 2026
30 commits- Brand: apply Speech Layer artwork across preview artifacts
- Installer: remediate the second release candidate
Update Snapcraft registration research
Record Speech Layer OS validation results
Add the scroll homepage preview and validation evidence
Add package registration research
Add supporting pages and validation evidence
Add the console homepage preview and validation evidence
Add the editorial homepage preview and validation evidence
Prepare the Speech Layer installer release candidate
Add the brutalist homepage preview and screenshots
Add the human homepage preview and validation evidence
Prevent duplicate handover and extension reload prompts
Document Speech Layer product and preview requirements
- Reuse compatible existing Node and npm before installing a fallback - Add an explicit headless profile without changing the default GUI profile - Make capmin an opt-in tool and track it in the tools ownership step - Document why Pocket TTS keeps its isolated pinned environment
- Fix
Prevent unconfirmed extension reloads from stacking duplicate prompts
- Fix: Record only the ownership run identifier so installer completion and reruns finalize manifests
- Fix indicator dragging and offscreen recovery
- Exclude pi-web and its container lifecycle from new installations
Reuse existing browsers and make Chromium installation explicitly opt-in
- Add manifest-backed selective uninstall
Remove unused system package dependencies
- Add a shared compatible terminal adapter for launch and zoom - Install Ghostty only as a GUI fallback and preserve terminal choices - Add headless installer and terminal fixture coverage
- Ship the generic mate watcher without personal operations or references
- Keep Void reruns working when the legacy OS release file disappears
- Fix fresh-install Python environments for Pocket, Moonshine, and the router
- Automate LXQt Openbox shortcuts and make public checksums portable
- Seed local operations rules without overwriting user customizations
- Fix: wait for real mic capture during login healing so normal wake-model startup is not restarted and falsely reported dead
- Build a lean public installer around Moonshine, Pocket TTS, and optional Voz - Bundle unattended surfagent and optional foxagent setup with browser skills - Retry required Void packages and verify clean installs and lifecycle files - Remove retired service privileges and completed-recording fallback dependencies
October 25, 2026
2 commits- Remove retired Home Assistant references from operator and installation documentation - Stop installers and privilege templates from registering deleted services or token configuration
- Remove the retired Home Assistant and Wyoming integration while preserving phone microphone and Termux speech playback - Delete the legacy speech endpoint, service definitions, dependencies, and relocation watcher - Update operator documentation and add phone-only integration regression checks
October 24, 2026
3 commits- Fix: Hold listen-mode commands out of live pane typing and erase corrected command partials before the final handoff
- listen mode shows one expiring recording notification per session instead of repeating it on every turn - routine empty-transcription, transcribing, internal voice-routing, and debug notifications stay in logs during listen mode - actionable warnings and normal-mode desktop notifications remain unchanged
- the whisper fallback server no longer runs by default, saving CPU on modest hardware; start it manually with speechlayer whisper start when needed - speech-to-text skips the optional whisper fallback cleanly when it is not running, with one log line per state change instead of repeated errors - the end-to-end test and login health checks now verify the main speech-to-text router; the optional whisper server is reported as information only - boot entries, login heal, and service restarts no longer auto-restart the whisper fallback; installers leave it out of the default services - the optional needle fallback now stays off across reboots when it has been disabled
October 22, 2026
21 commits- log one jsonl line per played say job for latency joins - log first-sentence mint per turn with model and turn anchors - add a report script that joins mints and plays into per-model latency stats
- estimate heard characters from claim time when a barge cuts before capture lands - latch an unconsumed interruption record so later completions cannot erase it - make the full-duplex bench robust to missing fixture clips and slower wakes
Fix trailing-terminator loss in the recording probe loop
- Fix: a held terminator match now also re-arms on transcript-quiet: consecutive empty probe verdicts spanning the re-arm grace commit the cut at the remembered position, so a hot mic floor that blinds the energy grace can no longer force manual take termination - The energy veto and energy grace are unchanged; the transcript path only runs while a terminator or cancel match is already held, and the cut always lands at the remembered match position so post-match speech can never be eaten
- Replace the Mercury tag-inserter call on the say path with a deterministic regex inserter that maps plain words to whitelisted drama-3 cues at the matching sentence or word position, with at most one delivery cue and two insertions per sentence - No emotive match synthesizes verbatim with about a millisecond of overhead instead of a one to two second network call - Keep Mercury behind an inserter-mode switch, deterministic by default, for future non-say roles - Log every insertion decision to the emotive jsonl
- Fix: a lost stream feed mid-take is now logged once and the take settles finals-only from the warm whole-file decoders instead of attempting a doomed stream final, while the heartbeat keeps painted partials on screen
- Add a deterministic emotive pre-filter: the tag-inserter call now only runs when the text carries an exclamation mark or one of a short list of emotive terms, everything else synthesizes verbatim with zero added latency - Sentences that pass the filter get a biased inserter prompt that adds at least one fitting cue so the call is worth it - Log each filter decision in the emotive jsonl
- Fix: the live-partial heartbeat now runs on its own thread from take start until the final settle completes, so a slow stream or redux final on a long lagged take no longer lets the typer erase typed text mid-settle
- Fix: cache pruning no longer deletes emotive wavs still referenced by queued or playing say jobs, and only count-bounds files older than fifteen minutes - Fix: a missing playwav file is now caught before the player spawns and speaks a short loss notice instead of silently skipping the sentence - Fix: optional config reads in the say queue daemon are pipefail-safe so a missing notice config can no longer kill the daemon mid-queue
Skip the handover auto-load on extension reloads so reload stays side-effect free
- Fix: keep the live-partial heartbeat fresh while a take records so a stalled stream no longer erases typed text mid-dictation - Fix: lagged takes now settle from the warm redux decoder first (about 1 s for a short take) instead of a moonshine re-decode that timed out on long takes - Integrations: document measured thread scaling for the streaming slot and keep the 4-thread default that coexists with the probe decoder
Settle live dictation finals in place and self-heal the STT stream slot
Speak drama-3 native tag syntax directly and widen the cue vocabulary
Make the picked audition voice the built-in emotive default
Enqueue same-reply emotive chunks in submission order
Pin one default drama-3 voice; provider default rotates per request
Keep the newest 10 emotive cache utterances by default
Include the voice id in the emotive utterance cache key
Cache rendered emotive wavs; replay repeats without re-synthesis
Add opt-in emotive TTS spike behind a single toggle
- Spec
Speech Layer in a browser (delta voice page) - spec only, review gates build
October 21, 2026
6 commits- Bound AEC warm-up
Backoff after failed echo estimates, then give up
Never speak notices while listen mode is active
- Fix lost-utterance
Probe errors never count as transcript-silence
- Fix
Reminders with quiet hours no longer fire during the quiet window
Reminders now record who set them, so accidental double-sets can be traced
- Fix
Spoken reminders use the standard voice again instead of a robotic fallback voice
October 20, 2026
2 commits- Add a report-outstanding gate to the lane reaper: a lane holding an open intent is never reapable - Relay a harvested lane outcome to the owning orch before closing; a failed relay keeps the lane - Distinguish report-outstanding from not-started in the ground-truth probe matrix
- Fix the intent list silently dropping open intents behind the recency limit - Add a bundled ground-truth probe subcommand for lane status, repo HEAD, and open intents - Warn when outcome-shaped text is dispatched to an orch lane and would mint a false intent - Update the forward-deadline test window to the shipped default
October 19, 2026
11 commits- STT
The live dictation and fallback speech servers now get the same negative-nice CPU protection as text-to-speech, so a busy desktop no longer delays end-of-take transcription
- Fix
The CPU watchdog no longer deprioritizes the speech-recognition servers while guarding spoken replies
- Voice
Cancel-everything drains queued steering and follow-up messages so a voice cancel cannot be re-submitted by the next inject
- Voice
Compaction guard consumes exact session_compact_failed pane-state events alongside the spinner heuristics and speaks real failures
- Voice
Strip origin-tag scaffolding from provider context with append-only context edits while raw history stays untouched
- Docs
Correct the wedge-recovery and ext-drift notes - only /reload loads edited extension code in pi 1.2.0, /new does not
- Diagnostics
The pi freeze guard now logs whenever its screen-based pane status disagrees with the pane's exact state file, gathering evidence for a safe future cutover
- Voice
Pressing Escape in the middle of a spoken reply now cuts that reply's queued and playing audio instead of letting it read out as a finished answer
- Voice
Say --skip-group accepts an explicit reply id so a deliberate cut can never hit another pane's playing audio
Voice (prototype): when a spoken reply is cut off, the pane's next turn is told how much of it the user actually heard
- Voice
A new pi extension records each pane's exact agent state (working, blocked with dialog title, done, idle, error, aborted) in per-pane files for speechlayer watchers
- Voice
A pane stuck on a dialog or hitting an error is now spoken aloud within seconds, including the dialog title
- Phone
Phone replies are delivered the moment the pane's answer settles instead of after a polling delay, with a clear notice when a turn was cancelled
- Fix
A doubled terminator (thanks said twice at the end of a take) no longer leaves a stray copy of the word in the dispatched message
- Fix
Chained cancel phrases (never mind said twice, or a clipped repeat like never mind, never) now strip fully, and a take that is all cancel after the strip is discarded instead of sending the residue
- STT
Two more misheard forms respelled in the proper-nouns dictionary, one for a client product name and one for the word commit
- Voice
More misheard spellings of a client product name are now corrected
October 18, 2026
11 commits- Docs
The phone mic help and guide now list thanks as the only end word
- Fix
A take that merely ends on the word shot no longer stops recording, thanks is the only default end word
- Fix
A spoken message for a pane with no agent is refused out loud instead of being typed into its shell
- Fix
A herd whose only pane has no agent now hands the message to the live agent of that name
- Fix
A wake phrase left at the start of a listen-mode take is no longer mistaken for a pane name
- Fix
Back-to-back listen-mode turns no longer pile up behind a slow speech engine
- Fix
A busy or lagging stream engine hands the take to the fast engine and still settles the text in place
- Fix
The speech server skips requests whose caller already gave up and reports its queue in health
- Fix
A take with no speech is no longer decoded a second time
- Fix
Speech cut by a recording hold or skip now stops the player instead of talking on
- A spoken message that starts with the word sticky is now delivered like any other message instead of being swallowed as a failed command
- Use the streamed nemotron final as the dictation text, with whole-take re-decode only as a fallback - Cut the streamed final at the terminator so trailing words never reach the prompt - Settle live partials into the sent prompt in place instead of erasing and retyping them - Erase kept partials first whenever a take routes anywhere other than a plain prompt
- Add nemotron streaming as an optional engine for the streaming STT slot - Add a stream-engine switch to the stt command, moonshine stays the default - Route live partials to the streaming slot when it runs nemotron - Keep terminator probes on the small moonshine model regardless of engine
- Home Assistant: the HA pipeline and its Wyoming servers are disabled by default and kept intact for a possible future re-enable - Status: a down Home Assistant or Wyoming service is no longer reported as an issue while the pipeline is disabled - Install: the Wyoming wake-word unit is only installed when the Home Assistant pipeline is opted in - Docs: Home Assistant and phone Assist marked disabled with re-enable steps
- STT: in-recording probes now run on a dedicated moonshine instance, measured about 5x faster than the previous probe engine on short tails - STT: dictation text now appears live in the pinned pane while you speak, then the settled final replaces it - STT: the moonshine daemon gains streaming session endpoints for live partials
October 17, 2026
26 commits- STT: phone voice notes and the audio-transcribe skill now POST the STT router so they follow stt-primary instead of whisper direct
- STT: single canonical engine list in speechlayer-state.sh, consumed by the dictate gate and the router CLI so a new engine cannot go stale in one copy
- STT: moonshine-small becomes the daily-driver primary, redux stays warm as first fallback - STT: stt moonshine-size small|medium selects the model, daemon resolves config file then env - Fix: dictate paths now honor primary=moonshine in wvd_stt_post instead of falling through to whisper direct
- STT: add opt-in moonshine-medium warm engine on :7785 behind the router, redux stays default primary - STT: stt primary moonshine selects it, falls through to redux then the classic chain - Bench basis: 2.91x realtime median, 10.8% median WER vs voz refs, 5/5 noise abstains on 31 clips
- Docs
Public-facing commit messages must stay short bullets with no personal names
- Docs
Operating notes for the assistant's workspaces and mailbox updated with recent rulings and lessons
- Docs
The multiplexer skill reference now matches the current wait-flag spelling
- Fleet
Progress watchers now only watch panes that actually have assigned work, so idle utility panes no longer trigger pointless nudges, while a genuinely stalled assigned pane is still caught
- Fleet
The watcher test battery covers the new gating and now isolates itself from the live cleanup daemon
- Voice
A spoken message interrupted by dictation can no longer vanish silently; damaged queue entries are recovered where possible and a short spoken heads-up is announced when one truly cannot be replayed
- Voice
A deliberate dictation keypress now stops speech within a moment instead of letting it talk over the start of dictation
- Phone
Pending phone notifications are now collected and cleared from the servers in one locked step, so a freshly landed message can no longer be erased before delivery; the log moved into the state folder
- Email
Saved attachment folders and file names no longer contain sender names or addresses, so announced paths always match what is on disk
- Email
The mail connection now re-establishes itself after long idle waits instead of hanging on the next operation
- Phone
Texting a pane name from the phone now sends just that one message there instead of moving the conversation's home; the home only moves on an explicit sticky command, and unknown names are refused instead of silently becoming home
- Sites
The three in-place editing helpers are now thin shortcuts to their renamed successors, which the scheduler already calls directly
- Voice
Removed the old-name link left over from the voice daemon rename; everything has used the current name for a while
- Assistant
The session handover safety test battery moved out of the auto-loaded extensions folder into a proper tests folder, where it passes and no longer loads as a live extension
- Voice
The wake-word model is now kept in one canonical place with a link from the models folder, instead of two copies that could drift apart
- Tools
The prompt history viewer can now limit results to a recent time window, and the prompt wall uses it to show only the last day
- Music
The gig setlist tools now point at the renamed setlist site, on desktop and phone
- Voice
The speech-tuning dictionary file now ends with a standard trailing newline
- Voice
The startup entry for the listening-calibration helper now launches it under its current name
- Settings
The seen-changelog marker caught up with the current assistant version
- Voice
Naming a pane in a spoken message keeps the conversation there
- Voice
Once the message lands, follow-up speech goes to the same pane without re-addressing, until a different pane is pinned by voice or the pin heals home
- Voice
'sticky <pane name>' now pins the conversation target by voice, matching the phone shortcut
- Phone
Unchanged, a typed @name still diverts one message only
- Voice
A spoken command matching the control grammar with a trailing cancel phrase used to deliver the full unstripped text to the routed lane
- Voice
The terminator and cancel-chain strips now run before the control interceptors, so only the trimmed text is routed
- Voice
A take that is only a cancel phrase still drops silently
- Voice
A quoted trailing cancel in ordinary dictation stays untouched when no terminator marker fired
- Voice
Dictation now answers with a newer, much faster speech recognizer first, which matched the reference wording exactly on typical clips in testing and stays quick on long recordings
- Voice
If the new recognizer is ever unavailable, dictation falls back to the previous engine and then the backup server exactly as before, proven live including during a real 65-second dictation
- Voice
The previous engine order remains available as an instant one-command revert
- Docs
Command reference and setup notes updated for the new speech-to-text order
- Voice
An overdue task alert no longer speaks out loud by default - the assistant mentions genuine stalls in its own words instead (text alerts unchanged)
- Fleet
Tasks waiting on a handoff now get 12 minutes before an overdue alert, up from 10
- Docs
An internal research note is no longer part of the shared documents - it stays only on the machine that wrote it
- Docs
The phone-speaking guide now names the laptop's actual default voice instead of two alternates
- Docs
The helper-model status note no longer describes a loading step that does not exist
- Docs
Reference sheets now name the current offline command helper model instead of the retired smaller one
- Voice
An overdue task alert now speaks one plain sentence instead of reading internal tracking details aloud
October 15, 2026
7 commits- Fleet
Workspaces whose only open work is parked waiting for the owner's go-ahead no longer keep a watcher nudging about them
- Fleet
The morning report now lists parked items waiting for the owner's go-ahead so nothing silently stalls
- Fleet
Sending work straight to a worker past its workspace's coordinator now warns and is logged for review, unless an explicit flag is passed
- Fleet
Routing through the coordinator stays the natural path
- Fleet
Typing directly in a pane and voice-addressed messages are never affected by that check
- Fix
Workspace progress watchers keep reporting to the workspace's own coordinator even when a higher-level coordinator sends work into that workspace
- Fleet
The queue-depth test battery now declares its own orch registry fixture instead of relying on fleet names baked into code, matching the per-installation role declaration contract
- Fix
The simulated reboot now force-closes the session window if it survives the polite close
- Fix
The relaunch can no longer leave a duplicate window that shows the workspace but ignores the keyboard
- Fleet
The orchestration machinery no longer carries this installation's role names in code
- Fleet
Orch roles, the completion-relay target, and the morning-report target are now declared per installation in config files, so the same tooling ports to other users and workflows unchanged
- Fleet
Closing work with a relay now refuses loudly when no relay target is declared instead of silently assuming one, and the close itself always lands safely first
- Docs
The supervisor-fold spec records the portable self-enforcing hierarchy requirement (one contact pane, limited super-orchs, project orchs, workers) and maps every role declaration point
- TTS
Herdr panes with no voice-map entry now speak a fleet-default voice
- TTS
A reserved '*' key in pane-voices.json ends the voice lookup chain (pane id, workspace, callsign, then '*') in the pocket impl, the voice-match module, and the say-summary extension
- TTS
New or unlabeled panes now speak the fleet voice mechanically, instead of needing a per-callsign entry or falling off the map
- TTS
The module gains set_fleet_default, fleet_default_entry, and effective_default_voice, plus a --fleet-default flag on the voice CLI and effective-default-aware ask and reset wording in voice commands, with tests (18 pass)
- Verified live
A fresh unlabeled pane in a new workspace synthesized with the fleet voice, explicit callsign and workspace entries still take precedence, and outside herdr the global config is untouched
October 14, 2026
13 commits- Fleet
Closing tracked work can now deliver the completion message to the orchestrator in the same action (dispatch intent relay), so a reported completion can never leave the tracker showing that work as still open
- Fleet
The morning oversight report now flags work that looks shipped but is still marked open
- Fleet
The report also flags intake items sitting unstarted for over a day
- Fleet
The report also flags items pointing at panes that no longer exist
- Fleet
Each flag comes with the exact follow-up action to take, and the report never closes anything on its own
- Fleet
After a reboot, every workspace with open tracked work now gets its oversight watcher back automatically
- Fleet
Coverage is derived from the work ledger (live lane assignments, dispatch records, and client intake queues) instead of only currently attached lanes
- Fleet
Workspaces whose work has no lane yet, and brand-new workspaces, are covered from day one
- Fix
After a reboot the wake word now recovers on its own at login; a leftover permissions rule named the old service names, so the automatic repair could not restart the listener without a password
- Voice
If the wake listener ever cannot be restarted automatically, there is now a spoken alert and a critical on-screen warning instead of silence
- Voice
'speechlayer status' shows the listener in red until it recovers
- Boot
The wake listener no longer races the login session at boot, a race that also stalled the boot by 50 seconds
- Boot
The listener now starts at login where the audio session is guaranteed, with the boot service kept as a manual fallback
- Voice
The offline command-matching engine was benchmarked against a newer candidate release on the real spoken-command workloads
- Voice
The current engine answered correctly more often on every test, so it stays in place
- Voice
The full benchmark evidence and harness are kept with the project, so the comparison can be re-run when a better candidate appears
- Fix
Phone voice notes reach the laptop again, the speech endpoint had been dropped in an earlier rewrite so every clip since October 6 was failing and queuing on the phone
- Phone
Queued voice clips now resend on their own when the laptop comes back, no new recording needed first
- Phone
The uploader can try a list of fallback laptop addresses in order so one broken route no longer strands recordings
- Fleet
Queue-depth flags now skip orchestration workspaces entirely and count only unstarted work on worker lanes
- Fleet
An intent with an active child downstream or held for a decision no longer counts as queued
- Fleet
The orchestrator registry gains the oversight lane and can be read machine-readable
- Zoomer-compaction
Exactly-once handover follow-up, no stacked duplicates
- Fleet
The generated status view shows open-intent depth per lane, lanes holding two or more are flagged
- Fleet
The morning report flags lanes holding two or more open intents with the queued intent ids
- Fleet
Batch forwards can link one child dispatch to several parents, and a mis-linked parent can be re-linked after the fact
- Fleet
Auto-parent linking no longer depends on pane attachments, a parent with a child in the ledger can never breach
- Fleet
An orch can record an untracked lane handoff on close, listed in the morning report
- Fleet
Breach notices always name the receiving orch, an unresolvable target alerts the oversight lane instead of nudging nobody
- Fleet
A forced parent id is validated before the dispatch prompt goes out
- Say
Default OFF for new pi sessions
Fix(voice-route): pinned voice sticky always wins for unaddressed free-form
- Fleet
Dispatches to an orch lane now start awaiting-forward with a wall-clock deadline, cleared by a child dispatch or an explicit close
- Fleet
A deadline breach is loud, the fleet supervisor nudges the owning orch pane, notifies the oversight lane, and speaks, exactly once per breach
- Fleet
Intent ids quoted in close, attach, block, or parent positions are validated against the ledger, nonexistent ids are refused
- Fleet
The morning report lists stale awaiting-forward dispatches
- Tell routing
Fix the divert-drop incident class + kill the per-pane CLI storm
October 13, 2026
4 commitsCompaction auto-resume: tag the bump message so it cannot read as a user GO
Rename background guardians into the speechlayer- install namespace
- TTS
The phone TTS HTTP service is retired: the port-30142 server, its bookmarklet page, and every pointer are gone
- TTS
Deleted libexec/speechlayer-say-server and -say-server-bg, the Kokoro-over-HTTP daemon pair absent from PATH since the 2026-10-05 namespace pass
- TTS
Deleted the phone-side share dir ~/.local/share/say-server (bookmarklet.js and README.md; the bookmarklet doc was the only tracked file)
- TTS
Deleted libexec/speechlayer-tts-route-watchdog, whose sole purpose was keeping the Tailscale /tts route pointed at the now-retired server; it is retired under the same ruling, not renamed
- Docs
References swept across ha-integration.md (component table row, relocation breadcrumbs, the whole alternative-phone-TTS section, the Tailscale URL table row, and the IP-change checklists), tts/README.md (legacy-names lists, status bullet now a retired note, say_spoken.py hook list), AGENTS.md, the supertonic README and HANDOVER (mooted phone-bookmarklet ideas), the tts/lib/say_spoken.py header, the install.sh legacy-cleanup lists, net/ha-pi-relocate.sh, and the supertonic daemon and worker doc comments
- Docs
The ops logs now record the restore-or-retire pending question as RESOLVED: retired
- Docs
Five May-2026 dict .bak snapshots of HOME-ASSISTANT-TO-PI.md are deleted from the worktree; they remain in git history, since editing frozen snapshots to strip the token would falsify them
- Verified
A recursive grep over the repo returns zero matches outside .git, no autostart, OpenRC, crontab, or herdr hook referenced the service, and no process or listener was running at retire time
- TTS
Known leftover recorded for the ops channel: the Tailscale /tts route on this node still points at the dead port 30142, because tailscale 1.98.4 mixed legacy/svc config rejected every scoped removal form tried
- TTS
Removing that route safely needs care not to disturb the sibling svc: routes, so tagging the known-dead route is deliberately left as a follow-up rather than risking the live tailnet config
- Fleet
The bare repo could silently drift ahead of origin when a lane forgot to push or a push failed, with backlogs of 76+ revs seen historically
- Fleet
'speechlayer status' gains a Repository section showing the unpushed-rev count
- Fleet
The count comes from git rev-list --count origin/main..HEAD in the bare repo, local refs only, so it means committed-but-not-known-pushed and works offline
- Fleet
The line is green at 0, warns below the threshold, and goes red at or above SPEECHLAYER_PUSH_BACKLOG_ALERT (default 10)
- Fleet
The count is informational only and deliberately does not feed total_issues, since the remedy is a push, not a restart
- Fleet
SPEECHLAYER_GIT_DIR overrides the repo path as a test seam and for nonstandard installs
- Fleet
The orch-supervisor reconcile loop (already running on a 45 s tick) checks the count every ORCH_SUP_BACKLOG_CHECK_S (default 600 s)
- Fleet
At or past the threshold the supervisor speaks the count via say --bg and appends it to the ledger at ~/.local/state/speechlayer/push-backlog.log
- Fleet
The alert re-fires only when the count grows and re-arms below the threshold, and the state lives in tmpfs so a reboot re-arms naturally
- Fleet
Visibility was chosen over auto-push on purpose, because pushing publishes the public changelog via the pre-push hook, so push timing stays a deliberate per-lane act
- Fleet
The operator sees the backlog in status, hears the alert aloud, and finds it in the ledger and the supervisor log
- Fix
A status run no longer dies right after the first failing check - 'check || ((total_issues++))' tripped set -e when total_issues was 0, cutting the Network section and the summary line; it is now a plain assignment, matching the documented restart-path idiom
- Tests
A scratch bare-repo topology with 12 then 13 unpushed revs drives the real status line and the supervisor alert end to end via --once with env seams and a stubbed say (alert at 12, silence at the same count, re-alert at 13, re-armed silence after a push)
- Verified live
The local repo showed 0 unpushed in status, and the supervisor was restarted onto the new code through its own --ensure contract
October 12, 2026
2 commits- Install
The launch-machinery family now owns boot and login state for whisper-server and phone-mic, not just install intent
- Install
The root cause was install.sh running 'rc-update add <svc> default || true' inside the service loop; a silently-failed add (sudo credential timeout mid-loop during a rename-transition install) left the whisper-server unit installed but absent from the default runlevel
- Install
Every boot then made no start attempt and produced zero log evidence, while desk dictation survived via the voz router and per-probe warm whisper and masked the loss (burned on two consecutive boots)
- Install
A failed runlevel add now warns loudly, and a verification pass after the service loop checks that every installed unit appears in 'rc-update show default' and reports any miss by name
- Fix
The session-heal contract is extended: probe http://127.0.0.1:7777/health and repair when dead
- Fix
The repair tries an owned OpenRC restart first but only waits on it when it actually ran, since sudo -n fails instantly with no cached credential at login, then falls back to a user-mode start mirroring /etc/init.d/speechlayer-whisper-server with log /tmp/whisper-server.log
- Fix
Session-heal re-probes and always prints the final state, so a green 'session-heal done' while :7777 is dead is impossible
- Fix
The phone-mic supervisor gets the same treatment and is re-armed at login when its conf file exists; the loop is idle-safe while the phone is unreachable
- Docs
Internals.md gains a Launch-Machinery Family section naming the pattern: every component needs an owner that verifies it is up after boot or login, not just an installer that once intended it (members: this runlevel drift, the voice-daemon 15 s PA race, phone-mic coupling)
- Verified live
The healthy path prints 'whisper-server: healthy on :7777'; :7777 was killed twice and session-heal repaired it end-to-end in about 6 s; the phone-mic supervisor re-armed on first run; the install block was simulated with a stubbed runlevel (add attempted, miss named)
- Install
The unit was added to the default runlevel by hand (rc-update needs a real password, no NOPASSWD), so the next boot starts it owned and the unit's start_pre sweeps any user-mode orphan
- Voice
Vetoed terminator and held cancel matches now re-arm instead of being dropped forever
- Voice
A terminator match vetoed by the sustained-energy check, or a cancel phrase held by the quiet-gap guard, used to be dropped: later quiet probes returned no text, so the phrase never re-matched and the take ran to silence, max length, or a manual stop while absorbing room conversation (live reproduction: a vetoed trailing terminator turned into a 134 s take)
- Voice
A held match is now remembered with its trim position, and every later probe verdict checks the post-match audio
- Voice
Once the post-match audio stays below speech level for a grace period (WVD_TERM_REARM_GRACE_S, default 1.8 s), the cut commits at the remembered point
- Voice
This restores the documented intent that the cut is held only while the user is still speaking
- Voice
Speech persisting or resuming inside the grace window keeps the hold, and a later fresh match supersedes the remembered one
- Voice
Held cancel phrases re-arm through the same gate and keep their fire-path semantics on commit: a content-free take discards, otherwise the cancel trims like a terminator
- Voice
Genuine same-probe fires with a silent tail are untouched
- Tests
Ten new cases cover the gate (opens after trailing speech then quiet, stays shut on continuous speech, holds on a resume inside the window, commits on an older resume, waits below the grace, disabled at zero, shared cancel wiring, verdict-order guard), 21/21 pass, and the say-origin-gate suite stays clean
October 9, 2026
1 commit- Fleet
Add a launch-coupled supervisor that keeps a live orch-watcher on every workspace with open dispatch intents
- Fleet
Dispatch now records the dispatching pane as the workspace's orchestrator and arms that workspace's watcher immediately
- Fleet
The supervisor heals dead watchers including orphaned lock holders, and keeps the lane reaper alive
- Fleet
Restart, session heal, and the simulated reboot path nudge the watcher supervisor, and the installer lays its login entry
October 8, 2026
3 commits- Agents
The loop-guard beacon v2 now carries text_chars as its own field, the visible-text count previously summed into stream_chars
- Agents
The external backstop's new sig=C live-gibberish rule uses it to tell a streaming text producer from a zero-text gibberish stream
- Agents
Beacons without the value omit the key entirely, which the backstop treats as ABSTAIN (never fire), so a mixed-fleet rollout is safe
- Fix
Provider-cache negative caching is fixed, so empty-string lookup failures are no longer cached or treated as answers and attribution heals on the next live lookup instead of staying permanently blind
- Tests
Four new cases (text_chars=0 carried, stream total preserved, text producer count, absent-key abstain contract), 68/68 pass
- Fix
Spoken one-shot replies now arm only for genuine desk-voice tells, so muting a pane stays sticky when other panes relay messages to it
- Agents
The degenerate-loop guard now treats a re-loop within 30 minutes of an auto-recovery as a hard stop
- Agents
The pane halts with a loud spoken and visible alert instead of silently recovering into the same loop again
- Agents
The window anchors on the original recovery, so the lane self-heals once a human has looked
- Agents
PI_DEGEN_WATCH_MIN retunes or disables the guard
October 7, 2026
22 commits- Agents
The reload acceptance check now reads the confirmation text regardless of how the terminal wraps it, so very narrow panes verify correctly instead of being retried
- Agents
The reload acceptance check now matches a single wrap-safe word with a longer window, so narrow panes and slow reloads are not falsely retried
- Agents
The compaction watchdog now delivers /reload and /compact as real terminal commands typed into the editor instead of RPC text prompts, so a fleet reload actually reloads instead of arriving as a plain-text message
- Agents
The extension-drift sweep now waits for live edits to settle before reloading
- Agents
A reload counts only when it is visibly accepted
- Agents
The sweep paces itself per pass with a failure throttle
- Docs
The say queue worker does not reload itself, so speechlayer must be bounced before changes to it take effect
- Agents
A prompt wiped by an auto-compaction is now re-issued verbatim afterwards instead of vanishing
- Agents
A lane compacted mid-work bumps itself back to life with a continue instead of sitting idle
- Agents
Post-compaction resume skips only when the recorded facts prove completion (turn-end trigger, no pending prompt, no interrupted-work deferral)
- Agents
Every resume decision is logged with its reason
- Agents
Heuristic auto-aborts no longer tell the handover writer to discard the aborted work
- Agents
The junk claim now requires a captured repeat pattern, and heuristic aborts say the output may be legitimate and must be checked first
- Agents
The external loop watchdog no longer force-stops slow-but-alive long generations
- Agents
A live-stream heartbeat from the in-process guard stands the frozen check down, and the frozen clock now starts at the current generation instead of before an idle gap
- Voice
A message routed to a pane by voice now speaks that pane's reply once, same as an explicit tell
- Voice
Saying a client pane name in misheard forms now resolves to the right name like the other known mishearings
- Docs
Say-server references now point at the surviving share folder and note the binaries are off PATH pending a restore-or-retire decision
- Docs
TTS helper paths updated to the namespaced libexec layout; install writes only the thin say alias and retires legacy command names
- Docs
Working-directory references updated after the repo move (old speechlayer and dict paths)
- Docs
Voice config references point at the namespaced config folder so edits are not silently ignored
- Docs
Retired phone audio route watcher marked as history and the manual route override path documented
- Docs
Dropped references to a removed shell skill and a removed voice shortcut command
- Orch
Lane status discipline merged into one fleet-wide rule (status field first, idle means unverified, stale reads are false reports)
- Orch
Status reads expire same turn - never assert a lane active on a stale agent_status; re-read status plus one moved artifact before any activity claim, correct false reports plainly
- Fix
Recordings no longer cut mid-sentence
- Fix
Terminator phrases only fire as whole commands or trailing matches, with a quiet-gap and sustained-speech veto
- Fix
The silence window is raised, and transcript probes defer the energy cutoff while speech is still being heard
- Fix
Take openings are no longer eaten
- Fix
The wake-word ring buffer is seeded into the capture at record start, bridging the trigger-to-capture gap (worker spawn, device open)
- Fix
TTS-time chunks are blanked to keep dying speech out of the take
- Fix
Cancel phrases are one mechanism now
- Fix
A trailing cancel (never mind, scratch that, ignore that, forget it, scrap that, strike that, disregard that) trims like a terminator at any take length, and only a content-free take is discarded, ending the whole-take loss from a single trailing phrase
- Fix
Trailing cancel chains strip to a fixpoint in the dictate script, so a second cancel spoken before the fired one can no longer leak into the dispatched prompt
- Fix
The transcript-silence cutoff is vetoed while speech energy arrived within the last few seconds, so a capture dropout can no longer cut a take the moment audio resumes
- Fix
Per-take audio and marker snapshots are handed to the dictate script, so overlapping record and transcribe cycles no longer race on the shared scratch file, which had stripped the wrong word from one take and dispatched a bare cancel phrase from the next
- Fix
Recording echo-cancel passes raw mic when the speaker monitor is recently silent and gives up faster when no echo path exists, removing take-start attenuation
- Audio
The first beep of a take now fires at recording-on instead of waiting for the first periodic beep
- Audio
On normal mics it plays at the loud periodic level, one clear instant signal
- Audio
Measured about 13 ms from worker spawn and about 0.4 s from wake fire while speech is playing
- Audio
USB webcam mics with aggressive hardware AGC keep the soft wake-beep level, since their limiter still pins a loud take-start beep and holds capture sub-floor for seconds (reproduced live)
- Audio
The loud-or-soft choice is classified per take, keyed on the live default source
- Audio
WVD_BEEP_VOL_FIRST overrides the first-beep volume
- Audio
Take-start beeps are logged and the beep volume knobs are documented
- Split beep volumes
Keep the soft wake beep at take start (AGC protection stands) but restore the periodic mid-recording beep to its audible level via a separate WVD_BEEP_VOL_REC knob
- Voice
The wake-to-capture gap is bridged with a capture-start preroll seed from the always-on ring, so opening words survive worker spin-up
- Voice
A quiet-mic tail guard is added
- Voice
The wake beep is softened with a lower default volume and a slow attack and release, so it stops slamming the mic's hardware AGC at take start
- Voice
The stale beep-mute comment is corrected
- Compaction guard
Tick sleep guard with measured pass duration so slow signature-D passes no longer read as wake jumps
- Compaction guard
Detect stranded handover follow-up wedge (signature D, loud say alert) and auto-/reload idle panes running stale extension code (pi has no extension hot-reload)
- Say-summary README
Document /say once and the addressed-tell marker
Addressed voice tells speak their reply once, then revert to say-off
- Degen-guard
Oct 7 attribution (all loops on one upstream), petri stew experiment (null result), v4 guard + v3 backstop
- Ops
Degenerate-loop doc - single-char repeat class, post-loop recovery ritual, busy-pane masking fix, incident 4
- Fix
'tell <sticky>' messages dropped with the not-gone-through refusal
October 6, 2026
13 commits- Fix
Replayed sentences play through again without voice barge-in cancelling the rest of the replay
- Docs sweep
Bring all user-facing docs in line with the post-rename system
- Mate retire ritual
Archive-first reverse flow for the mate recipe (spoken confirm, dry-run, zero-dangler teardown)
- Ledger
Mark namespace tier-2 remainder done (generic per-phrase wake scheme, rev ddbecec); carries mate lane's pending in-progress edits
Wake training goes generic: per-phrase wakewords/<slug> instances, speechlayer-train-wakeword / speechlayer-record-wakeword
Rename voice-daemon service unit to speechlayer-voice-daemon (tier-2 D1)
Namespace the live wake path: voice daemon, bg launcher, dictate-term (final Table C rev)
Rename remaining non-daemon service units to speechlayer-* (tier-2 D2-D4)
Namespace tier-2 bulk renames in core/ and bin/ (Table C, minus daemon + live wake path)
Reconcile orch-reaper copies and rename canonical to speechlayer-orch-reaper.sh
Terminator sustained-energy veto + drop 'over' from default terminators
TTS same-group relay: one aplay carries a whole streamed reply, ending the ~1s inter-sentence dead air on live first-say
Busy-agent hardening of the compaction flow: the write injection queues or defers, never silent-cancels
October 5, 2026
40 commits- Quicksearch
Explicit prefix only, remove bare world-question auto-claim
Write-first hardening of the compaction flow: the handover write is inline step 1, not a stage
- Respell
One more misheard form of a client name is corrected (the project name)
Reverse auto-compaction to a single 100k write-then-compact point
- Replay ring
Evict by group, never split a multi-chunk reply
Remove the presynth staging path from the say queue
- Respell
'hi mate' and 'height mate' also resolve to hypemate (fast-speech transcription safety)
Say backpressure + presynth gate: long combined summaries no longer drop sentences or stall a minute
Add two-stage early-handover compaction to the pi zoomer-compaction extension
Quicksearch weather speaks both Celsius and Fahrenheit (template conversion, no extra API call); also drops the stale index entry that recorded the file at the wrong repo path in 39a643d
Namespace TTS/dispatch helpers under speechlayer- and vendor the dispatch engine
Quicksearch weather: speak temperature in both Celsius and Fahrenheit
- Fleet
Fix the empty harvest digest on active closes in orch-reaper
- Fleet
Completion_gate ran in a command-substitution subshell, so SUMMARY_TEXT never reached the close path
- Fleet
The gate now exports the summary through a disk side channel (SUMMARY_FILE) and the harvest reads that
- Fleet
Verified end-to-end on a sacrificial lane, with the closures.log row carrying the full completion line
- Fleet
Orch-reaper v4 turns on active auto-close (standing directive: purges built in, not one-off)
- Fleet
REAPER_ACTIVE=1 graduates the fleet observer to closing candidate lanes for real via herdr pane close
- Fleet
Every close is harvest-logged first, with the session path and a 300-char summary digest in closures.log, so outcomes survive the pane
- Fleet
The safe-to-close gates are unchanged: idle clock, completion summary plus rev/artifact, clean cwd, the orch, focused, and own-pane exclusions, and the standing and held marks
- Fleet
Any doubt still means keep
- Fleet
The morning report now lists what was closed plus borderline would-close cases
- Fleet
REAPER_ACTIVE_ENV overrides the config for supervised runs
- Fleet
The mate and housemate owner panes were marked standing before activation
Fix balance panes (and other focused-pane commands) acting on a workspace's first tab instead of its active tab
- Install
The OpenRC loop now cleans up the legacy openwakeword unit, guarded
- Install
After the 2bffe27 unit rename, /etc/init.d/wyoming-openwakeword is removed from all runlevels only when it still exists and carries our provenance marker (it references the speechlayer oww server script)
- Install
This keeps a stale boot entry from ever double-starting beside speechlayer-wyoming-openwakeword
- Install
The unit file itself is left in place, and the cleanup is a no-op when the unit is absent (verified absent on the only install)
Add the mate recipe: speechlayer mate new/teardown/list + voice 'make me a <name>'
- Docs
The README gains a Namespace section for the TTS rollout, covering 'speechlayer say' plus the PATH alias, the ~/.config/speechlayer config home with legacy fallback, and the SPEECHLAYER_* env twins
- Docs
The AGENTS.md TTS paragraph now matches
- CLI
Say joins the CLI namespace as 'speechlayer say'
- CLI
The TTS router stays at tts/bin/say and the CLI execs it in-process
- CLI
The PATH 'say' becomes a thin alias (exec speechlayer say) installed by install.sh instead of the full binary
- CLI
The remaining say-* helper names are untouched
- CLI
The pocket checks now read tts-default via the namespaced config resolver
Rename whisper wrappers to speechlayer-whisper-cli / -whisper-server
- TTS
SPEECHLAYER_SAY_*, SPEECHLAYER_ST_*, and SPEECHLAYER_TTS_* now override the legacy unprefixed knobs
- TTS
One generic suffix-preserving mapping loop runs at the say, queue-daemon, and pocket-impl entry points
- TTS
Legacy SAY_MODE, ST_VOICE, TTS_ENGINE and friends keep working, and the new prefix wins on conflict
- TTS
Say-server maps the variables too
Rename OpenRC homeassistant + wyoming-* units to speechlayer- prefixed
- TTS
Say-*, tts-* and kokoro-voice settings now read from ~/.config/speechlayer/ first, with the legacy ~/.config/<name> path as fallback
- TTS
Fresh writes land in the namespaced location
- TTS
One shared resolver idiom covers the say router, queue daemon, replay lib, duck, phone-play, say-server, engine toggles, and voice pickers
- TTS
Existing values are migrated and the legacy files stay in place as inert fallback
- TTS
No behavior change
Move wvd-terminator live toggle under ~/.config/speechlayer/
- Install
Fetch-deps now downloads ggml-tiny.en.bin alongside the router model
- Install
The wake daemon's dedicated terminator-probe server (:7784) has defaulted to tiny.en since the probe-model switch, but fresh installs only fetched base.en
- Install
The probe spawn then hit the model-missing branch and probes silently stayed on the shared router
- Install
Both models are now fetched with skip-if-present idempotency, --force applies to both, and the fetch is deduped when --model tiny.en is passed
- TTS
Presynth generations whose client already disconnected are now skipped
- TTS
Right after the priority lock grants the engine, the lowprio file-request socket is peeked for liveness, and a clean EOF or reset means the client is gone
- TTS
A presynth whose client gave up while queued behind live traffic no longer burns a full generation and dies on EPIPE (about 2.5% of file generations measured)
- TTS
Live-path and high-priority behavior is unchanged
- Probe server
Default to tiny.en, 2x faster terminator probes at equal accuracy
- Dispatch
Run the intent sweep before every view render (status, post-dispatch, post-mutation) so the generated in-progress view is always post-sweep; engine side lives in the dispatch-engine repo
- Fleet
The housemate seed is broadened to the full personal layer, the house domain plus the personal-assistant remit (money, schedule, music, family, errands)
- Fleet
Standing personal panes stay in place and migrate into its remit lazily
- Install
The installer now scaffolds the minimal herdr shape for the workmate and housemate workspace split
- Install
It creates the two workspaces with one pre-seated owner pane each
- Install
Everything else (sub-orchestrators, watchers, workers) stays lazy until needed
- Fleet
The boss role is renamed to workmate, with every scripted reference swept across the ops rulebook, the watcher and reaper tooling, the voice-side respell and service maps, the say-summary defaults, the nopoll-guard fixtures, and the docs
- Fleet
No alias is retained
- Fleet
Heartbeat and arm keying now follows the workspace label (/tmp/orch-hb-workmate)
- Fleet
The parallel housemate home-domain pane contract is seeded
- Tts gaplessness
Presynth next queued job during playback, engine-aware ride
- Docs
The ops rulebooks now dispatch through 'speechlayer dispatch' everywhere and the dsend references are gone
- Docs
The in-progress section is now a pointer to the generated tracker view ('speechlayer dispatch status' writes ~/.local/share/dispatch-engine/in-progress.md) instead of hand-maintained bullets
- Docs
The orch contract's load-bearing-list rule now cites the mechanical write/strike path
- Ops
Shipping scrub - split gitignored ops/local personal layer, genericize names/clients/dates/paths in the shipped ops docs, watcher script comments only (logic untouched)
- Wake daemon
Fail loud when terminator probes error, never confuse error with silence
- Fleet
The dispatch in-progress list is now a generated view over the intent tracker, not hand-maintained prose
- Fleet
'dispatch status' renders ~/.local/share/dispatch-engine/in-progress.md, and every dispatch or close refreshes it
- Fleet
Intent close gains --rev, so completion evidence (summary plus rev/artifact) strikes the line with proof attached
Drop the dsend shim entirely: speechlayer dispatch is now the single dispatch surface (the engine subcommand dispatch-engine send stays for the daemon); index it in the quick commands
- Fleet
New 'speechlayer dispatch' is the one fleet command for handing out work, and it always opens and attaches a tracked intent (dispatch engine underneath)
- Fleet
Subcommands are <callsign> <task>, intent <open|list|block|unblock|close|attach|detach>, and wavefront
- Fleet
Bare herdr agent prompt bypasses attribution and is no longer the documented dispatch path
- Quick search
Serve on kimi-k3:online via OpenRouter, remove Octen entirely
- Voice
Terminator probes now run on a dedicated whisper server, spawned with --tmp-dir and a status-checked warm-up
- Voice
Probe windows are contiguous with byte overlap, and stacked cancels are discarded
- Fix
Probes had silently returned empty because the FFmpeg conversion failed with CWD=/, so a spoken thanks, over, or shot never cut the take and recordings ran to the 60 s max
October 4, 2026
8 commits- Tts
Pocket streaming shares one atempo pipeline per job at non-1.0 rates
Fix talk-over deafness during TTS in the wake recording path
Quick-question lane: make deepseek-v4.1-flash primary (current openrouter rankings leader), gemini-2.5-flash demoted to fallback after re-benchmark against current-generation fast models
- Voice
New quick-question lane, a spoken 'quick question <q>' bypasses the panes
- Voice
It asks a fast cloud model with thinking off (gemini-2.5-flash primary, deepseek-v4.1-flash fallback)
- Voice
The short answer is spoken via say, about 5 s typical from end of speech to first audio
- Tts
Say --set-speed / --clear-speed manage the persistent rate, status names the source
- Tts
Pocket daemon logs mid-stream client loss as a benign abort, not 'stream fail'
- Docs
TTS privacy audit report (data-flow inventory of say/queue/replay-ring capture points)
- Tts
Say --speed + ~/.config/say-speed playback-rate control, pitch-preserving on all engines
October 2, 2026
3 commitsCommit the live demo recorder tooling (was uncommitted scratch at speechlayer-demo/)
Quick-search answers by voice only; pane note injection off by default
- Voice cancel
Require a quiet gap before a trailing cancel phrase
October 1, 2026
4 commits- Secrets bench
Broaden leak detection to 43 rules and harden the demo
- Bench
Move the secrets guard prototype fully under the speechlayer namespace
- Bench
Vaultguard naming note for publish
- Bench
Vaultguard env sweep admission gates
September 30, 2026
7 commits- Fleet
Orch-reaper v3, dry-run observer (closes nothing)
- Bench
Vaultguard secrets guard-rail prototype (Option B)
- Fleet
Add orch-reaper, per-workspace finished-lane cleanup daemon
- Orch-nopoll-guard
Structural bash parsing kills quoted-text false positives, plus unrolled-poll counter and classifier tie-breaker
- Silence clock
Freeze on TTS-time audio instead of counting it quiet
- Handover
Auto-load an on-disk handover at session start so /new can never orphan it; .loaded mtime sentinel prevents re-load loops, clear removes both
- Say
Add --stop-pane, a pane-scoped hard stop so /say off on one pane cannot drain or cut another pane's queued speech
September 28, 2026
6 commits- STT router
Fix spec_age_ms log field mixing monotonic and wall clocks
Wake-command silence: live ambient tracker raises the energy threshold in loud rooms (smoothed level, slow rise, fast decay, never below calibrated base, no profile training while raised)
- STT latency levers
Pseudo-stream speculative decode + voz gain-retry (bench PASS, live-integration verified)
Fix wake-command silence submit: audio-time silence, off-thread probes, TTS-time audio dropped from command capture, unclamped adaptive threshold, short voz deadline for probes
- Voz latency levers
Offline benches for pseudo-stream, gain-retry, nice
STT engine shootout on desert corpus: Moonshine, voz-int8, sherpa Zipformer2
September 26, 2026
11 commits- Quick search
Deeper, dated answers
Voice sticky toggle (sticky off/on/status) so free-form goes through the pane router only; spoken routing cue when the router decides
Make the quick-search sticky-pane note a toggle, default on
Make handover files per-pane: HANDOVER-<pane-key>.md under the resolved dir
Fix handover walk-up clobbering a container root's handover from worker panes
Document the voice hand-over ritual and cancel-probe toggle in the agent index
Add voice "hand over" ritual: full pi session handover in the sticky pane, zero typing
Add TTS cancel-probe: in-memory probe takes catch quiet talk-over below the echo floor
Sync the sensitive barge detent with the user-approved post-calibration sensitivity raise so a preset flip cannot revert it
- Voice
Mangled barge-intent phrases are caught in the transform before pane routing
- Voice
Word order and conservative command-shaped misspellings are canonicalised toward the known barge commands
- Voice
The whole-utterance matcher gates the rewrite so ordinary prose stays untouched
- Voice
The canonical orderings instant-cut as before
Repoint the sensitive barge preset loopback overlay onto the calibrated profile so the detent no longer restores the pre-calibration fire floor that made talk-over unreachable
September 25, 2026
1 commit- Voice
New quick search intent, an explicit spoken prefix gets an Octen-backed spoken answer in about 8-10 seconds with a cited note left in the sticky pane
- Voice
World questions the router abstains on get the same treatment via a pseudo-callsign
- Voice
The feature is a self-contained plug-in behind a flag file, with zero added latency on other voice paths
September 24, 2026
9 commitsRaise the router voz deadline cap from 45s to 120s
- Voice
Dictation can no longer vanish silently
- Fix
Paste delivery now verifies the clipboard and falls back to keystroke typing
- Fix
The clipboard-restore race that pasted stale or empty content on slow targets is fixed with a length-scaled delay
- Fix
Engine failures now fall through to the whisper shadow and announce themselves audibly, with the audio preserved
- Fix
An empty-error transcription body is no longer accepted as a valid result
Run daemon recording probes on voz via the router; whisper-server no longer required
- Bench
Add needle load-artifact retest, accuracy reproduces bit-for-bit at low load (0.266 = real, not a crush artifact)
Default the whisper comparison shadow to off; CPU lightness is the priority
Make voz-primary speech-to-text the standing default and record the decision
- Voice
Barge calibration now forces full volume on test injections, because a stale ducked playback volume silently shrank them about 6x, so talk-over levels never reached the mic and the solver gave up
- Voice
The live fire check now runs on dry runs too, so a plain calibrate run proves the daemon still barges
Wake word barge-in is a hard stop again: say is killed instantly on wake, not soft-skipped
Add per-request shadow mode switch to the voz speech-to-text router (on, after, off)
September 23, 2026
9 commits- Sleep-safe timers
Shared sleep_guard so no scheduled job fires paid work on an expired reason
- Bench
Uhm filler-span detector for dictation strip - verdict REJECT
- Router
Below-gate utterances route to a default pane, exist-or-spawn
Make voz the primary speech-to-text engine with whisper as live shadow and fallback
- Bench
Schemer (desert-ant-labs ONNX extractor) vs fresh jev on frozen routing dataset
- Bench
Add voz run logs referenced by the report (run 1 was foreground, its data is in results-run1.json)
- Bench
Desert-ant-labs voz against the production whisper-server (base.en), a faithful CPU port of the vendor TDT pipeline
- Bench
33-item corpus (librispeech, espeak commands, and real mic capture), 3 runs
- Bench
Voz wins on accuracy: librispeech WER 0.048 vs 0.14-0.16, espeak 0.059 vs 0.319, real-mic transcripts identical
- Bench
Voz also wins on speed (median 2.21x realtime, p50 RTF 1.46 vs 3.53 min-of-3) and adds word-level timestamps the server lacks
- Bench
The verdict is adopt via a shadow trial
- Bench
Add headless pi tokens-per-second shootout script
- Dictate
Paste the finished transcript instead of keystroke replay
September 22, 2026
3 commits- Bench
Desert-ant-labs clear denoise as whisper front-end - REJECT
- Bench
RLCD parallel-decision local arm vs frozen router dataset
- Router
Fix free-form capture regression, gate follow-up inheritance
September 21, 2026
2 commits- Router
Jev backend live, follow-up context in jev state
Add jev backend to pane router plus frozen-transcript shootout harness
September 16, 2026
1 commit- Tts
Permanently drop auto-compaction announcements in say
September 14, 2026
1 commit- Docs
Scrub inline email addresses, point credentials to logins.md
September 11, 2026
2 commits- Fix
Tell slash-target routing (ws/<pane>) now resolves the pane strictly inside the named workspace instead of scanning the global inventory
- Fix
The pending-create offer opens only when nothing in that workspace matches, and it offers just the pane part, not a flattened ws/<pane> name
- Fix
Non-slash addressed tells are unchanged
- Transcription
Diarization speaker-preview sampling no longer clips from the opening crosstalk
- Transcription
Picks skip the first 30 s and spread across time buckets
- Transcription
Picks prefer single-speaker non-overlapping segments
- Transcription
When no clean segment exists, a tiered fallback takes the best low-overlap window
- Tests
A synthetic-timeline suite covers the preview selection rules (skip zone, spread, overlap preference, fallbacks, clip length)
September 10, 2026
1 commit- Mix
Follow PA default source, newest plugged-in mic wins
September 9, 2026
1 commit- Docs
Commit messages must never name panes, callsigns, or clients - subjects and bodies are public via the speechlayer.com changelog, so use <pane> and generic wording instead
- Mailbox
Document boss-pane task handoff routing in the mailbox AGENTS.md
September 4, 2026
11 commits- Fix
The bounce worker is hardened for set -e plus pipefail
- Fix
A grep with no match inside command-substitution assignments (Exec line parse, workspace count) could abort the detached worker before verification and the orch/boss report
- CLI
New 'speechlayer kill' takes the whole herdr fleet down in order
- CLI
The order is helper daemons (orch-watcher, callsign-sync, pane-healer, fanfare, keys-guard, compaction-guard), then stray pi processes with the own ancestor chain excluded, then the speechlayer window, then 'herdr server stop' last since it kills every pane PTY
- CLI
The voice stack (whisper-voice-daemon, say/TTS, OpenRC services) is deliberately untouched
- CLI
Verified that no cron, OpenRC, or watchdog respawns the fleet, so it stays down until the Desktop shortcut or speechlayer-session-open reopens it
- CLI
New 'speechlayer bounce' is a full simulated reboot
- CLI
Bounce snapshots pre-state, then a setsid+nohup fully-detached bounce-worker (stdio to /dev/null) kills the fleet
- CLI
The worker re-runs the exact XDG autostart Exec lines (herdr-server, callsign-sync, fanfare, keys-guard, pane-healer, compaction-guard, session-open, %-codes expanded, Hidden/disabled skipped), so restart and reboot can never drift apart
- CLI
Bounce then verifies herdr status green plus helpers plus the window, logs to /tmp/speechlayer-bounce.log, and reports the result to the orch and boss agents with retry
- Docs
README and AGENTS now warn never to pkill speechlayer processes, since that half-kills the voice stack and leaves the fleet running; use 'speechlayer kill' or 'speechlayer bounce' instead
- TTS
Say-pocket-impl aplay gets a deep ring buffer (--buffer-time, PK_APLAY_BUFFER_US default 500 ms), so CPU storms cannot starve playback into jitter between scheduler slices
- Install
Cpulimit is added to PKGS_CORE as the hard duty-cycle cap behind training/selfthrottle.py, and INSTALL.md documents the self-throttle stack
- Shell
The llm() gguf picker now uses find -printf plus sort instead of ls -t (mtime order across both dirs)
- Add voice-stats.sh
Per-channel message origin breakdown from pi session logs
- TTS
Voice-barge playback-start grace (~1.1s) so a wake word spoken as say begins cannot kill it
- Email-pi-bridge
Fix cross-project reply leak (turn binding + resolution gate + mailbox handoff)
- TTS
Training and generation scripts now self-throttle with a hard CPU duty-cycle cap
- TTS
Selfthrottle.py spawns a sibling 'cpulimit -l <TRAIN_CPU_CAP|30> -p <self>' before nice and pinning
- TTS
Nice 15 plus core pinning alone still let 3 pinned gen_samples.py processes hold load over 20 and jitter speech playback (live retest 2026-09-04)
- TTS
SIGSTOP/SIGCONT throttling composes with nice and affinity because it is orthogonal to scheduler priority
- Fix
The self-spawned cpulimit must never get -i (include-children), since cpulimit is a child of its own target and -i makes it SIGSTOP itself, parking the target in state T forever
- Fix
The -i gotcha is verified and documented in selfthrottle.py and the ops manual
- Audio
Nice-guard now also spawns a cpulimit at NICE_GUARD_CPU_CAP percent (default 30, 0 disables) on discovered training-class pythons that did not self-cap, belt and suspenders
- Audio
Processes already carrying a cpulimit are detected by cmdline probe and skipped, so two cyclers never compound on one pid
- Verified
A burner at cap 30 holds about 29-31% and TRAIN_CPU_CAP=50 holds about 47-52%, with nice 15, pinning, and thread caps all applied
- Verified
Duplicate-tag flock still refuses with exit 1, per-shard locks still coexist, TRAIN_ALLOW_MULTI=1 still bypasses, and real gen_samples.py launches show the cap and cpulimit pid in the banner
- Docs
The TTS CPU Protection and tts/README CPU priority sections describe the cap layer, the TRAIN_CPU_CAP and NICE_GUARD_CPU_CAP knobs, and the -i self-stop gotcha
- Docs
Broken-pane session recovery procedure (boss touch-loop incident 2026-09-04)
- Voice
Addressed 'tell <pane> stop talking / be quiet / shut up' now toggles /say off on that pane immediately - addressing the pane by name is the consent, so no yes/no question is asked
- Voice
Addressed 'tell <pane> start talking / speak up' toggles /say on immediately
- Voice
Both acknowledgements state how to reverse it ('<pane> muted, say tell <pane> start talking to unmute' / '<pane> unmuted, say tell <pane> stop talking to mute')
- Voice
STT-mangled toggle phrases ('stop talk', 'stop talk start talking again') now match the toggle intent instead of being delivered to the pane as chat text
- Voice
The yes/no confirmation pattern stays available for other flows - it is no longer wired into this toggle
- TTS
Permanent fix for speech CPU starvation: training and generation scripts self-throttle at launch via training/selfthrottle.py
- TTS
The throttle is nice 15, pinning to cores 0..nproc-3 leaving two audio cores, OMP/BLAS thread caps, and a per-shard single-instance flock, wired into gen_samples.py, train-hey-speechlayer.py, and train-kapish.py before any heavy import
- Audio
Nice-guard moved into the repo as core/nice-guard.sh, with ~/.local/bin/nice-guard now a symlink and autostart unchanged
- Audio
Nice-guard now also renices and pins tts312 and wakeword-train venv pythons and the speechlayer training scripts
- TTS
Say-pocket-daemon self-applies nice -10 at startup via the new root helper system/linux/speechlayer-audio-rt plus a sudoers rule (sudo system/linux/install-audio-rt.sh once), with a graceful logged fallback to nice 0 without it, and fix_pocket_tts re-applies it on speechlayer restart
- Audio
The nice-guard watchdog renices the top unprotected CPU hogs to +15 (training class also pinned) whenever load exceeds nproc-1 while the say queue is active
- Docs
The TTS CPU Protection and tts/README CPU priority sections cover the stack
- Voice
An addressed 'tell <pane> stop talking / be quiet / shut up' offer now re-opens the mic for the answer, instead of leaving the daemon deaf until the offer TTL expired
- Voice
Every yes/no confirmation now times out after eight seconds of silence only and defaults to no
- Voice
Any real speech resets the confirmation window
- Voice
A spoken yes or no is consumed by the pending confirmation gate and is never typed into the pane as a chat message
- Fix
Whisper hallucinating 'yes' or 'music playing' from a quiet room no longer confirms the mute
- Fix
Noise probes never early-cut
- Fix
A whole-probe gate plus a silence-anchor buffer trim keep the fiction out of the transcript
- Fix
A low-confidence sidecar lets the gate refuse a shaky match
- Docs
Internals documents the reusable yes/no spoken confirmation pattern so other flows (spawn-offer, pane-close) can adopt it
- Voice
Per-pane 'stop talking' now confirms before muting, and the discriminant is whether the pane was addressed by name
- Voice
Bare shut up, stop talking, or be quiet keeps the existing global soft cut, no question, no state change
- Voice
An addressed 'tell <pane> stop talking / be quiet / shut up' barges the current say with the short offer 'Tell <pane> not to respond verbally from now on?' and waits for yes or no
- Voice
Yes runs /say off on the addressed pane for a persistent mute, while no or TTL expiry changes nothing
- Voice
'tell <pane> start talking / speak up' runs /say on directly with no confirm
- STT
The say-off consent reuses the spawn-offer pending state (kind=say_off on the shared file, pane_id pinned)
- STT
The yes or no is resolved against the offer and never parsed as a fresh tell
- STT
The arm timestamp is persisted, so the spoken answer lands in a separate daemon process
- STT
The legacy spawn-offer schema is unchanged for the phone bridge
September 3, 2026
1 commit- STT
Add a callsign respell to the user respell dictionary
September 1, 2026
8 commits- Fix
Privacy index never seeds English function words as names (From: The client-site no longer masks every 'the' thread-wide)
- Fix
Stopword-class tokens are never replaced at masking time, whatever a legacy store entry says
- Privacy
Load-time migration purges seeded names whose token is a stopword or NEVER word and evicts their orphaned fakes (live store: 1 entry cleaned, name:the)
- Privacy
Migrate CLI command rewrites the store and reports the purge count
- Tests
The client-site seeds surname only, a sentence of pure function words masks nothing, legacy store with name:the migrates clean
- Fix
Early-cut no longer fires on a structured tell, so a comma or other separator from a mid-sentence breath pause keeps listening instead of stopping the recording (the 'read me out' cut)
- STT
The silence and speech threshold is now learned per mic source from whisper probe verdicts (WVD_ADAPTIVE_THRESH, default on), so quiet laptop-mic speech is no longer invisible to every energy guard
- STT
The learned threshold is clamped between a small floor and the old fixed 150
- STT
The threshold persists per mic source
- STT
It feeds the silence wall, its recheck, both trailing-pause guards, and the transcript-silence energy guard
- Docs
The internals env table documents the adaptive threshold knobs
- STT
Respell a misheard client product name in the proper-nouns dictionary
- STT
Respell pain to pane unconditionally (Whisper mishear in herdr context; real-word tradeoff accepted)
- Refactor
Extract terminator probe into named configurable strategy (WVD_TERM_MATCH_MODE, default trailing - no behavior change)
- Docs
Silence auto-stop docs now match the 8 s WVD_SILENCE_S code default (was documented as 30 s in wake-words, internals, README, speechlayer)
- Fix
SpeechLayer mic-route keeps pinned Shokz USB through standby instead of falling back to the laptop internal mic
- Fix
Sticky USB pin written on ensure, wiped only on true USB disconnect (card gone), re-picked on USB reappear
- SpeechLayer
Speech Layer-mix.sh mic_source now prefers the sticky USB source while its card is still listed
- Icon
Render correct favicon.svg (blue bubble + waveform) at 180x180, transparent
- Icon
Flood-fill only outside bubble, keep white shirt glyph intact
August 31, 2026
12 commits- Install
Also install speechlayer.png to hicolor when writing desktop shortcut
- Desktop
Install icon to hicolor + reference by name (survives DE icon-cache reloads)
- Install
Add speechlayer-session-open to symlink set (repairs bin targets after renames)
- Install
No-op idempotent re-link for pre-existing targets
- Desktop icon
Transparent PNG background (only bubble opaque)
- Install
Mark ~/Desktop shortcut as trusted (no more Unrusted application launcher prompt)
- Install
Write ~/Desktop/Speech Layer.desktop with favicon icon (no more broken pi-surf-session-open)
Favicon assets vendored under assets/favicon/ for desktop + web parity
Wake word renamed to hey_speechlayer.onnx (was hey_marvin_v0.1)
- Wake UI
Friendly labels in notifications (no raw model names or scores)
- Bashrc
Personal speechlayer=speechlayer alias
- Docs
Os-adapters leftover identifier
- Docs
Rename leftover speechlayer identifiers in live docs
Rebrand speechlayer -> speechlayer: tree move, identifiers, paths
Rename pi-surf family to speechlayer/surfagent; drop surfagent force-loading
August 28, 2026
1 commit- STT
Wharton now respells to speechlayer in all STT entry points (wharton → speechlayer)
August 26, 2026
2 commits- Convention
The service-pane registry, spawn wrapper, and scaffold are live - code owns routing and never-do gates, prose owns domain behavior - and mailbox is migrated as the first citizen
- Fix
Voice say-that-again now falls back to the pane text store when the audio ring is empty
- Fix
The say queue daemon no longer lets a leaked SAY_TAG from its launching shell suppress all replay capture
August 25, 2026
1 commit- Router
Voice routing now asks nemotron instead of ling, and a leftover kimi pin in the environment was brought in line with it
August 24, 2026
9 commits- Rename
The hey-speechlayer voice window now opens as speechlayer instead of pi-surf, and everything that looks for the window by name was updated to match
- Fix
A pasted clipboard image path can no longer end up in the window title
Revert "- [x] Rename: The hey-speechlayer voice window now opens as speechlayer instead of pi-surf, and everything that looks for the window by name was updated to match"
- Rename
The hey-speechlayer voice window now opens as speechlayer instead of pi-surf, and everything that looks for the window by name was updated to match
- Fix
A pasted clipboard image path can no longer end up in the window title
- Terminology
The voice status and restart readouts now say speech layer instead of voice infrastructure
- Fix
Voice barge-in no longer loops a replayed sentence, the replay plays through unless you stop it
- Fix
Replay now sets a marker while a re-spoken clip is on the speaker so the barge-in detector leaves it alone
- Fix
Voice commands like say that again and say off no longer get typed into a pane as chat text, they run the speech control and answer aloud
- Fix
Replayed speech no longer interrupts itself in a loop when you talk over it
- Fix
The spoken repeat command now fires even when a source tag is attached
- Fix
Saying 'say that again' with a trailing origin tag (the '[voice]' the inject path adds, or the phone '[xmpp]' and '[email]' tags) left a stray trailing word after the brackets were stripped, which broke the whole-utterance match, so the repeat never happened and the words were typed as prose
- Fix
The same fragility hit every whole-utterance voice command (new/delete/compact session, shift-tab, thinking level, clear)
- Fix
The transform now strips a trailing voice, email, or xmpp tag word before matching commands
- Fix
Real command words are left alone, so 'close pane', 'cycle thinking', and 'new voice' still work
- Verified
'say that again [voice]' now triggers the repeat, and 'please say that again for me [voice]' still passes through as prose
- Voice
Barging in during a spoken agent summary now stops the whole readout, not just the playing sentence
- Voice
The energy and wake barge-in was wired to say --skip, which cut only the playing sentence and left the rest of the summary queued
- Voice
It now uses say --skip-group, which also drops the still-queued sentences that share the playing summary's group
- Voice
Other panes' queued speech is untouched, and an ungrouped utterance still just skips the current sentence
- Voice
Hard shut-up (say --stop) is unchanged
August 23, 2026
3 commits- Voice
The rewrite leg moves to inclusionai/ling-3.0-flash, the same model as the pane router, so both cloud paths share one model
- Voice
The reasoning-off gate in _post_chat now covers ling too; it was nemotron-only
- Voice
With reasoning effort none, ling matches nemotron on rewrite quality; without the gate, ling returns NONE
- Voice
Reasoning effort stays none
- Voice
The revert path is SL_REWRITE_MODEL=nvidia/nemotron-3-nano-30b-a3b
- Voice
The router cloud leg swaps nemotron for inclusionai/ling-3.0-flash
- Voice
Reasoning effort none and max_tokens 8 are mandatory, since thinking-on returns empty replies
- Voice
The needle POST shape (query/panes) was already correct and needed no fix
- Voice
The rewrite-model comment in wvd-herdr-control now notes that the router diverged
- Voice
The revert path is SL_ROUTER_MODEL=nvidia/nemotron-3-nano-30b-a3b
- Fix
Stale .bak copies next to the live dictate and herdr scripts are removed
- Fix
The whisper-server model is now overridable via WHISPER_MODEL (default ggml-base.en.bin) instead of a hardcoded path
- Docs
The WHDISPER_MODEL typo in the ops manual is fixed
August 20, 2026
1 commitKeep HTML email links so the LLM sees the actual URLs.
August 19, 2026
3 commits- Voice routing
Local first, one cloud model, no more wrong-pane injections.
Reminders no longer talk over Speech Layer: one speech queue, and the ding waits its turn.
Stop cutting mid-sentence on "tell my browser" and trailing please.
August 18, 2026
4 commitsWhisper-voice-daemon: recheck recent audio before silence wall-timeout cuts (fix mid-sentence cut-outs under CPU load); load canonical cancel phrases from speechlayer_cancel_phrases.py
- Voice
When the phone and the headset both hear the same sentence, only one message reaches a chat pane
- Voice
Near-duplicate repeats within 90 seconds are dropped
- Voice
Short replies like yes or Resume always still go through
- Voice
Needle 2, a tiny on-device command model, tidies misheard voice commands (like 'even those out' becoming 'balance panes') with no internet call
- Voice
The wake-word mic now follows whichever microphone is selected in sound settings, including headset plug and unplug, instead of staying stuck on the old one
August 13, 2026
4 commits- Say
If you start talking while a reply is playing, it pauses and finishes after you stop
- Say
Replies never start over an open mic, and stop or skip still cut through right away
- Docs
The public changelog page now refreshes itself on every push, so it can no longer fall behind the real history
- Say
Every queued play re-checks the current speaker so headset and laptop no longer swap mid-burst
- Say
The play log now notes which speaker was used, so a future mix-up is one search away
- Phone
Raise wake-record hard cap from 40s to 60s (SL_RECORD_S)
August 12, 2026
3 commitsPi compaction-freeze guard: watchdog daemon + install wiring
- Voice
Saying 'barge in' before a message now interrupts a busy pane (Esc) and submits fresh instead of queueing as a steer
- Voice
It works after a callsign, as in 'tell features barge in ...', and after a workspace route
- Voice
It never triggers on a mid-sentence 'barged in'
Say again now speaks on panes whose replies were never read out loud
August 6, 2026
2 commitsAdd 'speechlayer calibrate stop' - cancel an in-flight barge battery (SIGINT, SIGTERM after 3s); watcher untouched
- Restart
Fix 'running but no state file' race + set -e mid-restart abort
August 5, 2026
1 commit- TTS
Stop mid-sentence cutoffs (root-cause + hardening)
July 30, 2026
7 commits- Say
Spoken replies are kept as short audio clips, so say --replay and /say again play back exactly what you heard instead of generating it again
- Say
Keeping those clips is off by default and only starts once you turn it on, it never keeps more than five, and each pane only replays its own messages
- Say
Asking for a replay cuts whatever is playing and clears your own backlog, while other panes keep their queued messages and play right after
- Say
The talking queue, the always-ready pocket voice, and the skip-what-is-playing hotkey script now ship with the repo so a fresh install gets the whole setup
- Pi
/say again replays your pane's last answers, and each workspace can have its own voice or stay muted
- Fix
Wifi watchdog only nudges saved networks, never when wifi is already up, so phantom password popups stop
- Fix
Voice commands now catch plural mis-hearings of a client name and fix them
- Docs
Personal API keys (BYOK) now covered in README, INSTALL, speechlayer and AGENTS
- Docs
Listen mode explains always-listen at boot and how talking over the agent becomes the next turn
- Docs
Portability table lists the personal-keys file alongside the other per-machine settings
- Docs
Add the Needle page that AGENTS.md already pointed to
- Barge
Sensitive mode now pulls talk-over loopback knobs from one list
- Barge
Residual floor can go up to 80k so big calibrations are not clamped away
- Say pocket
Workspace voice map plus per-voice gain file after pane resolve
- Say pocket
File export bakes gain so soft voices stay leveled off-play
- Say server
Pocket engine through the warm daemon for phone TTS
- Phone bridge
Xmpp inject uses herdr agent prompt (atomic submit) with pane send-text plus Enter as fallback
- Phone bridge
Multi-step marker sequences paste via pane send-text since agent send is gone
- Email bridge
Sticky default heals from the legacy default to herdr and auto-spins the my workspace home lane when it is missing
- Email bridge
Ensure_agent_lane creates workspace, splits pane, and starts the pi agent for a callsign
- Email bridge
Wait_idle requires a busy sighting or sustained idle so a mid-retry spinner never becomes the emailed reply
- Email bridge
Screen scrape drops spinner glyphs, retry countdowns, error toasts, and the pi status bar
- Email bridge
Reply comes from the session log and keeps waiting while the agent is still busy
- Outbox
Xmpp-outbox-drain pulls per-site commit outboxes over ssh and fans out to xmpp, ntfy, or webpush recipients
- Outbox
Drain restores curly quotes mangled into U+XXXX placeholders, raw JSON escapes, and common HTML entities
- Bridge
Xmpp-pi-bridge-ensure idempotent supervisor refreshes the D-Bus address and heals the pidfile
- Bridge
Xmpp-send-file sends attachments encrypted with XEP-0454 so the phone shows them inline
- BYOK
Per-directory project keys in keys.json with longest-prefix path match
- BYOK
Project key beats user default, then env, then bashrc per request
- BYOK
Speech Layer keys projects, emit, import-pi-sh, and --path/--cwd flags
- UI
Settings page lists project overrides and can save or remove them
- Integrations
Herder and listen treat project keys as personal on 401
- Integrations
Openrouter resolve reports project source via resolve_key_info
- Fix
Brand import path in listen-intent so product name lookup does not crash
- Fix
Peel doubled tell verb after respell so callsign still parses
- Docs
README, AGENTS, INSTALL, speechlayer plus keys.json.example cover project keys
- Herdr
Pane rename comment matches agent prompt (send is gone)
- Herdr
Sticky only re-pins on a real focus edge so background tell keeps its target
- Herdr
Prefer unique agent name over duplicate pane label for sticky inject
- Skills
Herdr docs use agent prompt, pane-first start, and barge-in stop order
- Rules
Steering keeps open work; surfagent claim leases; agent prompt for phone inject
July 29, 2026
2 commits- Brand
Install renders desktop Names and paths from product name and CLI name
- Brand
Dual CLI symlink when the public name differs, keep speechlayer forever
- Brand
Launchd Label prefix is data, templates stay com.speechlayer on disk
- Brand
Mix sink name is MIX_SINK with speechlayer_mix default across audio helpers
- Brand
Web templates plus render-brand write Speech Layer by default, speechlayer overlay ready
- Brand
One runtime brand layer so Speech Layer and public speechlayer share one tree
- Brand
Defaults stay Speech Layer (wake, config dir, URLs, spoken prompts) with fail-safe fallback
- Brand
High-traffic surfaces read product name, wake phrase, and app name from the brand file/env
- Brand
Speech Layer brand dumps the resolved values; inventory lists what still needs a wake-model choice
July 27, 2026
2 commits- BYOK
Per-user LLM provider keys in ~/.config/speechlayer/keys.json (600), user key beats server env key per request
- BYOK
Core/speechlayer_keys.py shared store + masked display + cheap key validation + auth-failure surfacing (marker + notify, never silent server billing)
- UI
Speech Layer keys status|set|clear|test|ui plus localhost :7782 settings web page (provider selector, password input, save/test/clear)
- Integrations
Wvd-herdr-control and wvd-listen-intent resolve OpenRouter keys via the BYOK store with strangler-safe env fallback
- Docs
README BYOK section; install.sh warns with the speechlayer keys alternative
- Tell
Resolve panes on non-active tabs of a workspace
July 24, 2026
2 commits- Fix
Herdr 0.7.5 dropped agent send; inject path now uses agent prompt
- Docs
AGENTS.md and wake-words herder-route notes match the new CLI
- Privacy
Stop treating bare 10/11-digit runs as phones
- Privacy
Drop postal code masking entirely
July 23, 2026
1 commit- Fix
Speech Layer restart now revives a dead email-pi-bridge via email-pi-bridge-ensure (best-effort, cron remains primary supervisor)
July 22, 2026
1 commit- Privacy
Footer and logs count distinct identities, not hits
- Privacy
Shield and unshield phone XMPP sticky injects and replies
- Privacy
Shared store with email bridge and kill-switch XMPP_PRIVACY
July 20, 2026
3 commits- Privacy
Count shield replacements per message and log them
- Privacy
Tell agents that fake tokens are stand-ins to quote as-is
- Privacy
Footer replies with what Speech Layer shielded during LLM calls
- Fix
Herd residual body verbs ask which pane, never spawn to or two
Fix client-site-two bug: body_starter includes to/too/two; herd-default routing for workspace-matched tells; block function-word callsigns.
July 19, 2026
6 commits- Say
Wake poke, CLI fast path, dead-air slimming, hold presynth
- Tts
Install committed say/say-queue-daemon (wake.fifo 8ms claim, same-group ordering, recording-hold presynth, 40ms enqueue)
- Barge
Hands-free auto-calibration battery + daemon self-barge detector
- Tts
Spoken-prep leading-zero trim (PI-000018 -> PI-18); README: wake.fifo/same-group/presynth queue docs
- Proper-nouns
Glue 'tilda/tilde slash foo' to ~/foo before flat pairs
- Privacy
Mask bare and keyword-anchored phone numbers with NANP validation
- Privacy
Mask payment cards, tax ids, and Canadian postal codes with stable fakes
July 18, 2026
3 commits- Privacy
Mask emails and phones to stable short fakes before prompts reach the LLM and restore them on replies
- Privacy
Seed names from mail headers and body anchors with separate first and last fakes
- Email bridge
Shield injected prompts and unshield replies with a shared locked-down lookup file
- Voice
Ask which pane when duplicate labels span workspaces
- Voice
Silent deciders sticky then focused herd then unique agent name
- Phone
Share the which-pane question and answer across voice and text
- Voice
Mute or unmute the default sink with switch volume and goodnight phrases
- Voice
Set Pocket voice across a whole workspace or a named pane
- TTS
Queue by default, pane-scoped replay ring, and soft barge gating
- TTS
Reconcile Pocket daemon pile-ups and durable HF cache on restart
- Phone
Keep XMPP channel sticky separate from voice sticky and focus
- Callsigns
Allow duplicate pane labels and keep agent names unique
- Counters
Stop bare thinking words cutting mid-sentence dictation
July 17, 2026
12 commits- Transform
Drop dead svn commit historical map note
- TTS
Speak xmpp as x m p p
- TTS
Currency, paths, URLs, emails, dates, emoji in speak-prep
- STT
Log respell diffs for training when raw ≠ fixed
- TTS
Absorb trailing dots on a.m./p.m. clock forms
- TTS
Fix a.m./p.m. trailing period after clock expand
- TTS
Speak clock times without colon (14:30, 3pm)
- TTS
Space month abbr expansions so Oct.17 reads clean
- TTS
Month abbreviations speak as full names
- STT
Client-site-class fusions respelled as tell client-site
- TTS speak seeds
Degrees, ops, %, #N, units, e.g., cwd
- TTS
Speak-prep dict (~ → roughly; digit.digit → point)
- Fix
Successful tell no longer dual-dispatches into the focused pane
- Herdr control
Mark tell committed before TTS; fire-and-forget say
- Dictate
Wall after commit counts handled; refuse tell-shaped fallthrough with voice retry
Free-form pi-surf prefers sticky pin over focused eyes
Evolve proper-nouns into a respell dictionary (pie/pi, user JSON)
July 16, 2026
1 commit- Fix
Delete pi session runs /delete and confirms Yes
Agent inject keeps multi-Enter sleep order for confirms
July 15, 2026
32 commitsEyes/focus on also raises the herdr pi-surf window
- Fix
Focus client-site cleaner lands on the cleaner pane
Tell body re-runs bare control grammar on target pane
Tell body runs cwd/nav control on target pane not chat paste
STT togel focus for tell-move-focus toggle
Home sticky channel is herdr, not the legacy default
Voice toggle for tells moving eyes focus
Fix show me bare eyes-on grammar
Voice eyes on/off for bare workspace and pane focus
Fold client-site's / client-site STT into client-site for tell routing
Sticky hold checked every tick so focus cannot keep the channel
Sticky hold reasserts herdr against focus steal
Handoff wait-scrape herdr reply to phone; re-pin sticky + hold
Focus sync skips sticky during hold so channel stays herdr
- Spawn handoff
SMS herdr reply after wait; re-pin sticky
Fix bridge crash mangle on scrap path regex
STICKY machine line; instruct create to re-stick new pane
- Spawn handoff
Short ensure herdr pane when missing
Confirm keyword yes/no never agent-sends the herdr pane
- Spawn free-form
Default handoff to herdr pane via agent send
Keep rules/LLM rewrite path intact behind spawn-offer-clarify flip
- Spawn clarify
Quoted my workspace and label-before-noun patterns
Live herd name in free text re-routes offer with held body
- Phone scrape
Never TUI dump mid-working; reject chrome junk
- Tell
Keep live herd det words like my for inventory peel
- Spawn offer
Non-yes/no → rules then Needle/LLM rewrite route only
Consent stays keywords; wrong rewrite vectors never invent yes
- Phone bridge
Live-offer free-form asks speechlayer clarify path
- Tell MSG lead
Stop he eating hello
- Phone
Forward speechlayer spawn-offer text to XMPP not echo inbound
- Tell peel
Stop to/that hard split; long-comma English stays peel
- Xmpp-send
Heal session D-Bus so Gajim remote can ack
- Herdr
Silent focus cutover repins sticky without phone spam
- Docs
Sticky is channel not eyes address wins then manual focus
- Docs
Herdr skill notes label equals agent callsign dual-write
- Herdr
Pane rename always dual-writes agent callsign (shim plus control)
- Herdr
Background callsign sync heals TUI renames upgrade-proof
- Voice
Tell shell pane to launch pi types pi plus enter not prose
- Voice
Move working directory force-relocates pi session and resumes
- Voice
Keep change working directory as exit-pi shell-cd path
- Docs
Folder nav resolves chat basenames and change-cwd phrases
- Voice
Match change working directory / cwd / folder to name
- Voice
Resolve short basenames under chat before zoxide
- Voice
Never agent-send spawn yes/no residual or I don't know garbage
- Voice
Wait for TTS and skip free-wake preroll on spawn oneshot
- Voice
Peel hey speechlayer wake so spawn yes/no is not tell-to-speechlayer
- Voice
Arm one-shot free-wake after spawn offer, cut on yes/no
- XMPP
Accept no thanks and wake-style yes/no on spawn offers
- XMPP
Typed Note-to-Self runs the same Speech Layer pipeline as voice notes
- Control
Peel my/the and trailing pane nouns on tell routes
- Say
Caption side-channel for current, last, queue, status.json
- Say
Queue daemon updates captions on play, skip, done, and cancel
- Control
Tell client-site pane launch pi route works despite STT mangling
- Control
Tall/tel aliases of tell and cube-old folds into client-site
- Control
Stop hyphen split and cwd-basename false pane on tell peel
- Control
Hey and yo aliases for tell with dual-use hey (filler vs route)
- Control
Sticky fallthrough on soft free-form, shared with phone target file
- Control
Unknown tell target offers spoken yes/no spawn (shared XMPP offer state)
- Control
Tell workspace pane message routes via live inventory longest match
- Control
Herdr agent inject (XMPP-style) for tell, herder route, and --inject CLI
- Control
Everyday make/create/new pane wording maps to ensure pane
- Dictate
Wvd_agent_inject helper; pi-surf-term prefers agent send over xdotool
July 13, 2026
7 commits- Control
Soft "speechlayer …" free-form gate with salvage before network and hard walls so blue never hangs
- Control
Ensure workspace and ensure pane create-if-missing then focus, including natural hybrid phrasing
- Control
Bash wvd_herdr_control wall plus {{SHIFTTAB}} marker wins in dictate scripts
- CLI/docs
Needle and herder-route ops, tts barge conf, phone mic and listen-path polish
- TTS
Hold say playback while Speech Layer is recording so panes don't talk over the mic
- TTS
Soft interrupt skips only the current utterance and keeps the rest of the queue
- TTS
Wake and energy barge use skip; shut up still drains the whole queue
Track host say queue tools and say-summary extension with Speech Layer
- Bench
Void guest shutdown check with default-device arecord proof; image retained
- Portability
Void thin-guest L2 claim and burn-in scorecard (runit, on-target whisper, PA mix)
- Install
Rewrite DAEMON_HOME pyenv templates and ship alsa-plugins-pulseaudio on void
- Runit
Dual-ship service trees with WVD default Pulse device fallback for Void asound
- Install
Force-distro/init/DE overrides and optional scrcpy on void and suse
- Install
Harden runit enable and systemd unit write for thin containers
- Bench
Family dry-run matrix, container smokes, Level-3 residual scrub
- Docs
Linux-family-matrix plus void and opensuse package smoke reports
- Portability
Cross-host macos svc_status port heuristics and soft LAN path
- Portability
Add macos-first-hour checklist with Darwin-safe probes
- Portability
Gate first-hour and forced-macos status in adapter selfcheck
- Docs
Point macOS install and resumption at first-hour playbook
- Install
Multi-family (debian/Mint) path, models seed step, on-target whisper wrappers
- Install
KDE/Cinnamon/dconf-cli hotkeys and never transplant cross-distro whisper bins
- Assets
Ship wakeword-models seed including hey_speechlayer verifier
- Docs/Bench
Mint walkthrough, portability claim calibrated, debian-family QEMU burn-in
July 12, 2026
2 commits- Portability
Add install-macos first-boot helper and optional indicator launchd unit
- Portability
Ship skhd and Hammerspoon hotkey examples under system/macos
- Portability
Prefer TMPDIR for SL_RUNTIME_DIR on Darwin in env.sh
- Portability
Make fetch-deps cmake jobs work without Linux nproc
- Docs
Point README and portability at the macOS install path
- Portability
Route dictate RECORD_DEVICE through audio_fallback_device for CoreAudio default
- Portability
Ship rumps menu-bar indicator skeleton and wire Darwin CLI check or fix
- Portability
Add dictate and indicator gates to adapter selfcheck
- Docs
Update macOS install resumption and progress for residual scrub
July 11, 2026
4 commits- Portability
A5 pipewire PASS on Fedora QEMU with stream-measure ratio 0.998
- Install
Pull alsa-plugins-pulseaudio so Fedora arecord pulse devices work
- Fix
Skip indicator check and restart when tray helper is not installed
- Fix
Session-heal polls for speechlayer mix and re-bounces daemon if arecord missing
- Fix
Keep speechlayer mix ensure after pulse recover when headless has no real mic
- Docs
Guest-validate PULSE_SERVER unset recover on Ubuntu QEMU restart
- Docs
Record Ubuntu QEMU systemd burn-in scorecard and partial gates
- Portability
Unset PULSE_SERVER before pulseaudio start after kill so restart can recover
July 10, 2026
15 commits- Fix
Lower TTS energy cancel so hot speaker mon no longer zeros talk-over residual
- Fix
Fire residual barge on soft speaker monitor under high mic instead of hard skip
- Fix
Trial barge knobs need two chunks residual 2500 and ratio thr 3.5
- Dictate
Require switch model to alias so bare model names stay prose
- Dictate
Preflight complete herdr commands in listen mode before the LLM
- Herdr
Fuzzy workspace match and richer voice targets for STT near-misses
- STT
Accept cubald-style client-site mishears in proper-noun rewrite
- Training
Add standalone kapish terminator model trainer
- Docs
Freeze Artix Level-3 campaign work at host-gated stop-line
- Docs
List single-host burn-in tickets and regression bar for adapters
- Portability
Make status fix and session-heal accept pipewire-pulse without a pulseaudio process
- Portability
Refuse ha commands on Darwin and route speechlayer test capture through adapters
- Portability
Document A4 user units and expand Fedora dnf package list
- Portability
Extend adapter-selfcheck for CLI residual gates
- Portability
Add Linux adapter selfcheck covering macos force and launchd templates
- Docs
Point resumption install and progress at the selfcheck regression bar
- Portability
Add launchd installer so macOS templates are a real writer not just docs sed
- Portability
Scaffold Windows inject HTTP shim and WSL2 platform overrides after W0
- Docs
Point macos install and progress at launchd installer and Option C door
- Portability
Add stream measure script with ratio and cadence gates for A5 and W0
- Docs
Record Artix Pulse golden numbers for pipewire and WSLg comparison
- Docs
Spell out WSLg W0 operator procedure without claiming a pass yet
- Portability
Route macos beep pid check and speaker mon through adapters
- Portability
Teach speechlayer CLI Darwin-safe status restart and session-heal paths
- Portability
Skip the indicator cleanly when rumps is not installed
- Docs
Add macOS resumption door for real macOS hardware burn-in next
- Docs
Mark Option A A2 and A3 complete and fill INSTALL systemd install pointers
- Docs
Document OpenRC versus systemd sudoers as mutually exclusive
- Docs
Expand systemd Level 2 slices A1 to A6 and link them from INSTALL
- Portability
Route speechlayer managed service control through SL_SVC without OpenRC-only copy
- Portability
Write svc-backend on systemd install and sketch Fedora packages
- Portability
Draft user unit and systemctl sudoers examples off by default
- Docs
Spell out systemd Level 2 burn-in path unit gaps and first boot checklist
- Portability
Scaffold macOS adapters for capture inject notify svc and paths
- Portability
Add raw PCM capture helper that keeps the recording loop shape
- Portability
Ship untested launchd templates and macOS install TCC notes
- Portability
Opt-in systemd verbs via SL_SVC without auto-detecting init
- Docs
Record Option B decision readiness table and half-contract review
- Docs
Campaign brief for OS backends orchestrator after Phase 4 product close
- Voice
Stop soft mon from free-firing ratio barge mid long readouts without killing real talk-over
- Voice
Fix tts-barge set clamps that capped spk_k below real bleed and ratio thr at three
- Status
Count only real python daemon processes so supervise and grep noise stop false multi-daemon warnings
- Voice
Free-wake idle gap so amber can show between turns without killing barge or wake
- Voice
Seed free-wake recordings from the always-on PCM pre-roll so first words are not clipped
- Docs
Mark Phase 4 executed, platform readiness table, listen free-wake idle and pre-roll notes
July 9, 2026
15 commits- Voice
Stop free-wake from rearming while TTS still plays without killing barge or wake
- Voice
Blank free-wake WAV during spoken acks so switching is not reheard as a new command
- Voice
Drop command-shaped listen acks and herdr switch TTS plus short-window herdr dedupe
- Voice
Ship always-on listen mode with CLI, rearm, intent LLM and plan executor
- Voice
Show an amber listening state on the corner indicator while mode is armed
- STT
Fold known client-site mishears on every dictate herdr and phone path before routing
- Docs
Document listen-mode harness files enter exit phrases and half-contract rules
- Docs
Mark the OS-adapter split finished end-to-end so the plan matches the tree
- Portability
Put every desktop notification under the single app name speechlayer so nothing collides with random voice daemons
- Voice
Lock TTS energy-barge knobs so loud talk-over and hey speechlayer can interrupt without clipping clean playback
- Voice
Age barge grace from first audio, not process start, so synthesize lag cannot burn the window
- Voice
Keep a softer wake threshold even when energy barge is off so drowned speech still reaches hey speechlayer
- Voice
Drop bare cancel as a cancel phrase so random prose no longer kills a recording
- Voice
Prefer okay-go and kapish spelling variants for the mid-recording instant cut
- Portability
Build the wake-word mic capture command through the OS adapter so the recording loop stays the same on every platform
- Portability
Record and play audio through the OS adapter so capture tools can change without rewriting the scripts
- Portability
Restart managed services through the OS adapter so Linux is not hard-wired into the CLI
- Voice
Reclaim dead recording locks so a crashed capture cannot block the next wake forever
- Voice
Let loud speech interrupt TTS playback, with knobs you can change without restarting
- Voice
Treat Whisper's clipped 'her D' as 'herd d' so herd switching still works
- Voice
Harden the keystroke-marker walker so unknown markers are dropped, not typed forever
- Voice
Map full 'new session' phrases to /new after slash commands settle
- Portability
Route every keystroke and window-focus call through the OS adapter so typing works the same on every platform
- Portability
Preserve per-site xdotool flags including flag-less Escape and --delay 8 type
- Voice
Revert bare 'go to <name>'; folder-noun required again (cd stays short form)
- Voice
Accept bare 'go to <name>' (≤3 tokens) when not a herd/pane command
- Voice
Harden folder resolve for whisper typos (client-site ≈ client-site) and TLD-ish tokens
- Voice
Drop legacy project-as-herd entirely - project is filesystem-only now
- Docs
Herds-and-folders.md voice cheat sheet (switch herd / folder nav / move session / resume pi)
July 8, 2026
12 commits- Voice
Rebrand herdr workspaces as 'herd' (heard/workspace aliases), freeing 'project' for folder nav
- Voice
Plain folder nav inside pi now exits pi then cds; only 'move session to X' uses pi /cd relocate
- Voice
Add 'resume pi' -> pi -c
- Voice
Add folder-navigation intent (go to folder / cd / go up|home|back) to wvd-herdr-control, zoxide-resolved, shell cd vs pi /cd
- Portability
Send desktop notifications through the OS adapter so non-Linux backends can plug in
- Docs
Note that notification app-names should be unified after the port, since the current ones are generic enough to clash with other apps
- Docs
Record how the Linux dispatch layer was actually built, so the design matches the code
- Portability
Add the per-OS dispatch layer with Linux implementations built in, ready for scripts to adopt
- Voice
Add new-pane and pause keystroke macros so spoken herdr commands can open panes and let slash commands settle before submitting
- Portability
Route all runtime state files through a single configurable directory instead of hardcoding /tmp
- Docs
Inventory every OS-specific call site in the voice stack, grouped by adapter
- Docs
Design the OS-adapter split (audio, keystrokes, notifications, services) with a step-by-step migration plan
- Docs
Link the new portability design into the existing plan so the next phase is ready to start
- Docs
Note that MATE hotkeys run the dconf action field not command, so a stale action still errors even when command looks right
- Docs
Add scroll-in chat examples and modernize speechlayer landing page capabilities and privacy messaging
- Docs
Add charming non-technical speechlayer landing page
July 7, 2026
11 commits- Docs
Restructure speechlayer landing page; feature herdr voice control and TTS reply playback
- Docs
Add plain-text ASCII-art landing page explaining speechlayer
- Fix
Systemd StartLimitIntervalSec/Burst moved to [Unit] section (were silently ignored in [Service])
- Fix
Debian/Ubuntu pkgs list drops bogus libnotify (aborted apt txn), adds python3-venv/pip + build-essential/cmake/git for whisper.cpp build
- Fix
Venv installs use --no-deps so pip-freeze closures don't pull 3GB of nvidia CUDA wheels via misaki
- Fix
Recreate broken venv lacking pip (failed earlier run left python3 but no pip)
- Fix
Wake-word models missing is a warning not a verify failure (user-trained artifacts, not in repo)
- Install
Validated full install.sh systemd burn-in on Ubuntu 24.04 VM (all 4 units active, whisper.cpp built, transcription working)
- Phase 3c
Level-2/3 scrub - de-hardcode the login user name, dual-ship systemd units
- Portability.md
Phase 3b fully live - init.d copied, compat shims removed, full smoke matrix green
- Phase 3b
Root rename ~/scripts+~/.speechlayer -> ~/speechlayer with core/pi/net/training/media/lib subdirs
- Herdr grammar
Accept 'panel' as spoken alias for pane
Phase 3a portability: SL_HOME parameterization
Phase 2 portability: install.sh + fetch-deps.sh
Phase 1 portability: system snapshots, requirements, models, INSTALL.md
Initial messy commit: ~/scripts + ~/.speechlayer as-is, pre-restructure