Skip to content

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 "" "" => /diarization

[meeting]

Key Type Default Status Notes
enabled bool false
output_dir str "" "" => /meetings
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 "" "" => /participants (enrolled speakers)
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 "" "" => /diarization
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 {}