Configuration Reference¶
YazSes reads its settings from ~/.config/yazses/config.toml on Linux (~/Library/Application Support/yazses/ on macOS, %LOCALAPPDATA%\yazses\ on Windows). Every section has defaults, so a missing config file is valid and every v2 feature is dormant (enabled = false) until you opt in.
Prefer yazses features enable/disable <toggle> over hand-editing — it writes the right keys and preserves your comments. This table is the full surface for when you do want to edit by hand.
Match the Type column exactly. In TOML only str values take quotes; int, float and bool must be bare. Writing vad_threshold = "0.004" instead of vad_threshold = 0.004 loads without complaint and then fails at runtime, because the value stays a string where a number is expected. See Troubleshooting.
63 of these 554 keys are inert, and they are marked ⚠️ inert in the Status column. The loader accepts them, configcheck validates them and they have a documented default — but nothing acts on them, so setting one loads without complaint and changes nothing. Most belong to capabilities that are registered but not yet wired; see yazses features for what is actually switchable. Both numbers here are counted at generation time, and the list of inert keys is the same one the test suite gates on, so neither can quietly fall out of date.
This has bitten before: [injection] fallback_to_clipboard was documented in seventeen places and defaulted to true while nothing read it, so anyone who turned it off was silently overruled.
[stt]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
engine | str | "faster-whisper" | Which speech-to-text backend decodes audio: "faster-whisper" (default, Whisper via CTranslate2) | "parakeet" (NVIDIA Parakeet TDT via onnx-asr — 2.06% WER against whisper-large-v3's 3.23% on 200 LibriSpeech utterances, measured at ~20x realtime CPU on 16 Xeon vCPUs; opt-in via yazses features enable stt-parakeet). An unknown value or a missing optional dep falls back to faster-whisper with a logged warning — never a crash (stt/factory.py). | |
model | str | "base.en" | base.en is the default because it is the best latency trade for hold-to-talk, not because the larger checkpoints add little -- they add a lot, and this comment used to say otherwise. Measured on 200 LibriSpeech utterances per cell (results/wer.json and wer-test-other.json): tiny.en scores 4.82% on clean audio and 11.77% on hard; base.en 4.07% and 9.46%; small.en 2.59% and 5.59%; medium.en 5.51% on hard. So small.en removes 36% of base.en's errors on clean audio and 41% on hard audio, for about twice the decode time (RTF 0.104 against 0.049) -- still ~10x realtime, so a five-second burst costs roughly half a second more. That is the real trade: if you notice word errors more than you notice the wait, set small.en. medium.en costs 2.6x small.en for 0.08 of a point and is not worth it. large-v3 is worse than both on hard audio (7.69%) and decodes a different answer each run -- see condition_on_previous_text below. Read the ordering, not the digits: CTranslate2 picks different int8 kernels per instruction set, so the same decode on another CPU lands a few hundredths away (this laptop's 2.59% for small.en is 2.66% on a Xeon). The ranking is stable; the third significant figure is not. | |
language | str | "en" | Spoken language, as a Whisper code ("en", "de", "fr", "es", "fa", …). Empty string = let Whisper auto-detect per utterance, which costs an extra decode pass and can flip mid-session, so an explicit code is preferred when you know the language. Requires a MULTILINGUAL model: the .en checkpoints (base.en, small.en, …) and the distil-* checkpoints are English-only and cannot decode anything else, so set model = "small" (no suffix) alongside it. A contradictory pair is refused, not decoded as English: doctor fails it, Settings will not save it and dictation does not start (#515; the cited table is src/yazses/language/capability.py). The default Parakeet and Moonshine models are English-only too. Ignored on the translate path (ADR-v2-014), which auto-detects the source by design. | |
device | str | "cpu" | Where CTranslate2 runs the decode: "cpu" (default) | "cuda" | "auto". YazSes is a CPU-first project — every published benchmark, latency target and model recommendation on this page assumes int8 on CPU — so "cuda" is supported but unmeasured, and needs a CTranslate2 built against your CUDA runtime. Ignored by engines that do not decode through CTranslate2 (Parakeet, Moonshine). | |
compute_type | str | "int8" | Decode precision. "int8" (default) is the CPU-first choice and what everything here is measured at; "int8_float32", "float32" and (on GPU) "float16" also exist. The supported set is a property of your CPU, not of this project: an unsupported value raises inside WhisperModel(...) and is re-raised as ModelUnavailableError, so it is reported as a missing model rather than a bad precision. ctranslate2.get_supported_compute_types(device) is the authority, and the Settings window checks against it before writing this key. | |
condition_on_previous_text | bool | true | Whether each decode window is prompted with the text of the one before it. true (default) is faster-whisper's own default and what every published YazSes benchmark was measured at — leave it alone unless you have configured a large checkpoint. What it buys and what it costs was measured, five decodes per arm, 200 LibriSpeech utterances (docs/benchmarks.md, and the artifacts decode-determinism-*.json under results/probes/). On base.en, the shipped model, conditioning is simply better: 4.01% against 4.24-4.28% on test-clean, 9.46% against 9.81% on test-other, and bit-reproducible run to run. On large-v3 the sign flips — conditioning sends the model into a repetition loop on roughly 1.5% of utterances, which is what makes that checkpoint's WER wander between 4.84% and 6.21% across identical runs, and turning it off removes the runaway and makes decoding reproducible. Note what that is not: the corpus-average gain from turning it off is 1.05 points with a 95% interval of [-2.59, +0.16], more utterances get worse (8) than better (4), and 95.7% of it comes from three clips. This is a knob for not losing a paragraph to a repetition loop, not a knob for lowering WER. It applies to dictation, not only to long recordings: faster-whisper advances to the model's last emitted timestamp rather than by a whole 30s window, so 8-20% of ordinary sub-30-second utterances take a second pass that carries the first pass's text. Measured across the checkpoint ladder on test-other, the benefit shrinks and then reverses: base.en 9.46% on against 9.81% off, small.en 5.59% against 5.70%, medium.en identical output byte for byte, large-v3 4.84-6.21% against 3.82%. So it is a size rule, not a preference -- leave it alone on base.en and small.en, it changes nothing on medium.en, set it false on large-v3 and above. medium.en's zero is the strongest cell in the ladder and the only one that needed no statistics: 20 decodes over both splits -- 5 per arm on test-other at 5.51% and 5 per arm on test-clean at 3.28% -- produced a single distinct hypothesis set per split, so the two arms are not merely equal on average, they are the same text. That is why the rule above is stated as a threshold rather than a trend: the effect does not shrink toward zero at medium.en, it is exactly zero there, and only reappears with the opposite sign on large-v3. | |
initial_prompt | str | "" | Optional vocabulary/context primed into Whisper as initial_prompt. Helps it spell domain terms and proper nouns it otherwise mis-transcribes. yazses tune proposes additions here from the learning corpus. | |
vocab_correction | bool | false | Recover personal-vocabulary words the recogniser mis-heard, after decoding (#73). initial_prompt is Whisper-only, so with engine = "parakeet" the personal dictionary is otherwise ignored entirely — this is engine-agnostic and helps Whisper too. OFF by default: it rewrites transcribed text, and that is a thing a user should switch on knowingly. | |
cpu_threads | int | 0 | How many CPU cores the decoder may use. 0 keeps ctranslate2's default, which is "all of them" — a 0.8 s decode measured 4.9 CPU-seconds on a 20-core laptop, because the work is spread across every core. That is the right trade on mains power and the wrong one on battery, where the cost is the core-seconds rather than the wall-clock. Nothing capped it before this. | |
beam_size | int | 0 | Decoder beam width. 0 keeps faster-whisper's own default (5). 1 is greedy decoding; it is here so the Adaptive Latency Governor ([latency]) can ask for it on a loaded machine, and so a user who wants that trade permanently can take it without one. What the trade actually costs, measured on 200 LibriSpeech utterances per cell (docs/benchmarks.md): greedy costs base.en 0.38 WER points on clean audio and 1.07 on hard audio, and is 11-16% faster — a smaller speed gain than "greedy" suggests. On small.en and clean audio it is better (2.53% against 2.66%), so "worse" is a property of the model and the audio, not of beam search. Beams 2, 5 and 8 score identically on base.en; the default is 5 because it is the well-trodden setting and beam 2 would save about 20 ms on a five-second burst, which nobody can perceive. Ignored by engines that do not decode with a beam. | |
chinese_script | str | "" | Which Han script Chinese output is written in: "simplified" (简体, mainland) | "traditional" (繁體, Taiwan/Hong Kong) | "" to leave the model's own choice alone. Whisper picks a script per utterance and is not consistent about it, so a mainland user gets Traditional characters back for a large share of correct transcriptions (postprocess/han_script.py has the measurements). Empty by default because the right answer is regional, not universal. Needs the chinese extra; without it the setting warns once and no-ops. | |
persian_normalisation | bool | false | Conservative Persian Unicode normalisation of the transcript (NFC, Arabic Yeh/Kaf -> Persian Yeh/Keheh, ZWNJ tidying, bidi-control strip; see postprocess/persian_text.py and design/specs/persian-text-and-rtl.md). Off by default: the normaliser changes the text a Persian user already gets, so an upgrade must not switch it on for them. It only acts when language is also Persian ("fa"); set on its own it warns once and no-ops. | |
idle_unload_s | int | 0 | Release the speech model after this many seconds without a decode, and load it again on the next press (ADR-029). 0 (default) = never: the model stays loaded for as long as the daemon runs, which is what makes the first word fast. A positive value trades that for memory on a small machine: base.en holds about 190-220 MB once loaded. The reload starts when you press the key and runs while you speak; your audio is recorded either way, but the first words after a long pause arrive a few seconds late, and the tray shows "loading" while they do. Values under a few minutes mean most presses pay the reload. How much memory an unload hands back to the OS is not yet measured: CTranslate2 may keep some of it. |
[residency]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
latency_keep_alive_s | int | 0 | The latency governor's second model (ADR-029): with [latency] on, the daemon loads a lighter Whisper model when the CPU is busy and keeps it after. This is how many seconds that extra model stays in memory after its last use before it is released; the next time the governor wants it, it reloads in the background. 0 (default) = never release, which is what the daemon did before this key existed, so an install that has not set it is unchanged. The dictation model is never released by this key: [stt] idle_unload_s owns that one. Values under a few minutes mean a busy spell pays the reload; the released memory is not yet measured. |
[hotkey]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
key | str | "auto" | "auto" resolves to the platform's default hold-to-talk key (Linux: right_alt, macOS: right_option, Windows: right_ctrl) — a modifier key, so it never collides with normal typing the way the space bar would. | |
hold_threshold_ms | int | 500 | ||
source | str | "default" | ⚠️ inert | |
evdev_device | str | "" | ⚠️ inert | |
command_key | str | "" | Optional dedicated command key. Empty = single-key mode (commands are auto-detected on the dictation key). When set to a different key, holding it forces command mode: whatever you say is parsed as a command and never typed as literal text (an unrecognised phrase is ignored, not inserted). |
[audio]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
sample_rate | int | 16000 | ||
channels | int | 1 | ⚠️ inert | |
max_record_seconds | int | 300 | Hard cap on a single hold-to-talk recording. Generous so long dictations aren't cut off mid-sentence; raise further in config for very long takes. | |
device | str | "" | Pin the input microphone by name (case-insensitive substring). Empty = follow the OS default input device. Resolved fresh on each recording, so a hotplug that shifts device indices can't break the pin. Set it with yazses audio use <name> so a monitor/headset can't silently steal capture. | |
device_change_notify | bool | true | Desktop-notify (with action buttons where supported) when the OS default input device changes — so a silent switch that breaks dictation is visible. | |
silent_streak_notify | bool | true | Desktop-notify after a run of consecutive silent-discards (the direct "dictation stopped writing" symptom of a mic that switched to a dead source). | |
silent_streak_threshold | int | 3 | How many silent-discards in a row trigger the notify + auto-heal. | |
auto_heal_device | bool | true | On a device change / silent streak, automatically switch capture back to the last device that produced usable audio ("last-good"), then notify what changed. | |
device_poll_interval_s | float | 3.0 | Cadence of the background default-input-device watcher, in seconds. 0 disables the watcher (the silent-streak detector still works, being on the hot path). | |
level_stream_rescan_s | float | 30.0 | While a hands-free feature holds the microphone open (Vocal Morse listening for its entry hum, the Mouth-Sound Switch or the Vocal Joystick while armed), the watcher cannot re-scan the audio devices without briefly closing that stream. It does so every this many seconds, closing the stream for a moment and reopening it; between re-scans it only reads the current default, which on PipeWire already notices a switch. Lower it to notice an unplugged mic sooner on macOS and Windows, raise it if the short gap in the hands-free stream bothers you. 5 to 3600. | |
level_stream_in_use_max_s | float | 600.0 | A re-scan waits while you are in the middle of using one of those streams (Morse mode on, a switch scan running, a held joystick vowel), so it never cuts a letter or a highlight short. This is the longest it waits: a backstop for a sound that never ends, such as a fan read as one endless Morse pulse. 10 to 3600. | |
level_stream_fresh_s | float | 2.0 | A hands-free stream counts as "in use" only while it has delivered audio within this many seconds. A microphone unplugged mid-gesture stops delivering, so after this long the frozen gesture no longer holds the re-scan off and the dead device is noticed. 0.5 to 60. | |
voice_answer | bool | false | Answer the mic guard's [Re-calibrate]/[Pin this mic]/[Ignore] toast by SAYING one of them (ADR-022, Spec 1). Without this the daemon asks a question about your microphone that can only be answered with a pointer -- and the person seeing it is the one whose dictation just stopped working. OFF by default like the other utterance-consuming guards ([cmdsafety], [checkdigit]): it swallows a burst that would otherwise be typed, and that is a behaviour change to opt into. | |
voice_answer_window_s | float | 45.0 | How long the toast stays answerable by voice. Bounded on purpose -- "ignore" is an ordinary word, and an unbounded window arms it for the rest of the session. |
[injection]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
backend | str | "auto" | How text reaches the focused app. "auto" (default) probes the session: xdotool on X11, ydotool on Wayland (types, so it works in terminals too). "type"/"ydotool" force typing, "clipboard" forces copy+Ctrl+V (instant, but a no-op in terminals where Ctrl+V is literal), "wtype" is Wayland-only and is ignored on X11, and "unicode" is an opt-in Linux XKB/uinput path. yazses doctor names the one that will actually be used. "portal" forces the xdg-desktop-portal RemoteDesktop API (inject/portal.py). auto already picks it on Wayland when ydotoold is not running, which is the case inside a strictly confined snap; force it when a session has a stale ydotoold socket that wins the probe but cannot actually inject. On Windows two values apply: "auto" (SendInput + KEYEVENTF_UNICODE, the default) and "clipboard" (copy + a real Ctrl+V). Use "clipboard" when an application receives the right number of characters and every one of them is wrong -- rows of "?", "-" or "." instead of the words. Microsoft documents both causes: an ANSI window has each character converted to the active ANSI codepage ("?" for anything it cannot represent), and a text service that does not unpack the synthesised VK_PACKET keystroke runs it through the keyboard layout instead. Pasting bypasses both. yazses inject -d 5 --diagnose "test" says which window you are actually typing into and whether it is ANSI. | |
portal_consent | str | "ask" | Whether auto may select the RemoteDesktop portal on Wayland. "ask" (default) | "allow" | "deny". OFF by default, deliberately: the portal makes the desktop show a screen-sharing indicator for as long as the session is open, and switching that on for somebody -- in an application whose whole promise is that nothing leaves the machine -- is not a default to take on their behalf. With "ask", dictation uses the clipboard fallback and YazSes offers the choice instead. Three things already count as consent and are NOT affected by this key, so no working install is regressed: naming backend = "portal", an existing restore token on disk (you answered the dialog before), and a strictly confined snap, for which the portal is the only way to type on Wayland at all. | |
portal_idle_release_s | int | 60 | Seconds of idle before the portal session is closed; 0 keeps it open forever. The one place this file deliberately ships a feature "on": defaulting to 0 would ship the indicator sitting in the top bar for the daemon's whole life, which is the complaint this key exists to answer. Re-opening replays the restore token, so it costs a round trip on the first burst after idle and no new dialog. Set 0 if you prefer the session pinned open. | |
fallback_to_clipboard | bool | true | ||
continuation_window_ms | int | 30000 | Successive hold-to-talk bursts within this window are treated as one continuous dictation: a separating space is prepended to the next burst so words don't glue together at the boundary (postprocess/spacing.py). 0 disables continuation spacing entirely. | |
target_guard | str | "clipboard" | "No text target" guard: what to do when you dictate with no editable field focused (so the text would be typed into the wrong place / nowhere). "clipboard" (default) — copy the transcript to the clipboard + notify instead of typing; "warn" — notify but still type; "off" — no guard. Detection is AT-SPI when available (precise; needs python3-pyatspi), else a best-effort X11 focus check. Only acts on a confident "no target", so it never drops normal dictation. |
[general]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
log_level | str | "INFO" | ||
update_check | bool | false | Periodically ask whether a newer YazSes has been released and, if so, say so once with the exact steps to update. OFF by default, and it must stay that way: this is the only thing in YazSes that reaches the network on its own, and "nothing leaves the machine" is the product. A background check tells github.com/PyPI your IP and that you run this tool. Nothing about your voice, audio, text or config is ever sent — the request is a plain "what is the latest version" GET — but it is still an outbound connection the user has to choose. Turn it on with yazses features enable update-check. | |
update_check_interval_hours | int | 24 |
[streaming]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | Disabled by default for two independent reasons. Correctness: live-partial injection corrects on commit via shift+Left selection (inject/streaming.py), which deletes text in apps where shift+Left isn't "extend selection". Batch transcribe-on-release is the reliable, higher-accuracy path proven by tools like nerd-dictation and faster-whisper-dictation. Latency: streaming does NOT make the final text arrive sooner — commit() re-decodes the whole utterance anyway, now competing with a decode loop running every partial_interval_ms. Measured (benchmark/bench_streaming.py, n=15 real-time-fed utterances): speech-end -> final text 0.92 s -> 1.22 s on tiny.en, and 1.42 s -> 2.21 s on base.en. Worse, on base.en the rolling decode cannot keep up with the audio, so LocalAgreement confirmed no prefix at all before release in 9 of 15 utterances (0 % visible at release, vs 72 % on tiny.en). Streaming is only a win on tiny.en. Opt back in with [streaming] enabled = true. | |
partial_interval_ms | int | 300 | ||
partial_marker | str | "" | ⚠️ inert |
[filters]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
[filters.disfluency] | ||||
disfluency.enabled | bool | true | ||
disfluency.filler_words | list | ['um', 'uh', 'er', 'ah', 'hmm', 'you know', 'i mean', 'okay so', 'so um', 'so uh'] | ||
disfluency.self_correction_triggers | list | ['no wait', 'delete that', 'scratch that', 'never mind', 'forget that', 'strike that'] | Saying one of these discards everything before it in the same burst. They are also ordinary English, so a trigger is treated as prose -- and the sentence is typed whole -- when the word immediately before it is a negation ("do not delete that branch"), a governing verb ("you should never mind the warning"), an article or possessive ("the no wait policy", "your delete that habit"), a reporting verb ("she said no wait for the batch"), or a copula ("there is no wait time"). Only that one word is consulted, so "they told me scratch that plan" is still rolled back. Remove a phrase from this list if you dictate it in prose more often than you use it to correct yourself. | |
disfluency.collapse_repetitions | bool | false | b-b-because / b b because / the the the | |
disfluency.collapse_prolongations | bool | false | sooo -> so | |
disfluency.prolongation_min_run | int | 3 | letter-run length that triggers collapse | |
disfluency.repetition_max_fragment_len | int | 2 | max length of a stutter "fragment" | |
disfluency.llm_enabled | bool | false | ||
disfluency.llm_endpoint | str | "http://localhost:11434" | ||
disfluency.llm_allow_remote_endpoint | bool | false | Refuse an llm_endpoint that is not loopback. Cleanup sends transcribed text to the endpoint, so a remote host here would carry dictation off the machine — which AGENTS.md rule 1 ("nothing leaves the machine") forbids by default. Setting this true is the deliberate, documented opt-out; the daemon warns on every start while it is on. | |
disfluency.llm_model | str | "" | Local GGUF model path for offline cleanup; empty falls back to the Ollama HTTP endpoint above. Mirrors the Rust v1.0 [cleanup] feature for the Python path (kept in parity until v1.0 GA). | |
disfluency.llm_system_prompt | str | "Reformat only. Do not add facts and do not remove information. Preserve every proper noun, number, code identifier, and URL exactly as given. Fix capitalization, punctuation, and paragraph breaks; do not change word choices. Output ONLY the reformatted text with no preamble, no explanation, and no markdown fences." | ||
disfluency.llm_max_tokens | int | 256 | ||
disfluency.llm_timeout_ms | int | 2000 | ||
disfluency.llm_min_length_ratio | float | 0.5 | ||
disfluency.llm_max_length_ratio | float | 2.0 |
[accessibility]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
min_silence_ms | int | 500 | ||
pre_speech_padding_ms | int | 300 | Silence prepended before STT decode, and the size of the (deliberately unfed) pre-speech ring buffer. Measured on 200 LibriSpeech utterances with the leading room tone trimmed away: with the onset intact it changes nothing, every lead from 0 to 1000 ms landing inside the run-to-run noise band. It matters only when the key was caught late and speech is actually missing, and there it changes sign -- with 40 ms of speech gone it recovers 6 opening words in 200, with 120 ms gone it loses 11. Silence cannot reconstruct audio that was never captured; 300 ms is kept because it is the better half of that trade in the near-miss case and costs nothing when there is no miss at all. | |
vad_source | str | "default" | ⚠️ inert | |
vad_threshold | float | 0.01 | ||
speech_presence_check | bool | true | Before decoding a burst that cleared vad_threshold, ask a speech detector (Silero, bundled with faster-whisper) whether there is any speech in it, and discard the burst if there is none. Loudness cannot tell a talker from a fan, and Whisper answers a burst of fan with the words it was primed with (#598: "The app is called YazSes."). Fails open: a detector that cannot run decodes as before. Skipped in Whisper / Low-Effort mode, Dysfluency-Friendly mode and the sotto-voce command channel. Set false if quiet speech is being discarded as "no speech". | |
dysfluency_friendly | bool | false | v0.8.0 — Dysfluency-Friendly Mode master preset (ADR-015): enables the disfluency collapse pass and widens onset padding. Off by default. | |
read_back | str | "off" | v2 — Read-Back Loop (spec-read-back-loop): speak the final transcript back via offline TTS so dictation can be verified by ear. "off" (default) | "final" (P1: read the final transcript) | "confirm" (P2: full yes/no/redo loop). Requires [tts] enabled. confirm_timeout_s is the P2 listen window. | |
confirm_timeout_s | float | 6.0 | ⚠️ inert |
[commands]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | true | ||
profile | str | "auto" | Which editor's keys a spoken command sends. Read only when editor_profiles is on: "auto" follows the focused application; default, vscode, jetbrains or sublime pins that profile for every application (commands/profiles.py). | |
language | str | "auto" | auto | en | zh | |
custom | list | [] | ||
slm_model_path | str | "" | path to GGUF file; empty = disabled | |
slm_confidence_threshold | float | 0.75 | ||
lsp_enabled | bool | false | ⚠️ inert | v0.4.0 — LSP context injection (ADR-v04-002) |
lsp_editor | str | "auto" | ⚠️ inert | auto | neovim | vscode |
voice_punctuation | bool | false | v1.4.0 — spoken punctuation/formatting in dictation ("comma", "new line"). Off by default: these words also occur in ordinary speech. | |
rewrite | bool | false | Offline Command Mode (#99): with a selection and the command key held, "make this shorter" rewrites it in place using the LOCAL model configured under [filters.disfluency]. OFF by default — it replaces text the user already wrote, which is not something to switch on for them. | |
rewrite_timeout_s | float | 20.0 | ⚠️ inert | Seconds a local rewrite may take before it is abandoned and the selection left alone. A stalled model must not hold the dictation pipeline. |
symbols | bool | false | v2.4 Wave H — Emoji & Symbol by Voice (ADR-v2-055): "shrug emoji"→🤷, "right arrow"→→. Off by default: the names also occur in ordinary speech. | |
self_repair | bool | false | v2.4 Wave H — Mid-Utterance Self-Repair (ADR-v2-058): "email Sarah no I mean Sara"→"Sara". Off by default: editing phrases also occur in ordinary speech. | |
spoken_edit | bool | false | v2.0.0 Wave A — Spoken Edit Mode (ADR-v2-003): open-ended voice editing of the last-injected span ("change X to Y", "delete the last sentence"). Command-key gated to avoid dictate-vs-command ambiguity. OFF by default. | |
spoken_edit_destructive | bool | false | Allow destructive spoken edits (delete last sentence/words). OFF by default; when on, a destructive edit still updates the ledger so "scratch that" undoes it. Requires spoken_edit. (ADR-v2-003) | |
editor_profiles | bool | false | Editor command profiles: send the keys the focused editor binds — Ctrl+Y, not Ctrl+Shift+K, to delete a line in a JetBrains IDE — and refuse a command the editor has no safe key for. OFF by default; off, every application gets the VS Code-style keys. The focused app is read via AT-SPI or X11 xdotool on Linux, the frontmost app's bundle id on macOS, the foreground program's name on Windows. |
[macros]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
path | str | "macros.toml" | relative to config dir, or absolute | |
author | str | "" | value substituted for ${author} |
[revise]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | true |
[punch_in]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_score | float | 0.5 | minimum difflib similarity to surface a span | |
max_candidates | int | 3 | ||
record_seconds | float | 4.0 | re-record window for the respoken phrase |
[endpoint]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_silence_s | float | 0.3 | ||
stable_updates | int | 2 | ||
prewarm | bool | true | Phase 1: eagerly decode the buffer on endpoint | |
speculative_finalize | bool | false | ⚠️ inert | Phase 2 (gated): decode early, discardable |
debounce_ms | int | 500 | min gap between endpoint fires (anti-thrash) | |
prefix_stable_ms | int | 400 | ⚠️ inert | confirmed prefix unchanged this long = content flat |
falling_window_ms | int | 250 | ⚠️ inert | window over which trailing energy must be falling |
[prosody]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
format | str | "none" | none | markdown | |
pause_paragraph_ms | int | 700 | inter-word gap (ms) at/above which a ¶ is inserted | |
pause_sentence_ms | int | 0 | v2.0.0 Wave A — pause→sentence punctuation (ADR-v2-002). 0 disables; when >0, a gap at/above this (but below pause_paragraph_ms) inserts a sentence-ending period. | |
emphasis_enabled | bool | true | bold prominent words (only when format renders bold) | |
emphasis_sensitivity | float | 0.65 | 0..1; higher = fewer, surer bolds (precision bias) | |
experimental_pitch_question | bool | false | ⚠️ inert | |
max_latency_ms | int | 150 | latency valve: above this, log + degrade to pause-only |
[remote]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
default_host | str | "" | ⚠️ inert | |
ssh_port | int | 22 | ||
agent_port | int | 9875 | ||
key_file | str | "" |
[emg]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
device_port | str | "" | e.g. /dev/ttyUSB0; empty = disabled | |
baud_rate | int | 115200 | ||
ble_address | str | "" | e.g. "AA:BB:CC:DD:EE:FF"; empty = disabled | |
mode | str | "command" | command | full_text | |
command_map | dict | {} | ⚠️ inert |
[learning]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
capture_audio | bool | true | ||
retention_days | int | 30 | ||
max_corpus_mb | int | 500 | ||
tune_model | str | "small.en" | Larger model used by yazses tune to re-transcribe captured audio and produce pseudo-ground-truth for error detection. | |
redact_patterns | list | [] | Regexes scrubbed (replaced with [REDACTED]) from text before it is stored. | |
anonymize_audio | bool | false | v2.3 Wave G — Corpus Voiceprint Scrub (ADR-v2-048): speaker-anonymize stored clips. | |
anonymize_strength | float | 1.08 | ||
capture_edits | bool | false | Edit capture (signal b): after a dictation, read the editor line back and record what you changed in place. Opt-in, editor-bridge only (NO keystroke logging). Currently supports Neovim via a --listen socket. | |
edit_capture_delay_s | float | 8.0 | ||
editor_socket | str | "" | e.g. nvim --listen /tmp/nvim.sock; empty = disabled |
[overlay]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | auto-launch the overlay with the daemon | |
style | str | "sonar" | reserved for future styles | |
position | str | "cursor" | cursor | bottom_center | top_center | corner | |
react_to_voice | bool | true | amplitude-driven vs state-only self-animation | |
accent | str | "#00e5ff" | ring colour (neon cyan) | |
size_px | int | 220 | overlay window square size | |
fps | int | 60 | render tick rate | |
cursor_offset_px | int | 28 | offset from the pointer so it isn't under the caret | |
reduced_motion | str | "auto" | auto | on | off. auto follows the desktop's own reduce-animations setting (GNOME, macOS, Windows); a desktop it cannot read means full motion, as before. Reduced motion keeps the ring and drops the travel -- it removes the animation, not the answer to "am I being heard". |
[tray]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | true | auto-launch the tray with the daemon | |
poll_interval_s | float | 1.0 | ⚠️ inert | how often the tray refreshes daemon state |
[tts]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
engine | str | "kokoro" | kokoro | melo | kitten | |
voice | str | "default" | ||
model_path | str | "" | override; empty => auto-resolved/downloaded | |
voices_path | str | "" | Kokoro voices file; empty => auto-resolved | |
sample_rate | int | 24000 | ⚠️ inert | Kokoro native rate |
speed | float | 1.0 | ||
max_readback_chars | int | 600 | truncate very long bursts with "…" | |
clone_voice | bool | false | read back in a clone of the user's own voice | |
clone_backend | str | "openvoice" | openvoice (permissive) | f5 | xtts (non-commercial, opt-in) |
[voiceprint]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "ecapa" | ecapa (speechbrain) | resemblyzer | |
enroll_seconds | float | 25.0 | speech captured during enrollment | |
multi_profile | bool | false | v2.1 Wave E — N-way per-speaker routing (ADR-v2-028) | |
profile_min_similarity | float | 0.5 | ⚠️ inert | min cosine to switch to a matched profile |
[gaze]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "mediapipe" | mediapipe (light, offline) | l2cs | none | |
model_path | str | "" | override the mediapipe model asset; "" = auto-download | |
zones | str | "grid3x3" | ⚠️ inert | grid3x3 | grid2x2 | windows |
camera_index | int | 0 | ||
calibration_points | int | 9 | ||
confidence_min | float | 0.5 | ||
route_dictation | bool | false | v2.0.0 Wave C — Gaze-Routed Dictation (ADR-v2-010): route the next dictation to the looked-at window (else the focused window), and confirm destructive gaze-routed actions since coarse gaze can misroute. Off by default. | |
confirm_destructive | bool | true | ||
deixis | bool | true | Gaze deixis (2026-08): in command mode, "close this" / "focus that" / "minimize this" act on the window the gaze snapshot says you are looking at. Sub-flag of the (opt-in) gaze feature; destructive actions honour confirm_destructive above via an actionable confirm toast. | |
refuse_destructive_fallback | bool | false | Recovery hierarchy (ADR-v2-148): when gaze could not choose a window and the target is only the focused one, a destructive deixis action ("close this") is REFUSED, with feedback, instead of closing the focused window. Off keeps ADR-v2-010's behaviour (run on the focused window). The hands-free preset turns it on; so can you, by hand. |
[facegesture]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
gesture | str | "jaw_open" | jaw_open | brow_raise | mouth_pucker | smile | eyes_closed | |
mode | str | "full_text" | full_text (dictate) | command (force command mode) | |
camera_index | int | 0 | ||
model_path | str | "" | override the FaceLandmarker asset; "" = auto-download | |
hold_threshold | float | 0.5 | open the mic at/above this blendshape score | |
release_threshold | float | 0.35 | close it below this one (must be lower — hysteresis) | |
min_hold_frames | int | 3 | frames above hold_threshold before the mic opens | |
min_release_frames | int | 2 | frames below release_threshold before it closes | |
fps | int | 15 | camera sampling rate (1..60) | |
use_baseline | bool | false | normalise the score against yazses facegesture calibrate | |
confidence_floor | float | 0.0 | 0..1; frames below it never count toward a hold (0 = off) | |
refractory_frames | int | 0 | frames after a release before a new hold may begin | |
max_hold_s | float | 0.0 | seconds: release a hold open this long, once (stuck-open guard; 0 = off) | |
use_active_levels | bool | false | derive hold/release from your rest + active (+ talk) levels | |
active_hold_fraction | float | 0.5 | how far up the rest-to-active span hold sits (<= 0.8) | |
active_release_fraction | float | 0.25 | how far up it release sits (must be below hold) | |
switches | list | [] | Switch mappings (EYE-FACE-002). gesture + mode above stay the one hold-to-talk binding; each entry here ADDS another, as [[facegesture.switches]] tables with gesture (a gesture name) and intent (hold_to_talk | hold_to_command | select | confirm | cancel | pause_pointer | none). Empty = the single-gesture install, unchanged. |
[perception]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
camera_index | int | 0 | which camera the one owner opens | |
fps | int | 15 | shared sampling rate, clamped to 1..60 |
[gaze_refine]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
click_latency_ms | int | 100 | gaze sample aimed at this long before the click | |
lookback_ms | int | 500 | oldest gaze sample a click may be paired with | |
min_confidence | float | 0.5 | eye-agreement floor for a pair (and a held-out pair) | |
min_train_samples | int | 30 | accepted training pairs before a comparison | |
min_holdout_samples | int | 10 | held-out pairs before a comparison | |
holdout_every | int | 4 | every Nth pair is held out of training (2 or more) | |
min_improvement_px | float | 1.0 | held-out error the candidate must save to promote | |
evaluate_every | int | 10 | compare after this many new accepted pairs | |
max_holdout_samples | int | 200 | bound on retained held-out pairs |
[cocktail]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
mode | str | "gate" | gate (P1) | suppress (P2, gated on a model) | |
target_threshold | float | 0.5 | per-window target-speaker cosine score to keep | |
window_ms | int | 500 | The window the gate scores. 500 ms is NOT a recommendation -- it is the value live testing on 2026-06-19 measured as broken, kept only because the feature ships off and features enable cocktail refuses without --force. At this granularity ECAPA scores the enrolled speaker low against their own voiceprint, so any threshold strict enough to reject another voice rejected ~90% of the user's own speech (a 5 s utterance left one surviving window). design/v2-cognitive-layer/02-cocktail-filter.md says revisit only with 1-1.5 s windows plus a much lower threshold tuned live, cohort scoring, or a real target-speaker model -- so this is deliberately not "fixed" by guessing a bigger number, which would swap a known-bad default for an unmeasured one. |
[personalize]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
bias_from_corpus | bool | true | ||
max_prompt_terms | int | 64 | ||
lora | bool | false | ⚠️ inert | P2 master switch (training is heavy) |
lora_base_model | str | "small.en" | ⚠️ inert | |
lora_min_events | int | 200 | ⚠️ inert | |
lora_min_improvement | float | 0.03 | ⚠️ inert | min held-out relative WER win to apply (ADR-v2-021) |
[polyglot]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
pair | str | "" | ||
adapter_path | str | "" | ||
lid | str | "segment" | ⚠️ inert | |
mer_gate | float | 0.0 |
[confidence]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.55 | words at/below this confidence (0..1) are flagged | |
mark_in_overlay | bool | true | ⚠️ inert | show markers via the overlay when available |
[staged]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
spoken_commit | bool | false | also accept "commit that" / "discard that" by voice | |
show_in_overlay | bool | true | ⚠️ inert | show the pending text while you speak |
max_chunks | int | 200 | a runaway buffer is a bug, not a workflow |
[sendto]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[context]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
use_window_title | bool | true | ||
use_selection | bool | true | ||
use_clipboard | bool | false | clipboard is the broadest signal; opt-in separately | |
use_lsp | bool | true | ⚠️ inert | |
max_terms | int | 48 | ⚠️ inert |
[recall]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
scratch | bool | false | capture note-to-self phrases to the scratch pad | |
max_hits | int | 5 | how many recall results to return |
[agent]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
allowlist | list | [] | ⚠️ inert | tool names allowed to run |
confirm | str | "writes" | all | writes | none — confirm before running | |
slm_model_path | str | "" | local planner SLM; empty = disabled |
[pilot]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "atspi" | atspi | none | |
match_threshold | float | 0.5 | min label-match similarity to act | |
confirm_ambiguous | bool | true | ask when several elements tie |
[modality]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
preset | str | "balanced" | balanced | hands-free | voice-only | |
priority | list | ['voice', 'emg', 'gaze', 'keyboard'] |
[activation]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
confirm_threshold | float | 0.9 | below this, a reversible action confirms | |
reject_floor | float | 0.5 | below this, the intent is dropped outright |
[biosignal]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
source | str | "" | Where samples come from. Empty = no source = nothing starts, even with enabled. synthetic is a built-in generator that needs no hardware (for yazses biosignal monitor/doctor and for trying the pipeline); file:<path> replays a recording (CSV, .npz, EDF/EDF+/BDF, or XDF with the xdf extra); brainflow:<board_id>[:<serial port>] opens a board yazses biosignal boards lists (others are refused, network boards included), e.g. brainflow:0:/dev/ttyUSB0 for an OpenBCI Cyton (needs the brainflow package; run yazses biosignal doctor to see what is installed and which ports are visible). lsl:<stream name> or lsl:type=EEG reads a Lab Streaming Layer stream published on this machine only (lsl extra); thinkgear:<port> a NeuroSky headset and bitalino:<port> a BITalino board (emg extra); myo:<address> a Myo armband's raw EMG over Bluetooth LE (ble extra). | |
mains_hz | int | 50 | Powerline frequency, 50 or 60 Hz: the notch the filters place on the mains hum that otherwise swamps microvolt signals. 50 is the default because most of the world (Europe, Africa, Asia, Oceania) runs 50 Hz mains; set 60 in the Americas, South Korea, Taiwan and western Japan. A wrong value leaves the real hum in the signal and raises the false-positive rate; yazses biosignal monitor reports hum it sees. | |
emg | bool | true | Which detectors run. Muscle squeeze needs an EMG channel (forearm, jaw or face). | |
double_blink | bool | true | A deliberate double blink, read from a frontal EEG or an EOG channel. On because a single blink is involuntary (about 15 a minute), but two quick ones are a gesture almost no one makes by accident; still dormant until enabled and a source are set. | |
jaw_clench | bool | false | A deliberate jaw clench, read from a temporal/frontal channel. Off by default: chewing, talking and yawning all clench the jaw, so it is the likeliest to fire by mistake and should be turned on only after yazses biosignal replay/report show a low rate. | |
mode_map | dict | {'light': 'full_text', 'hard': 'command'} | Squeeze strength -> what the squeeze does, using the same two modes as [emg] mode: command or full_text. A light squeeze types what you say; a hard one speaks a command. Keys are strength labels: light, hard, and on (a detector that reports a squeeze without a strength). A strength left out is ignored, so removing hard leaves a single-strength switch rather than guessing a mode for it. | |
intent_map | dict | {'double_blink': 'undo'} | Discrete events -> a command phrase the command grammar knows (not free text), run through the [activation] confirmation gate. Undo by default for a double blink, because undo is the one action that is always safe to run by mistake. Events left out (jaw_clench by default) do nothing. | |
max_cancelled_per_hour | float | 6.0 | False-positive budget: how many activations you may cancel (undo) per hour. Past it the guard first DESENSITIZES the detectors (they become harder to trigger); if the cancelled rate stays above the budget it then SUSPENDS them and says so. A suspended switch comes back with one action from you (yazses handsfree resume) or when its timer ends -- it never re-enables itself while the rate is still too high. A cancelled activation is the only false positive the system can observe directly, so this is the measured guard. 0 = no budget: the rate is still counted, nothing is ever desensitized or suspended. | |
ledger_autosave_seconds | float | 60.0 | How often the session's activation counters (the data behind yazses biosignal report) are written to disk while the daemon runs, in seconds. The counters are also written on a clean stop; the periodic write exists so a crash or power loss costs at most this much of the false-positive record. | |
speech_guard | bool | true | Suppress the jaw-clench detector while you are speaking (a dictation turn is being recorded, plus a short hangover after it). On by default because talking moves the jaw and the masseter/temporalis EMG with it: without the guard ordinary speech is the most likely thing to read as a clench. Turn it off only to measure the unguarded rate (yazses biosignal report); it has no effect while jaw_clench is off. | |
calibration_file | str | "" | Path of the saved calibration profile (yazses biosignal calibrate); empty = the default file in the data directory. Thresholds come from your own signal, never a population average, which is why a switch without a profile stays conservative. | |
calibration_max_age_days | float | 30.0 | How old a saved calibration profile may be before the switches that depend on it (double blink, jaw clench) fall back to their conservative built-ins and say so. 30 days because skin impedance, electrode placement and fatigue drift over weeks, not hours: a month-old profile is usually still close, a quarter-old one is a guess. Recalibrating takes a minute (yazses biosignal calibrate). Bounds 1..365 days. | |
watchdog_seconds | float | 1.5 | Stuck-key watchdog: if no sample block arrives for this long while a squeeze is held (cable pulled, Bluetooth stall, board crash) the held dictation turn is released. 1.5 s because a healthy board delivers a block every few tens to ~250 ms, so a gap of six times the slowest is a dead stream rather than jitter, yet a microphone left open by a vanished device never stays open for long. Bounds 0.5..30 seconds. | |
min_event_confidence | float | 0.0 | Events whose confidence is below this are dropped before they become a switch press. 0.0 = accept whatever the detector reports (the detectors already apply the thresholds from your calibration); raise it to trade missed presses for fewer false ones. The false-positive guard (max_cancelled_per_hour) lifts the effective floor on its own when it desensitizes. Releasing a held squeeze is never gated by this. Bounds 0..1. |
[continuum]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
whisper_mode | bool | false | ||
whisper_threshold_factor | float | 0.4 | VAD threshold multiplier for quiet speech | |
semantic_capture | bool | false | ⚠️ inert | reuse LLM cleanup for meaning capture |
[bridge]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
listen_port | int | 9876 | ||
pair_token | str | "" | ⚠️ inert | shared secret the companion must present |
device_name | str | "" | last paired companion (informational) |
[translate]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
target | str | "en" | target language (whisper backend: English only) | |
backend | str | "whisper" | whisper (X→English) | seamless (opt-in) |
[affect]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
mode | str | "conservative" | ⚠️ inert | conservative | expressive |
min_confidence | float | 0.6 | ⚠️ inert |
[denoise]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "spectral" | spectral | deepfilternet | none | |
strength | float | 1.0 | graded suppression (higher = more aggressive) |
[predict]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
model_path | str | "" | local planner/completion GGUF; empty = disabled | |
max_tokens | int | 12 |
[voiceguard]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
match_threshold | float | 0.5 | min cosine similarity to the enrolled voiceprint | |
spoof_threshold | float | 0.5 | max spoof probability allowed | |
fail_open | bool | true | admit when a score is unavailable |
[scribe]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "sortformer" | sortformer | none | |
max_speakers | int | 6 |
[rag]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
top_k | int | 4 | ⚠️ inert | |
min_score | float | 0.2 | ⚠️ inert | |
embed_model | str | "embeddinggemma" | ⚠️ inert | embedding backend (lazy) |
store_path | str | "" | ⚠️ inert | sqlite-vec index; empty = disabled |
[codec]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
backend | str | "kyutai" | kyutai (Mimi) | none | |
max_delay_ms | int | 500 | ⚠️ inert |
[hallucination]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
drop_ghost_phrases | bool | true | ||
drop_loops | bool | true | ||
no_speech_threshold | float | 0.6 | ||
logprob_threshold | float | -1.0 | ||
compression_ratio_threshold | float | 2.4 |
[snippets]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
entries | dict | {} |
[phonetic]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_distance | float | 0.34 | ⚠️ inert | normalized phonetic-key distance to accept a fix |
[autostop]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
mode | str | "silence" | silence | semantic | |
silence_timeout_ms | int | 800 | ||
max_duration_ms | int | 30000 |
[mousegrid]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
cols | int | 3 | ||
rows | int | 3 |
[code]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[math]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[wakeword]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
keyword | str | "hey yaz" | ⚠️ inert | |
threshold | float | 0.5 | ||
cooldown_ms | int | 2000 |
[voicehealth]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.6 | mean strain over the window to advise a break | |
min_samples | int | 20 |
[coach]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[smartpaste]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[scrub]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[reflow]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[acoustic_profiles]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_stable | int | 3 | consecutive scene observations before switching |
[sentiment]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[pronunciation]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
good_threshold | float | 0.7 | ⚠️ inert | GOP >= this is "good" |
poor_threshold | float | 0.4 | GOP < this is "poor" (needs practice) |
[gesture]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
chords | dict | {} | "token+token" -> action; empty = nothing bound | |
chord_window_ms | int | 400 | tokens made within this window of the first count as one chord | |
refractory_ms | int | 1000 | after a chord, nothing fires until every token is released and this passes | |
freshness_ms | int | 500 | A sample older than this is "no signal"; unmeasured placeholder. Bounded like [headpointer] freshness_ms and [handsfree_safety] stale_after_ms: 0 would call every real sample stale (chords silently dead while Config reports a valid 0), and a huge value means "never stale". Outside (0, 60000] the loader repairs it to 500 and says so. | |
min_confidence | float | 0.5 | samples below this presence confidence are "no signal" | |
freeze_tail_ms | int | 300 | keep the pointer frozen this long after a chord token lets go | |
onset_rewind_ms | int | 150 | when the freeze lands a frame late, take back up to this much pointer motion since the expression began; 0 = never. Provisional | |
hold_ms | int | 800 | the hold token: tokens held unchanged this long. Provisional | |
head_amplitude_deg | float | 10.0 | Each leg of a nod/shake must swing at least this far. Bounded (0, 90]: 0 is "no gesture can ever be seen" and the detector would be silently dead. Provisional sanity bound, not measured. | |
head_swings | int | 4 | legs per nod/shake: 4 is a double nod, 2 a single down-up | |
head_window_ms | int | 1500 | a nod/shake must complete within this long | |
tilt_deg | float | 20.0 | Roll beyond this, either way, is a tilt. Bounded (0, 90]: at 0 a perfectly level head is "tilted" and the tilt token is held for ever (any chord using it fires with no movement at all); past 90 no head can reach it. Provisional sanity bound, not measured. | |
tilt_hold_ms | int | 400 | ...held this long |
[interpret]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
pair | str | "en-es" | language pair to interpret between |
[itn]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[redaction]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
mode | str | "mask" | mask | hold |
[fieldaware]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[compose]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
source | str | "" | ⚠️ inert | your spoken language (empty = autodetect) |
target | str | "en" | language to inject |
[gec]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[screengrounded]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_terms | int | 32 |
[headpointer]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
x_gain | float | -1200.0 | pointer units per second per radian of yaw; negative: left turn -> pointer left | |
y_gain | float | 900.0 | pointer units per second per radian of pitch; negative flips | |
max_speed_x | float | 800.0 | fastest horizontal pointer speed, units per second; provisional safety cap | |
max_speed_y | float | 600.0 | fastest vertical pointer speed, units per second; provisional safety cap | |
max_speed_overall | float | 800.0 | fastest combined pointer speed, units per second; provisional safety cap | |
deadzone | float | 0.02 | radians around the neutral pose that produce no motion | |
freshness_ms | int | 500 | a head pose older than this is "no signal"; unmeasured | |
min_confidence | float | 0.5 | samples below this presence confidence are "no signal" | |
dwell_enabled | bool | false | click by holding still; off so motion never clicks unasked | |
dwell_radius_px | float | 15.0 | stay within this many pointer units to count as holding still | |
dwell_ms | int | 700 | how long to hold still before the click, real time; provisional, unmeasured | |
dwell_hold_frames | int | 0 | legacy, replaced by dwell_ms: when above 0, that many frames at a nominal 30 fps |
[handsfree_safety]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | off until the hands-free preset and its consumers are wired | |
stale_after_ms | int | 500 | a signal older than this cannot act; unmeasured placeholder | |
stop_phrase | str | "" | Voice stop word: saying exactly this phrase (the WHOLE utterance, never a substring of dictation) pauses every hands-free input, like yazses handsfree pause. "" = off. It can only pause; there is no resume phrase (yazses handsfree resume, or Settings → Hands-free). 2-6 words, validated at load (handsfree/stopword.py). [handsfree] enabled supplies "pause hands free" -- a PROVISIONAL, unmeasured default -- unless you set this yourself. |
[handsfree]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | experimental preset: every value it sets is provisional, none validated with users | |
gaze | bool | true | Glance-Type: look at a window to target dictation and "close this" | |
pointer | bool | true | Head-Pointer: the head moves the cursor | |
dwell | bool | true | commit a click by holding the pointer still (needs [overlay] shown) | |
switch | bool | true | face switch: hold a jaw-open to dictate, no key | |
chords | bool | true | Gesture Chords: brow-raise + nod recenters, brow-raise + shake stops | |
voice_stop | bool | true | say "pause hands free" (the whole utterance) to pause every hands-free input |
[lipread]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
mouth_threshold | float | 0.35 | ⚠️ inert |
[sign]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
pause_frames | int | 8 | ⚠️ inert |
[convert]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[temporal]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[spreadsheet]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[cliphistory]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
capacity | int | 20 | ⚠️ inert |
[audioguard]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
cooldown_frames | int | 30 | ⚠️ inert |
[condense]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_sentences | int | 2 |
[slotfill]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[cmdspotter]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.75 |
[cmdsafety]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
confirm_words | list | [] | Phrases that release a held command / discard it. Empty falls back to the defaults in cmdsafety/spoken.py rather than disabling the words, because a held command with no release phrase cannot be run at all. | |
cancel_words | list | [] |
[spokenregex]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[markup]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
flavor | str | "markdown" |
[findreplace]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[hotwords]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
boost | float | 2.0 | ⚠️ inert | Retired with the N-best rescorer (biasing/trie.py), which had no producer. Read by nothing; kept so an existing config that sets it still loads. |
terms | list | [] | Extra terms to correct toward, on top of the yazses vocab dictionary. Only read while hotwords is active (enabled and opted_in). Words under four characters are never corrected. | |
opted_in | bool | false | The deliberate opt-in: yazses features enable hotwords and the Settings toggle write it next to enabled = true. Hotwords runs only when both are true, because older first-run setup wrote enabled = true into configs on its own. |
[windowctl]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[cite]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
bib_path | str | "" | ⚠️ inert | |
style | str | "latex" | ⚠️ inert |
[langroute]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_confidence | float | 0.5 | ⚠️ inert |
[latency]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
high_load | float | 85.0 | ||
low_load | float | 40.0 | ||
light_model | str | "tiny.en" | The model used while load is at or above high_load, with greedy decoding. It is loaded in the background the first time that happens and then stays resident alongside [stt] model — roughly 75 MB for tiny.en, and the reason this feature is off by default rather than free. |
[diarize]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[spelling]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[gitvoice]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ⚠️ inert |
[reask]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | -1.0 |
[verbatim]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[corrdict]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_support | int | 3 |
[fileopen]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.4 |
[jump]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[shellpipe]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[mcp]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
ask_human | bool | false | Offer ask_human at all. yazses mcp-server always offers transcribe. | |
ask_human_per_hour | int | 3 | Spoken questions allowed per rolling hour, shared across every caller — it protects the person, not each agent's fair share. 0 = never. | |
ask_human_end_silence_s | float | 1.2 | Seconds of quiet after you have started answering that end the answer, so a two-word reply frees the microphone in about a second instead of holding it for the agent's whole wait. Never below 0.3 s (a between-word pause). | |
ask_human_no_speech_s | float | 8.0 | Seconds to wait for you to start answering before returning no answer. 0 waits for the caller's whole timeout instead. |
[recimport]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
diarize | bool | false | attribute speakers; false = plain transcript | |
backend | str | "sherpa" | sherpa (default, ONNX/no torch) | pyannote (accuracy; needs the diarization-pyannote extra + a one-time gated HF model download) | none | |
max_speakers | int | 0 | EXACT count on sherpa, not a cap; 0 auto-detects | |
min_speakers | int | 0 | ||
cluster_threshold | float | 1.0 | sherpa fast-clustering threshold (auto-count mode) | |
output_format | str | "txt" | txt | md | srt | vtt | json | |
model | str | "" | "" => inherit the [stt] model | |
language | str | "en" | Whisper code ("en", "fa", …); "" auto-detects; "translate" renders any language into English | |
batched | bool | true | ⚠️ inert | BatchedInferencePipeline on long files |
name_from_voiceprints | bool | true | match enrolled voiceprints (needs enrollment) | |
min_speaker_seconds | float | 3.0 | min aggregated cluster speech to attempt naming | |
name_threshold | float | 0.5 | reject-biased cosine similarity to accept a name | |
model_dir | str | "" | "" => |
[meeting]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
output_dir | str | "" | "" => | |
retain_audio | bool | false | keep audio.wav after finalize (else deleted) | |
live_transcript | bool | true | stream a rolling transcript for meeting status | |
live_markdown | bool | true | append live-transcript.md during the meeting | |
diarize | bool | true | attribute speakers at stop | |
backend | str | "sherpa" | sherpa (default, ONNX/no torch) | pyannote (accuracy; needs the diarization-pyannote extra + a one-time gated HF model download) | none | |
max_speakers | int | 0 | EXACT count on sherpa, not a cap; 0 auto-detects | |
min_speakers | int | 0 | ||
cluster_threshold | float | 1.2 | sherpa fast-clustering threshold (auto-count mode) | |
model | str | "" | "" => inherit the [stt] model | |
language | str | "en" | Whisper code ("en", "fa", …); "" auto-detects; "translate" renders any language into English | |
vad_backend | str | "calibrated" | calibrated | silero -- silero needs the silero extra: ~3 GB (torch + CUDA) | |
silero_threshold | float | 0.5 | silero speech-probability gate (only read when vad_backend = "silero") | |
name_from_voiceprints | bool | true | match enrolled voiceprints (needs enrollment) | |
participants_dir | str | "" | "" => | |
min_speaker_seconds | float | 3.0 | min aggregated cluster speech to attempt naming | |
name_threshold | float | 0.5 | reject-biased cosine similarity to accept a name | |
model_dir | str | "" | "" => | |
output_format | str | "md" | md | txt | srt | vtt | json | |
max_minutes | int | 180 | auto-stop safety cap (0 = unlimited) | |
notes | bool | false | generate notes.md at stop (needs the notes extra) | |
notes_model | str | "" | path to a local GGUF; "" = dormant | |
notes_grammar | bool | true | constrain minutes JSON with a GBNF grammar (falls back to tolerant parse) | |
notes_window_turns | int | 40 | map-reduce window size (utterance turns, upper bound) | |
notes_max_tokens | int | 1024 | per-window generation cap | |
notes_ctx_tokens | int | 4096 | the GGUF context llama.cpp is opened with |
[crowdproof]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.5 |
[chords]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ⚠️ inert |
[compute]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[casetransform]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[autopair]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[timeline]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[bookmarks]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[tablecsv]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
delimiter | str | "," | ⚠️ inert |
[wordgoal]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
goal | int | 0 |
[voicetimer]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[focusprofile]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[vocaljoystick]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_speed | float | 20.0 | ||
click_pitch | float | 250.0 |
[earcon]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[spatialvad]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
target_angle | float | 0.0 | ⚠️ inert | |
tolerance_deg | float | 35.0 | ⚠️ inert | |
mic_distance_m | float | 0.14 | ⚠️ inert |
[prosodypunct]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
sentence_pause_ms | float | 700.0 | ||
comma_pause_ms | float | 250.0 |
[hesitation]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
commit_ms | float | 0.0 | ||
hold_extra_ms | float | 1200.0 |
[contour]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[breath]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
min_gap_s | float | 1.0 | ⚠️ inert | |
onset_threshold | float | 0.6 | ⚠️ inert |
[whispermode]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
voicing_max | float | 0.3 | ||
tilt_min | float | -1.0 | ||
gain_db | float | 6.0 | ||
vad_scale | float | 0.5 | ||
command_channel | bool | true |
[mouthswitch]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
dwell_s | float | 1.2 | Seconds per highlight step (clamped to 0.5-10 by mouthswitch/scanner.py). Where the scan is announced, it is the time left to click after the item's tick or name and the detector's deaf window behind it, so those steps run longer. | |
speak_names | bool | false | Where the overlay cannot draw the scan, say each item's name in the offline [tts] voice even with read-back off; your dictation is still not read back. Needs the tts extra and its voice model already on disk (never downloaded for this); without them the steps are announced with earcons only, and the log says why once. | |
scan_items | list | ['enter', 'undo', 'scroll up', 'scroll down', 'click'] | What the scan offers, in order. "click", "scroll up" and "scroll down" are pointer operations; anything else is a command phrase the command grammar must know and run without confirmation, or it is dropped (with a log line) when the daemon starts. |
[involuntary]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[morsevox]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
dot_max_ms | float | 200.0 | ||
letter_gap_ms | float | 600.0 | ||
word_gap_ms | float | 1400.0 | ||
entry_hum_s | float | 1.5 | Seconds of one steady, unbroken hum that enter Morse mode. 0 = only the spoken "morse mode" enters. | |
exit_silence_s | float | 3.0 | Seconds of silence that leave Morse mode. Raised above the word gap if set at or below it. |
[checkdigit]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
schemes | list | ['luhn', 'isbn13', 'isbn10'] | Which checksums to test, in order. luhn covers payment cards and many national IDs; isbn13/isbn10 books; verhoeff several government schemes (e.g. Aadhaar). | |
min_digits | int | 12 | Shortest run of digits worth checking. Below this, false positives dominate — a 4-digit year or a house number is not a card number, and Luhn will happily reject it. | |
suggest_fix | bool | true | Offer the single-digit correction when exactly one candidate passes. More than one candidate means the suggestion would be a guess between them, so none is offered. |
[sembr]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_len | int | 0 | ⚠️ inert |
[acronyms]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[styleguard]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
path | str | "style-rules.toml" | relative to config dir, or absolute |
[suggestmode]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[screenplay]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[srscap]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[diagramvox]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
flavor | str | "mermaid" |
[proofback]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[hatselect]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[translit]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
scheme | str | "finglish" |
[brailleout]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
grade | int | 2 | ⚠️ inert |
[outline]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
format | str | "markdown" | ⚠️ inert |
[diacritize]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[safeglyph]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[wordfind]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
max_candidates | int | 5 | ⚠️ inert |
[loadguard]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
threshold | float | 0.7 |
[echo]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false |
[srpace]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
enabled | bool | false | ||
wpm | float | 180.0 |
[profiles]¶
| Key | Type | Default | Status | Notes |
|---|---|---|---|---|
app | dict | {} |