agentleFS
LegionForgeLegionForge/convobox/llms.txt

convobox

llms.txt2 starsChanged 3 days agoMITView on GitHub

A local, backend-agnostic voice frontend for CLI coding agents (opencode, Claude Code, Codex): microphone → Silero VAD → faster-whisper STT → orchestrator → agent backend → Kokoro TTS. MIT licensed. github.com/LegionForge/convobox — LegionForge (https://legionforge.org) Distilled, evidence-anchored findings from building and live-testing a voice interface for coding agents. Written for human practitioners and for LLMs ingesting this repo as reference. Each note carries full provenance (human + AI authors, models, providers, timestamps). CC BY 4.0 intent. - Field notes index: the…

Files
llms.txt
# ConvoBox

> A local, backend-agnostic voice frontend for CLI coding agents (opencode,
> Claude Code, Codex): microphone → Silero VAD → faster-whisper STT →
> orchestrator → agent backend → Kokoro TTS. MIT licensed.
> github.com/LegionForge/convobox — LegionForge (https://legionforge.org)

## Field notes

Distilled, evidence-anchored findings from building and live-testing a
voice interface for coding agents. Written for human practitioners and for
LLMs ingesting this repo as reference. Each note carries full provenance
(human + AI authors, models, providers, timestamps). CC BY 4.0 intent.

- [Field notes index](docs/field-notes/README.md): the collection, its
  discipline, and its status vocabulary.
- [Interactive prompts deadlock voice-driven coding agents](docs/field-notes/2026-07-18-interactive-prompt-deadlock.md): a blocking multiple-choice tool froze a voice session 5+ min while user speech queued invisibly; why conversational repair can't fix it.
- [Your abort phrase is only as reliable as your VAD threshold](docs/field-notes/2026-07-18-safeword-vad-coupling.md): a safeword inherits the reliability of every input gate upstream of where it's checked; tuning VAD silently tuned a safety control.
- [A speech-correction glossary must map FROM tokens you would never say](docs/field-notes/2026-07-19-corrections-glossary-domain-improbable-sources.md): correcting a real word (bargain→barge-in) silently corrupts the user genuinely meaning it; safe sources are domain-improbable STT outputs.
- [A plausible AEC theory, verified two ways, was still wrong](docs/field-notes/2026-07-20-aec-delay-hint-was-a-red-herring.md): a delay-hint theory survived a synthetic experiment AND a real-source read, but real on-hardware calibration data already in the repo refuted it — check for existing empirical evidence before building fresh verification.
- [Repeated self-barge-in was an over-narrow backchannel filter, not uncancelled AEC echo](docs/field-notes/2026-07-20-self-barge-in-was-backchannel-not-echo.md): the backchannel-filter fix is still correct, but the "not echo" causal claim was later reopened (see the 2026-07-26 correction below).
- [Codex silently rejected every voice-approved write because the decision value was invalid, not declined on purpose](docs/field-notes/2026-07-21-codex-approval-decision-schema-bug.md): the approval response didn't match Codex's own generated JSON schema, so every "yes" was rejected as malformed rather than acted on.
- [A dedicated keyword-spotting engine (Sherpa-ONNX) could fix fixed-phrase STT reliability generally, not phrase-by-phrase](docs/field-notes/2026-07-21-sherpa-onnx-dedicated-keyword-spotting-candidate.md): hypothesis status, raised live by Codex during a voice session — not yet built or verified.
- [os.add_dll_directory alone did not fix a pip-installed CUDA DLL that a C extension delay-loads on Windows — prepending PATH did](docs/field-notes/2026-07-22-cublas-dll-loading-needs-path-not-just-add-dll-directory.md): the DLL directory was correctly registered and present on disk, yet loading still failed until the same paths were also prepended to `PATH`.
- [Claude Code's MCP tool permission is a separate gate from --permission-mode — permissive mode doesn't cover it without an explicit grant](docs/field-notes/2026-07-22-mcp-tool-calls-have-a-separate-permission-gate.md): only an exact per-server `permissions.allow` entry (not a wildcard, not `--allowedTools`) unlocks an MCP server's tools, and it grants the whole server at once.
- [ctranslate2's native-allocator leak also surfaces as a bare numpy MemoryError, not just RuntimeError — and that manifestation wasn't caught](docs/field-notes/2026-07-22-native-allocator-leak-also-surfaces-as-numpy-memoryerror.md): `numpy._core._exceptions._ArrayMemoryError` is a `MemoryError` subclass, not a `RuntimeError`, so the existing recovery path silently missed it and the whole process died.
- [A shared venv silently repoints between two clones' editable installs, breaking one of them without touching its code](docs/field-notes/2026-07-22-shared-venv-editable-install-cross-contamination.md): a Windows directory junction sharing one `.venv` across two checkouts let `import convobox` resolve to the wrong clone's source, with no code change in sight to explain the symptom.
- ["Explain"/"clarify"/"help" during a pending approval now gets a spoken answer, not silence](docs/field-notes/2026-07-23-approval-explain-clarify-help-outcome.md): the "discuss" outcome was anticipated and named in the approval detector's own docstring since it shipped, but never actually wired to a spoken reply until this fix.
- [A barge-in can fire against a response that never made a sound, because is_playing() means "thread started," not "audio is out"](docs/field-notes/2026-07-25-player-is-playing-races-ahead-of-first-audio.md): `AudioPlayer.is_playing()` goes true when the playback thread starts, which can race ahead of any audio actually reaching the speaker.
- [Reference-vs-mic timing coincidence looked like echo, briefly — a real cross-correlation said otherwise, and the actual mechanism was already fixed](docs/field-notes/2026-07-25-timing-coincidence-is-not-echo-correlation.md): the `aec_delay_ms` calibration finding held up, but the "not echo, this was operator backchannel" causal claim was itself reopened by the very next note.
- [The "not echo" conclusion in two prior field notes rests on a cross-correlation methodology with a real blind spot — reference.wav is time-compressed, not wall-clock continuous](docs/field-notes/2026-07-26-reference-capture-is-time-compressed-not-wall-clock.md): hypothesis, structurally confirmed by code reading (not yet re-verified against live audio) — the reference capture only advances on real played blocks, so any cross-correlation against wall-clock mic time is comparing misaligned timelines.
- [Under-cancelled AEC echo can be loud enough for STT to transcribe real words out of the assistant's own voice, which then get accepted and echoed back as if the operator said them](docs/field-notes/2026-07-26-under-cancelled-echo-is-sometimes-transcribable.md): resolves the prior two notes' open question — the echo really was echo, just quiet enough to slip past the AEC verdict while still being STT-transcribable.
- [Headphone choice does not meaningfully change the under-cancelled-echo leak rate in an acoustically reflective room — the room dominates, not the transducer](docs/field-notes/2026-07-27-headphone-choice-does-not-eliminate-under-cancelled-echo.md): bone-conduction and sealed over-ear headsets were compared live in the same room; neither eliminated the leak class the prior note identified.
- [General-purpose Claude Code web UIs are IDE-in-a-browser; ConvoBox's web UI is a voice-session companion](docs/field-notes/2026-07-28-other-claude-code-web-uis-dont-transfer-much.md): surveyed 5 open-source Claude Code web frontends — file tree/Git/terminal/multi-session features don't transfer to a voice-companion UI backed by a sandboxed agent; the one small portable idea (PWA install-ability) is flagged, not yet built.
- [OpenLive confirms ConvoBox's coding-agent-first niche and surfaces ACP as the direction for standardized backend support](docs/field-notes/2026-07-29-openlive-comparison-and-acp-direction.md): a competitor survey that both validated the positioning and named the Agent Client Protocol as the way out of one-adapter-per-CLI.
- [ACP scoping: only OpenCode exposes it as a first-party protocol today](docs/field-notes/2026-07-31-acp-scoping-only-opencode-native.md): Claude Code and Codex have only third-party bridges, so adopting ACP would not currently remove any of the three existing adapters.
- [An STT config-swap evening: too confounded to name a cause, but a real VRAM ceiling and a clean AEC-delay negative result survive](docs/field-notes/2026-08-03-stt-config-swap-session-self-barge-in-drift.md): backend, model size, and elapsed session time all moved together at every transition — a worked example of how not to run a tuning session, plus the two results that were still salvageable.
- [The same hotwords-active branch produced both the best and worst "Athena" resume runs of the day](docs/field-notes/2026-08-05-stt-hotwords-athena-resume-inconclusive.md): the `stt.hotwords` result was inconclusive in both directions, and mic hardware turned out to matter more than the branch under test.
- [The VAD segmenter can go silent for extended stretches even with max_utterance_s set](docs/field-notes/2026-08-05-vad-segmenter-silent-unbounded-lockup.md): mic capture keeps running and nothing is transcribed, with no log line at all — the first sighting of the freeze class that dominated the following two weeks.
- [A web-triggered resume unblocks the mic loop but never tells the TUI](docs/field-notes/2026-08-05-web-resume-desyncs-tui-display.md): two views of one session drifted out of sync, producing a "hung" session that wasn't — a state-ownership bug, not a hang.
- [A dropped-by-any-gate transcript showed in the TUI but was invisible in the web UI](docs/field-notes/2026-08-05-web-transcript-forwarding-parity.md): `forward_transcript()` fired too late in the pipeline, so anything a gate rejected never reached the browser at all.
- [A biased hotword can trap the STT decoder into a runaway repetition loop, and it reliably fires the safeword](docs/field-notes/2026-08-06-resume-word-hallucination-and-runaway-repetition.md): hotword biasing on short audio produced endless repetition that fell through into a genuine hard-stop — a tuning knob with a safety-path consequence.
- [The Settings TUI could not open a convobox.yaml it could not validate](docs/field-notes/2026-08-06-settings-tui-cannot-open-invalid-config.md): the one tool meant to repair a broken config refused to start when the config was broken.
- [codex's app-server reports file changes in a shape the artifact pane could use, but nobody has watched it happen live](docs/field-notes/2026-08-07-codex-artifact-pane-wiring.md): the wiring is identified and plausible; it is explicitly not claimed as verified.
- [opencode's file.edited event is trivial to parse but isn't on the session stream the adapter subscribes to](docs/field-notes/2026-08-07-opencode-artifact-pane-file-edited-is-a-global-event.md): it's a global event, not a session-scoped one — which is why opencode's artifact-pane wiring is blocked on a design question rather than parsing work.
- [faster-whisper/ctranslate2's reliability problems are still unfixed a month later](docs/field-notes/2026-08-07-stt-engine-continued-investment-research.md): onnx-asr/Parakeet TDT has no hotword/biasing support and is not viable for the safety path; the conclusion is to decouple the safeword mechanism from the transcriber rather than swap transcribers.
- [AEC3 spectral suppression and VAD-based self-trigger rejection diverge on a laptop-internal array](docs/field-notes/2026-08-09-aec-spectral-suppression-vs-vad-rejection-diverge-on-laptop-internal-array.md): optimizing the AEC metric does not optimize the outcome you actually care about — two measures of "did echo get handled" pointing at different settings.
- [Hard-stop reliably aborts ConvoBox's own state, but does not cancel an already-dispatched tool call](docs/field-notes/2026-08-09-hard-stop-does-not-cancel-an-in-flight-tool-call.md): true on all three backends — a safety-relevant limit of what "stop" can mean once a tool call is in flight.
- [Kokoro on macOS, plus a TTS/STT round-trip that reproduces a known issue](docs/field-notes/2026-08-10-macos-kokoro-and-tts-stt-roundtrip.md): Kokoro confirmed working live; the naive speaker-to-mic round-trip reproduces the known far-field hallucination pattern rather than a new accuracy bug.
- [First live-hardware pass on macOS](docs/field-notes/2026-08-10-macos-live-hardware-first-pass.md): real AEC calibration and real claude-code/codex round-trips, plus a real crash found and fixed in the process — but no live human speech through the mic yet.
- [First live mic-loop and safeword confirmation on macOS](docs/field-notes/2026-08-10-macos-live-mic-loop-and-safeword-first-confirmation.md): via synthetic audio injection rather than a human speaker — the note is explicit about which claim that does and doesn't support.
- ["Open in editor" pointed at the wrong file due to an unguarded stale fetch on a shared DOM node](docs/field-notes/2026-08-11-artifact-editor-uri-stale-fetch-race-live-reproduced-and-fixed.md): a classic async-race-on-shared-state bug, live-reproduced and fixed.
- [Full self-barge-in volume sweep plus room RT60 — complete raw data](docs/field-notes/2026-08-11-full-volume-sweep-raw-data-and-room-rt60.md): 119 real trials at N=7 per level from 100% down to 20%, and 50 repeat RT60 measurements, published as reusable raw data rather than just a conclusion.
- [First real human-speech demo on macOS](docs/field-notes/2026-08-11-macos-live-human-demo-safeword-bargein-and-self-echo-loop.md): safeword and barge-in both confirmed live with a real speaker, and a genuine self-triggered barge-in loop found and diagnosed in conversational mode during the same demo.
- [Permission-model validation across claude-code, codex, and opencode](docs/field-notes/2026-08-11-permission-model-validation-claude-codex-opencode.md): plan/approve/permissive validated live; opencode's built-in auth confirmed broken in `serve` mode across three independent causes, while a manually-declared custom provider works end to end including real tool-calling.
- [Combined self-barge-in mitigation, plus hardware notes](docs/field-notes/2026-08-11-self-barge-in-combined-mitigation-and-hardware-notes.md): a 400ms delay plus a 1200ms threshold nearly eliminates the problem; the likely root cause is speaker distortion at high volume, not AEC delay alone.
- [What actually reduces self-barge-in at the live-demo volume](docs/field-notes/2026-08-11-self-barge-in-mitigation-at-demo-volume.md): an AEC-delay sweep and a `barge_in_min_speech_ms` sensitivity run on real hardware, with the N=1-per-point limitation stated rather than hidden.
- [A safeword match skips checking the same transcript for a pause phrase](docs/field-notes/2026-08-12-safeword-and-pause-phrase-are-mutually-exclusive-within-one-utterance.md): both phrases present in one utterance, only one acted on — the two safety gates were unintentionally mutually exclusive.
- [A low-confidence hallucination bypassed the language-probability gate and landed near the approval phrase](docs/field-notes/2026-08-12-stt-hallucination-bypasses-the-language-probability-gate-near-miss-on-approval-phrase.md): the error ladder gates on language probability, not decode confidence, so a hallucination got two of three words into a configured approval phrase.
- [An exhaustive 10-cycle batch, clean of the Windows Enhancements confound, still shows a real ~30% stall rate](docs/field-notes/2026-08-12-vad-freeze-exhaustive-batch-after-fixing-windows-enhancements-confound.md): removing one confound did not make the freeze go away, and pause/resume remained unreliable.
- [A repeatable harness confirms short capture stalls, then catches a 12+ minute freeze that resisted every recovery path](docs/field-notes/2026-08-12-vad-freeze-harness-catches-short-stalls-and-a-12-minute-unrecoverable-one.md): strong evidence for two distinct bugs rather than one, from the first synthetic-speech harness built for this.
- [The VAD/mic-loop freeze still reproduces after PR #269 — three clean live repros, new diagnostic silent throughout](docs/field-notes/2026-08-12-vad-freeze-live-reproduced-three-times-pr269-did-not-fix-it.md): a dedicated-executor fix that did not fix it, and a diagnostic that never fired during the very condition it was built to catch.
- [force_kill() reliability across all three backends](docs/field-notes/2026-08-14-force-kill-reliability-across-all-three-backends.md): 90/90 on the two subprocess-owning backends across three tool-call shapes; opencode has no equivalent guarantee by architecture and measured an inconsistent 23/30.
- [A structurally distinct mic-freeze isolated from the backend via typed text — then an unnoticed ~41-minute compound freeze found only in forensic review](docs/field-notes/2026-08-14-mic-pipeline-silence-freeze-isolated-from-backend-via-typed-text-then-a-41-minute-compound-freeze.md): typed text removed the backend from the equation for the first time, and the log review afterwards found a freeze nobody had noticed while it happened.
- [Two more codex readline() freezes reproduced live, this time with real stall telemetry instead of silence](docs/field-notes/2026-08-14-vad-freeze-harness-live-catches-two-more-readline-stalls-with-real-telemetry.md): 65.5s and 236.7s, caught by a rapid-fire-hotwords-while-paused stress pattern.
- [claude-code re-confirmed clean at good volume](docs/field-notes/2026-08-15-claude-code-vad-freeze-re-confirmed-clean-at-good-volume.md): completes the volume-confound re-verification across all three backends — codex clean, claude-code clean, opencode a real bug found and fixed.
- [force_kill() does NOT reach real tool-call children on macOS for codex; claude-code stays reliable](docs/field-notes/2026-08-15-force-kill-does-not-reach-real-tool-call-children-on-macos.md): codex 0/10 and claude-code 10/10 — the exact opposite of each backend's own Windows result, and the finding that opened the macOS force-kill gap.
- [Two candidate fixes for codex's macOS force_kill() gap both fail](docs/field-notes/2026-08-15-force-kill-macos-fix-attempts-killpg-and-processid-both-fail.md): `os.killpg()` fails because the real child is its own process-group leader regardless of sandboxing, and the reported `processId` targets the wrong process; a real termination RPC exists but covers a different execution path.
- [The pgrep/ps fallback works — 15/15, after fixing a quoting mismatch](docs/field-notes/2026-08-15-force-kill-macos-pgrep-fallback-implemented-and-validated-15-of-15.md): codex's reported command text keeps its shell-quoting wrapper while the live process's argv has already consumed it, so a naive substring match silently matched nothing; note carries its own correction — the first validation's survivor check couldn't see orphaned grandchildren.
- [kill_phrase live-verified during a genuine freeze — and it was needed because the resume word failed every attempt](docs/field-notes/2026-08-15-kill-phrase-live-verified-during-a-genuine-freeze-resume-word-stt-unreliable.md): the emergency path worked through the real mic pipeline, in the exact circumstance it exists for.
- [The opencode freeze reproduces with zero audio — a pure orchestrator/adapter bug](docs/field-notes/2026-08-15-opencode-freeze-deterministic-audio-free-repro-orchestrator-only.md): a ~90-line async script against a real `opencode serve` hits the identical freeze 4-for-4, eliminating audio, VAD, STT, and mic hardware as necessary conditions.
- [The retry-cancel fix works — 7/7, always resolves on the first retry](docs/field-notes/2026-08-15-opencode-freeze-fix-validated-retry-cancel-turns-indefinite-hang-into-3s-bound.md): ~3.0s every time, against 15-90s indefinite hangs that never self-resolved before the change.
- [opencode has a real, live, reproducing event-loop freeze — not the volume confound](docs/field-notes/2026-08-15-opencode-freeze-genuine-event-loop-hang-not-a-volume-confound-live-repro.md): ConvoBox's own asyncio loop genuinely stalls (main thread parked in kevent, 0% CPU) while the OS mic callback keeps firing underneath it.
- [The minimal hard-stop/resubscribe repro did not reproduce the freeze](docs/field-notes/2026-08-15-opencode-freeze-minimal-repro-attempt-inconclusive-not-a-single-hard-stop.md): a negative result that narrows the hypothesis without disproving it — one clean hard-stop-then-turn is not sufficient on its own.
- [A second cancel() call reliably unsticks the freeze — fast](docs/field-notes/2026-08-15-opencode-freeze-repeated-cancel-mitigates-mechanism-and-workaround-candidate.md): recovery in under 6s, 2-for-2, suggesting the cancellation is being lost or coalesced rather than being fundamentally impossible.
- [The opencode freeze is confirmed real and reliably reproducible — and now looks like an overlapping-hard-stop race](docs/field-notes/2026-08-15-opencode-freeze-reproduced-again-narrows-to-overlapping-hard-stops-not-a-single-one.md): it took three closely-spaced hard stops, one with its TCP connect cancelled mid-flight — consistent with overlapping stops poisoning a shared connection pool.
- [Root cause pinpointed: `_consume_events()`'s `async for` never honors cancellation](docs/field-notes/2026-08-15-opencode-freeze-root-cause-pinpointed-cancel-does-not-unstick-aiter-sse.md): the stuck task's dumped stack is byte-identical before and after `cancel()` is called on it, established by live asyncio task introspection.
- [The opencode retry-cancel fix holds under an automated hard-stop storm on Windows](docs/field-notes/2026-08-15-opencode-retry-cancel-fix-holds-under-automated-hardstop-storm-on-windows.md): zero timeouts across 143 calls, though ~22% still pay a 1.8-4.3s resolution cost the macOS numbers didn't show.
- [PR #276's fix live-verified: hard stop and pause both register from one chained utterance](docs/field-notes/2026-08-15-pause-phrase-fix-live-verified-hard-stop-and-pause-both-register.md): closes the mutually-exclusive-gates finding from 2026-08-12, confirmed twice in a row.
- [Safety-phrase reliability battery: "halt" and bare "Athena" are unreliable; "stop"/"abort" are solid](docs/field-notes/2026-08-15-safety-phrase-reliability-battery-halt-and-bare-athena-unreliable.md): "halt halt halt" failed 4/5 round-trip tests and the bare resume word failed 3/5, against a codebase claim of 5/5 that only reproduced with surrounding context; no false positives found from gibberish or foreign-language input.
- [Both original freeze-repro conditions ran clean once volume was confirmed good](docs/field-notes/2026-08-15-vad-freeze-both-repro-conditions-clean-at-confirmed-good-volume.md): 35/35 utterances processed at 65% output volume, and the one 150.6s stall fully explained by genuine idle time.
- [claude-code survives a 6-cycle VAD stress run where codex froze on cycle 5 of 5](docs/field-notes/2026-08-15-vad-freeze-claude-code-backend-more-resilient-than-codex-on-macos.md): also isolates a benign false-alarm shape in the stall diagnostic itself.
- [The audio harness is exonerated for short stalls; the severe freeze looks coupled to real audio-pipeline activity](docs/field-notes/2026-08-15-vad-freeze-harness-confound-check-pure-text-still-stalls-severe-variant-audio-coupled.md): short stalls reproduce identically via pure text with no mic, speakers, or STT — 0/10 severe in the text batch against 1/10 and 1/5 in matched audio batches.
- [The severe freeze does NOT require active stress — confirmed directly](docs/field-notes/2026-08-15-vad-freeze-idle-trigger-confirmed-no-active-stress-needed.md): one ordinary interaction followed by 100+ seconds of pure idle listening was enough to trigger it.
- [The idle-trigger freeze does not reproduce on claude-code](docs/field-notes/2026-08-15-vad-freeze-idle-trigger-does-not-reproduce-on-claude-code.md): four minutes of idle under the identical condition that reliably hits codex at ~90-100s onset.
- [opencode does not freeze under the idle-trigger condition either](docs/field-notes/2026-08-15-vad-freeze-idle-trigger-does-not-reproduce-on-opencode.md): 5+ minutes idle plus two probe utterances stayed fully responsive; includes a self-caught false alarm kept deliberately as a methodology note.
- [The definitive idle-trigger re-run: readline() stalls were harmless, a separate mic-layer freeze was the real problem](docs/field-notes/2026-08-15-vad-freeze-idle-trigger-re-run-with-busy-diagnostic-readline-was-harmless-mic-layer-freeze-real.md): a 335.6s "stall" — longer than any prior severe catch — was entirely benign, while a structurally different mic-layer freeze occurred twice in the same session.
- [The mic-layer freeze reproduced this round was a volume confound, not a bug](docs/field-notes/2026-08-15-vad-freeze-mic-layer-repro-was-a-test-harness-confound-system-output-volume-at-25pct.md): system output at 25% meant the synthesized test WAVs never crossed the VAD speech threshold; at 70% the identical files worked every time.
- [A new freeze variant: pure mic-layer silence, no backend involved, 6+ minutes, self-resolved](docs/field-notes/2026-08-15-vad-freeze-new-variant-mic-layer-only-6-minutes-self-resolved.md): no codex subprocess ever spawned, and the first freeze in the investigation to recover with no manual intervention — this is the variant that remains open.
- [A major correction: many "stalls" are ordinary idle time, not a hang](docs/field-notes/2026-08-15-vad-freeze-readline-stalls-often-just-idle-time-not-a-hang-busy-state-fix.md): the diagnostic never distinguished "waiting for a response" from "correctly idle, nothing sent" — fixed by adding busy state to the log line, which retroactively reclassified much of the investigation.
- [Re-run with the busy-aware diagnostic: zero genuine hangs in a fresh 10-cycle batch](docs/field-notes/2026-08-15-vad-freeze-re-run-with-busy-diagnostic-zero-genuine-hangs-in-fresh-10-cycle-batch.md): every stall of 5.5s or longer showed busy=False, confirming the correction generalizes rather than being a one-off.
- [Root cause captured: codex is blocked on its OWN stdin, not ConvoBox's event loop](docs/field-notes/2026-08-15-vad-freeze-root-cause-codex-blocked-on-own-stdin-not-convobox-event-loop.md): a live native stack sample directly refutes the long-standing "synchronous audio call blocks the event loop" hypothesis — ConvoBox was entirely idle at that moment.
- [A 10-cycle batch surfaces a self-resolving 66.3s stall AND a second severe freeze](docs/field-notes/2026-08-15-vad-freeze-second-severe-instance-plus-a-self-resolving-66s-stall.md): two for two batches, both near the tail after explicit stress had already stopped.
- [The VAD/mic-pipeline freeze reproduces live on macOS](docs/field-notes/2026-08-15-vad-mic-freeze-live-reproduced-on-macos.md): a 94.4s readline() stall plus 2+ minutes of total mic silence that survived a safeword, a subprocess kill, and a fresh utterance.
- [PR #302's race fix is live-reverified, closing its own unchecked test-plan box](docs/field-notes/2026-08-18-artifact-active-race-fix-live-reverified-post-restart.md): 5/5 clean across three runs against a genuinely fresh process with real concurrent HTTP requests, no TestClient shortcuts.
- [Bare "Athena" mis-transcribed by real human speech on Windows](docs/field-notes/2026-08-18-bare-athena-stt-unreliable-real-voice-windows.md): extends the earlier macOS/synthetic-speech-only finding to real voice on a second platform.
- [A ~1s ambiguous barge-in was hallucinated into 69x "brake", false-triggering the safeword hard-stop](docs/field-notes/2026-08-18-brake-safeword-stt-hallucination-false-positive-hard-stop.md): the first confirmed false positive on the safety path — a hallucination, not a mishearing of a real word.
- [The first real-voice kill_phrase test finds two real gaps, both previously invisible to scripted testing](docs/field-notes/2026-08-18-kill-phrase-live-voice-test-finds-two-real-gaps.md): the just-merged pgrep fallback had a 15-char minimum-length guard silently excluding short commands like `sleep 90`, and the "ends this session" claim didn't hold — the self-signal SIGINT never reached `asyncio.run()`'s handler.
- [The pgrep-fallback fix is reconciled, re-verified, and shipped](docs/field-notes/2026-08-18-macos-force-kill-pgrep-fallback-reconciled-and-shipped.md): clean rebase, 20/20 on real spawned processes, and the disclosure across KNOWN-ISSUES/README/STATUS/CHANGELOG corrected from "candidate fix, unconfirmed" to "fixed, closed".
- [kill_phrase ends the session but leaves an orphaned, resource-heavy child running on Windows](docs/field-notes/2026-08-19-kill-phrase-windows-orphaned-descendant-survives-force-kill.md): a deliberately detached PowerShell write loop survived 2+ minutes past full session exit, stopping only on its own timer; the macOS `ps` fallback doesn't apply on Windows, and an automated harness driving the identical scenario failed to reproduce it 8/8.
- [A real Windows amplitude sweep confirms AEC struggles at high volume there too, but Audio Enhancements' effect on it is genuinely mixed](docs/field-notes/2026-08-20-windows-amplitude-sweep-audio-enhancements-mixed-effect.md): matched N=3 sweep (36 trials) on Realtek+amplified-7.1 hardware reproduces the macOS "AEC worse than off at high volume" finding on different hardware, but Windows Audio Enhancements' effect on the pipeline is a mixed result, not simply good or bad.
- [A full delay x volume grid (250 real trials, N=10 each) reproduces the macOS AEC-worse-at-high-volume finding at statistically robust scale](docs/field-notes/2026-08-27-full-delay-x-volume-grid-aec-processing-makes-self-barge-in-worse-at-high-volume.md): confirms issue #119's finding holds across every standard delay candidate, not just `auto`, and pins the crossover to roughly the same 30-50% range the earlier 119-trial sweep found; the known `aec_delay_ms=400`+`barge_in_min_speech_ms=1200` mitigation was not included in this grid.
- [The known 1200ms barge-in-threshold mitigation validated at N=10 across the full volume range](docs/field-notes/2026-08-28-mitigation-grid-barge-in-threshold-1200ms-plus-400ms-delay-validated-at-scale.md): 300 trials, complete elimination of AEC-caused false barge-ins at 20-35% volume, 2.4-6x improvement at 50-100% (still short of raw-AEC-off there); `aec_delay_ms=309` -- not the newly-tested 400ms -- turns out the most consistently strong paired delay choice.
- [Real external speakers essentially eliminate the AEC-worse-at-volume problem at 75% and below](docs/field-notes/2026-08-28-external-vs-internal-speaker-confirms-mac-mini-built-in-speaker-is-the-driver.md): first direct (not corroborated-by-citation) evidence the Mac mini's built-in speaker was the driver all along -- essentially zero false barge-ins at 50-75% volume on external speakers vs. 4.6-9.9 mean on the internal speaker at the same settings.
- [An N=20 fixed comparison confirms the grid finding exactly; a THD sweep gives the first objective distortion measurement; a real jack-mute methodology gotcha found along the way](docs/field-notes/2026-08-29-thd-measurement-and-n20-fixed-comparison-plus-front-jack-mutes-internal-speaker-gotcha.md): something physically plugged into the Mac mini's front 3.5mm jack mutes the internal speaker at the hardware level regardless of software output-device selection (a real testing-methodology trap); once isolated, internal speaker shows 4.66% THD at 4kHz/100% volume vs. external's 1.02% -- the first objective measurement backing this whole field-note series' distortion hypothesis.
- [Building an ESS/Farina sweep tool surfaces two real bugs](docs/field-notes/2026-08-29-ess-farina-sweep-tool-debugging-a-missing-2pi-and-a-bad-fr-window.md): a missing 2*pi in the sweep's phase formula silently scaled the whole sweep down by ~6.28x, and a 1.5s frequency-response window measured room decay instead of direct sound -- both caught only because independent discrete-tone THD data already existed to sanity-check against; RT60 output flagged unresolved.
- [Chasing the RT60 discrepancy: one real bug fixed, one real limit found](docs/field-notes/2026-08-30-rt60-discrepancy-root-caused-not-a-code-bug-not-enough-dynamic-range.md): fixed a real Chu-correction clip-ordering bug, then root-caused the remaining ~10x gap to genuinely insufficient measurement SNR (~18-24dB vs. the ~30-45dB ISO 3382 wants) for this near-field/safe-volume setup, not a further code bug -- added an honest `t20_reliable`/`t30_reliable` flag instead of a silently-wrong number; same-day addendum confirms the fix at 25-75% volume, RT60 converging to a consistent ~0.51-0.55s.
- [External speaker THD gap-fill reveals volume-dependent bass distortion, and a Tone dial before/after resolves most of it](docs/field-notes/2026-08-30-external-speaker-200hz-thd-gap-fill-reveals-volume-dependent-bass-distortion.md): 200Hz THD climbs to 46-48% at 75% volume while 1kHz/4kHz stay under 1% -- a genuinely new finding, corroborated by JP's own prior knowledge of this speaker's weak bass/treble response.
- [Tone dial before/after: full bass cuts 200Hz THD 2-3x vs. full treble](docs/field-notes/2026-08-30-tone-dial-before-after-full-bass-cuts-200hz-thd-2-3x-vs-full-treble.md): a physical Tone dial (found only after identifying the speaker's Z200-class QSG) was full-treble for the entire field-note series without anyone knowing -- full bass measurably halves-to-thirds the 200Hz distortion, though a frequency-response sweep shows this is NOT a simple bass-boost (100-300Hz broadband energy is unchanged or even slightly lower), so the mechanism remains unresolved.

## Development record (primary sources behind the notes)

- [UAT checklist](docs/UAT-checklist.md): per-subsystem live-testing matrix and raw findings ([E*]/[L*]/[U*]).
- [Known issues](docs/KNOWN-ISSUES.md): diagnosed-and-deferred problems, indexed by component/platform/severity.
- [Permission model](docs/PERMISSION-MODEL.md): canonical reference for `backend.permission_mode` across all three backends.
- [AI attribution convention](docs/AI-ATTRIBUTION.md): how every AI-assisted change in this repo is provenance-stamped.
- [Working agreements](AGENTS.md): change-scope discipline binding every agent in the repo, each rule citing its incident.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.