Skip to content

voxtype: Configuration & CLI

Configuration lives at ~/.config/voxtype/config.toml (voxtype also reads a legacy ~/.config/voice-type/config.toml if it exists and the voxtype one doesn’t — a carryover from when the tool shipped as voice-type).

You rarely need CLI flags. Every runtime flag is just an override of a config key (the exceptions are --config, which points at a different file, and the setup/init --force flag), so the intended workflow is: put your preferences in the config once, then your daily command is plain voxtype — flags exist for one-off experiments (e.g. trying another engine) and always win over the file.

Any config key can be set for one run with --set KEY=VALUE, exactly as if that line were in the file. The key may use hyphens or underscores, and --set can be repeated:

Terminal window
voxtype --set post-process=true --set post-process-provider=s1-mini
voxtype --set sounds=false --set submit-phrases="go, send it"
voxtype post-process --set post-process-format=minimal "so um hi"

Values are read as the key’s type: true/false (also yes/no, on/off, 1/0), numbers, plain strings, and lists as comma-separated items or a TOML array such as ["go", "send it"]. KEY= gives an empty string or empty list. If a dedicated flag such as --engine sets the same key, that flag wins.

Two ways to create that file:

Terminal window
voxtype setup # interactive walkthrough — asks, then writes
voxtype init # write a fully commented sample to edit by hand
voxtype init --force # overwrite an existing sample

voxtype setup is the quickest start: it asks a short series of explained questions (engine, mode, segmentation, hotkey, wake word, and optional extras), validates your choices, and writes a ready-to-use config — you can record the hotkey live during the walkthrough. init instead drops a fully commented sample (like the reference below) for hand-editing.

Three settings combine to define how voxtype behaves, and they answer different questions:

  • mode — when is it listening? toggle: only between two presses of the hotkey. wake: always passively listening for the wake word (hotkey works as an override). vad: dictating from the moment it starts.
  • segmentation — when does text appear? See “When does the text appear?” below — this is the axis people mean when they ask about “streaming” dictation. (Mostly independent, with one tie: hold needs a parakeet engine in toggle mode; otherwise voxtype uses vad.)
  • engine — what transcribes it? Pure speed/accuracy/platform trade-off; see the engine table below. Any engine works with any mode.

Dictation tools differ in how immediately the transcript shows up. The spectrum, from most to least immediate:

  1. Word-by-word streaming (Apple-dictation style: words materialize and self-correct as you speak). voxtype deliberately does not do this into your apps: revising already-typed text in another application means blindly sending backspaces into whatever has focus — one desync and your document is mangled. Typed text should be final.
  2. Per-pause typing — segmentation = "vad". Speak; roughly half a second after each natural pause, that utterance is typed. This is the closest voxtype comes to a streaming feel: text flows in sentence-sized pieces while you keep talking. Trade-off: the model transcribes each fragment with only that fragment’s context, so accuracy is a notch lower.
  3. Whole-take — segmentation = "hold". Nothing appears while you speak (the ghost indicator is your feedback); on toggle-off the entire take is transcribed as one segment and typed in one go. Maximum accuracy — the model sees full sentence context — and most apps undo it as a single edit (keystrokes are synthesized, so undo grouping is up to the focused app). Requires toggle mode, since the wake word can only be heard by continuous per-utterance transcription.

Wake and vad modes always use per-pause typing (2); toggle mode lets you pick between (2) and (3), and defaults to (3), whole-take, with a parakeet engine — so out of the box you get maximum-accuracy push-to-talk. Set segmentation = "vad" if you’d rather see text appear as you pause.

Push-to-talk dictation (the default, and the recommended daily driver). No wake word involved at all; maximum accuracy; text lands in one go (a single edit to undo, in most apps). This is exactly what you get out of the box — no config needed — since mode defaults to toggle, the engine is auto-selected (a parakeet engine), and segmentation then defaults to hold. Spelled out, that is:

mode = "toggle"
segmentation = "hold"
# engine is auto-selected: parakeet-mlx on Apple Silicon,
# parakeet on Intel — you normally leave it unset

Toggle with live feedback. Same hotkey workflow, but text appears at every pause instead of at the end — useful when you want to see progress while dictating something long, at some cost in accuracy:

mode = "toggle"
segmentation = "vad"

Hands-free with a wake word. Say “hey claude …” to dictate, “stop listening” (or silence) to re-arm; the hotkey still toggles manually. Per-pause typing is inherent to this mode:

mode = "wake"
wake_word_aliases = ["hey cloud"] # add what the model mishears

Always-on transcription. Types everything it hears while running — for captioning yourself or short bursts of use:

mode = "vad"

(These recipes leave engine unset so it auto-selects for your machine; set it explicitly only to force a specific engine.)

Selected with engine / --engine. All run 100% on-device.

EngineRuns onSpeed*Notes
parakeet-mlxApple GPU (MLX)~40x realtimeDefault on Apple Silicon. fp16 Parakeet-TDT v3: best accuracy and speed. Weights from HuggingFace on first run.
parakeetCPU (sherpa-onnx)~32x realtimeDefault on other machines. int8 Parakeet-TDT v3 (or fp16 v2 via parakeet_model); ~490 MB download.
moonshineCPU (ONNX)streamingMoonshine streaming models; smallest footprint. Opt-in: uv tool install "voxtype[moonshine]" (no Intel-macOS build).

Both parakeet engines ship with the base install; the default is chosen for your machine, so most people never set engine at all.

*measured on an M-series Mac; see parakeet_threads for CPU tuning.

# ~/.config/voxtype/config.toml — all keys optional; the values shown
# are the defaults (except `engine`, which is auto-selected per machine)
# Activation: "toggle" (hotkey), "vad" (hands-free), "wake" (wake word)
mode = "toggle"
# Engine: "parakeet-mlx" | "parakeet" | "moonshine". Auto-selected when
# unset: parakeet-mlx on Apple Silicon, parakeet on Intel. Set it only to
# force a choice; the value below is just the Apple-Silicon case.
engine = "parakeet-mlx"
# "vad" types each utterance when you pause; "hold" records everything
# between toggle-on/off and transcribes the whole take at once (parakeet
# engines + toggle mode only). Default: "hold" with a parakeet engine in
# toggle mode (the common case), otherwise "vad".
segmentation = "hold"
# parakeet (CPU) build: "v3-int8" | "v2-fp16"; and decode threads
parakeet_model = "v3-int8"
parakeet_threads = 4
# parakeet-mlx model (HuggingFace id)
mlx_model = "mlx-community/parakeet-tdt-0.6b-v3"
# moonshine model: tiny | base | tiny-streaming | base-streaming |
# small-streaming | medium-streaming
model_arch = "medium-streaming"
language = "en"
# Hotkeys (pynput or bracket-less syntax; `voxtype hotkey` records one)
hotkey = "<ctrl>+;" # toggle recording
# A second toggle for the laptop keyboard (macOS): tap a modifier key
# twice on its own. One of left_alt right_alt left_cmd right_cmd
# left_ctrl right_ctrl left_shift right_shift ("alt" = Option). The key
# keeps working as a normal modifier. "" disables.
double_tap_key = ""
double_tap_ms = 400 # max gap between the two taps, press to press
cancel_hotkey = "<esc>" # cancel recording (only intercepted WHILE recording)
paste_hotkey = "" # re-type last transcript, e.g. "<cmd>+<ctrl>+v"
# Wake mode
wake_word = "claude"
wake_word_aliases = [] # misspellings the model produces, e.g. ["hey cloud"]
stop_phrase = "stop listening"
idle_timeout = 20.0 # seconds of silence before wake mode re-arms
# Spoken submit: saying one of these as an ENTIRE utterance presses Enter
submit_phrases = ["over", "go", "submit"]
# Transcript cleanup: strip standalone fillers (uh, um, ...) and
# collapse 3+ word stutters ("I I I think" -> "I think")
strip_fillers = true
# Optional LLM cleanup, off by default — see "Post-processing" below
post_process = false
post_process_provider = "s1-mini" # s1-mini (local) | cerebras (external API)
post_process_format = "auto" # cerebras: auto | paragraphs | minimal
post_process_newlines = "auto" # line breaks: auto | shift_enter | flatten
post_process_log_text = true # log each take's before/after text
post_process_cerebras_model = "gpt-oss-120b"
post_process_style = "semi-formal" # casual | semi-casual | semi-formal | formal
post_process_structure = "prose" # prose | lists
post_process_context = "general" # general | email
post_process_timeout = 0.0 # seconds before raw; 0 = 4 (s1-mini) / 2 (cerebras)
post_process_model = "" # local .gguf path; "" = pinned S1-mini download
post_process_server = "llama-server" # llama.cpp server binary (name or path)
trailing_space = true # append a space after each typed utterance
# Toggle chimes. sounds = false silences the start/stop chime entirely
# (or run with --no-sounds). Names are system sounds
# (/System/Library/Sounds) or file paths.
sounds = true # false = no chime when recording toggles on/off
sound_start = "Glass"
sound_stop = "Bottle"
# Keep each session's text on the clipboard too
copy_to_clipboard = false
# Floating ghost indicator while recording (macOS): a little blue
# ghost whose mouth opens with your voice.
overlay = true
overlay_flex = 1.0 # how much the face flexes its shape (higher = more)
overlay_speed = 1.0 # animation speed (lower = slower/gentler)
overlay_opacity = 1.0 # 0.1–1.0; lower it if the ghost hides text under it
# Keep the model's memory warm (parakeet-mlx only). After this many
# minutes without a decode, voxtype quietly decodes a short silent
# clip so the idle model stays recently-used and macOS is far less
# likely to evict it to swap — otherwise, on a memory-pressured
# machine, the first take after a long pause can stall for seconds
# paging the model back in. Keeps ~1.7 GB in active use. 0 disables;
# max 1440 (a day). See the note below on the one trade-off. Also keeps
# the post-processing model warm when post_process is on.
keepalive_minutes = 0.0

Turn this on if your Mac runs under heavy memory pressure and your first take after a pause is sometimes slow — several seconds for a few seconds of audio, when a normal take is near-instant. That slowness is macOS having evicted the idle model (~1.7 GB) to swap; the periodic silent decode keeps those pages in active use so it is far less likely to happen. A value of 5 (minutes) is a reasonable start. On a machine with memory to spare, leave it off — it is not free, it keeps ~1.7 GB resident.

One trade-off worth knowing:

  • The keepalive decode runs on the same thread that reads the microphone, so while it runs, capture pauses. It skips itself during a take, during an utterance, and for 30 seconds after any hotkey press, so it should never collide with you speaking — but if you happen to press the hotkey in the instant it starts, the first fraction of a second of your dictation can be lost.
  • In practice that window is ~0.2 s, because a keepalive on a warm model is fast, and keeping the model warm is the whole point. A multi-second keepalive means the model had already been evicted, which is the situation this option prevents.

Optionally, voxtype can pass each transcript through a language model before typing it, to clean it up. Pick one of three setups in ~/.config/voxtype/config.toml:

You wantPut in your configAlso needed
No cleanup (the default)nothingnothing
Local cleanup (on-device, English only)post_process = truebrew install llama.cpp (details)
Cerebras cleanup (also paragraphs and lists; sends transcripts to Cerebras)post_process = true
post_process_provider = "cerebras"
CEREBRAS_API_KEY in ~/.config/voxtype/.env (details)

With no cleanup, plain voxtype types Parakeet’s transcript exactly as it always has, after the regex filler removal. With either kind of cleanup, any failure or timeout types the raw transcript, so a take is never lost. To turn cleanup off again, delete post_process = true or set it to false.

The local model adds punctuation and capitals, drops self-corrections, and removes verbal clutter like “you know”. These are real takes from this Mac:

Parakeet heardvoxtype typed
it does not handle missing keys, I mean optional keys, and then it crashesIt does not handle optional keys, and then it crashes.
Let’s meet on Tuesday, no wait Wednesday at three.Let’s meet on Wednesday at 3.
First install Voxtype second run Voxtype setup third grant the permissionsFirst, install Voxtype. Second, run Voxtype setup. Third, grant the permissions.
which is like kind of surprising you know.which is kind of surprising.

The model is “S1-mini” by “Superwhisper”, a 0.6B-parameter fine-tune of Qwen3 trained for exactly this job. It is Apache-2.0 licensed, with one added condition: anything that uses it must keep calling it “S1-mini” by “Superwhisper”. It handles English only. Everything runs on your Mac; nothing leaves the machine.

  1. Install llama.cpp, which provides the llama-server that runs the model. voxtype adds no Python dependencies for this, so the base install stays as light as before.

    Terminal window
    brew install llama.cpp
  2. Download the model and try it once. The model is a single 462 MiB file, pinned to a fixed revision and checked against its sha256, and stored in ~/.cache/voxtype/models/.

    Terminal window
    voxtype post-process "so um I think we should uh move it to Tuesday no wait Wednesday"

    This prints the cleaned text and how long it took. Pass --style formal (or any other style) to compare styles.

  3. Turn it on in ~/.config/voxtype/config.toml, or answer yes to the question in voxtype setup:

    post_process = true
KeyDefaultWhat it does
post_processfalseTurn LLM cleanup on.
post_process_style"semi-formal"casual (lowercase, little punctuation), semi-casual, semi-formal (sentences, capitals, full stops), or formal (also expands contractions).
post_process_structure"prose"lists numbers “first…, second…” items.
post_process_context"general"email formats the text as an email.
post_process_provider"s1-mini"s1-mini (local) or cerebras (external API; see below).
post_process_newlines"auto"How line breaks in cleaned text are typed: shift_enter, flatten (one line), or auto (Shift+Enter for cerebras, flatten for s1-mini). See below.
post_process_log_texttrueLog each take’s full before/after text. false logs timings only.
post_process_timeout0.0Seconds a take may spend in cleanup before voxtype types it raw (0.5–60). 0 means the provider default: 4 s for s1-mini, 2 s for cerebras.
post_process_model""Path to your own .gguf file. Empty means the pinned S1-mini download.
post_process_server"llama-server"Name or full path of the llama.cpp server binary.

The style, structure and context values are the only ones the model was trained on, so voxtype rejects anything else.

voxtype never types a bare Enter in the middle of a take, because that would send a chat prompt or run a shell command partway through. With post_process_newlines = "shift_enter", each line break in cleaned text (list items, paragraphs) is typed as Shift+Enter, which inserts a new line without sending in Claude Code, Codex, Slack, most chat boxes and editors. The default, "auto", does that for the cerebras provider and types s1-mini’s output on one line, as s1-mini always has.

Measured on an M1 Max with real Parakeet takes:

  • Latency. Cleanup adds about 150 ms at the median and about 550 ms at the 95th percentile, after the server is warm. A short take of 20 words or fewer costs under 300 ms. A 60-word take costs about 0.6 s. A take longer than 250 words is split at sentence boundaries, and each piece is cleaned in turn.
  • Memory. The server’s resident size is about 830 MB, but only about 300 MB of that is its own (dirty) memory. The other ~470 MB is the model file mapped from disk with no dirty pages: under memory pressure macOS simply drops those pages and rereads them later, without writing anything to swap. voxtype never locks the model into RAM (--mlock) and keeps the context small (2048 tokens, one request at a time). If memory pressure makes the first take after a pause slow, keepalive_minutes keeps this model warm too.
  • Startup. voxtype starts the server in the background at launch, which takes about 5–15 seconds. Takes that arrive before it is ready are typed raw, with a one-line notice.

Cleanup can only change the text that gets typed. It can never lose a take. voxtype types the raw transcript, exactly as it would with cleanup off, when any of the following happens:

  • llama-server is missing, failed to start, or crashed. voxtype retries starting it at most once a minute.
  • The take exceeds post_process_timeout.
  • The model returns empty output, truncated output, or output that looks like a chat reply rather than a transcript.
  • The output is much longer than the input, or lost most of it.
  • The transcript looks non-English. Either most of its letters are non-ASCII (Cyrillic, Greek or Chinese, for example), or, in a take of four or more words, at least a quarter are common words of a single one of these languages, and they outnumber the English ones: Spanish, French, German, Italian, Portuguese, Dutch or Indonesian. Other mostly-ASCII languages (Polish or Romanian, for example) are not reliably detected, so use cleanup only for English dictation.

The terminal shows post-processed in N ms, or post-process fell back to raw (reason), for every take. Each take also gets a latency: line; see Reading the logs.

Spoken commands are matched on the raw transcript, before cleanup. That covers the submit phrases (“go”), the stop phrase and the wake word, so cleanup cannot break them. Filler-word removal (strip_fillers) also still runs first. Esc behaves as it does without cleanup: it discards the recording in progress, but text already transcribed and waiting for cleanup is still typed.

The server never outlives voxtype. It runs under a tiny supervisor process (about 20 MB) that stops it as soon as voxtype exits for any reason, including a crash, a closed terminal, or kill -9. As a backstop, each voxtype process records its server in ~/.cache/voxtype/run/, and the next launch stops any server left behind by a voxtype process that has died. It never touches the server of a voxtype process that is still running. A server that fails to start leaves its log in that same directory.

post_process_provider = "cerebras" sends each transcript to Cerebras and runs it through gpt-oss-120b. Besides cleanup, it splits long, rambling dictations into paragraphs at topic changes and turns spoken enumerations into plain-text lists, while keeping technical terms, file names, commands and URLs as dictated. Short utterances stay short.

Enable it. Put your API key from cloud.cerebras.ai in voxtype’s own key file, ~/.config/voxtype/.env. Don’t put it in your shell profile (where every program you run can read it) or in config.toml. The file holds a single line:

Terminal window
CEREBRAS_API_KEY=your-key-here

Create it with your editor, then make it readable only by you:

Terminal window
chmod 600 ~/.config/voxtype/.env

Then add these lines to ~/.config/voxtype/config.toml:

post_process = true
post_process_provider = "cerebras"

Now plain voxtype uses Cerebras. To disable it, set post_process = false, or switch the provider back to s1-mini.

voxtype looks for the key in this order and never logs it:

  1. A CEREBRAS_API_KEY environment variable, for example one set by a secrets manager.
  2. ~/.config/voxtype/.env.
  3. ~/.config/voice-type/.env, if your config is still at that legacy location. A config given with --config doesn’t change where voxtype looks for the key.

If the key file is readable by other users, voxtype warns you to chmod 600 it. If no key is found, it says so once at launch and types raw transcripts.

Try it once without starting dictation:

Terminal window
voxtype post-process --provider cerebras "um so lets do it Friday no sorry Thursday"
KeyDefaultWhat it does
post_process_provider"s1-mini"cerebras selects this provider.
post_process_format"auto"auto: paragraphs and lists when appropriate. paragraphs: paragraph breaks, but enumerations stay prose. minimal: fix punctuation and disfluencies only, with no added structure; the output is always one line.
post_process_cerebras_model"gpt-oss-120b"The Cerebras model id.
post_process_timeout0.00 means 2 s for this provider. A take that takes longer is typed raw.
post_process_newlines"auto"auto types Shift+Enter for this provider; paragraphs and lists need it. See Line breaks.
post_process_log_texttrueLog the before/after text of each take.

The format is passed to the model through its prompt. The transcript is sent as delimited data, and the prompt tells the model never to follow instructions inside it. A dictated request stays a request: say “write an email to John saying the meeting moved” and that sentence is typed, not an email. voxtype keeps one HTTPS connection open to save the TLS handshake on each take. Every failure (no key, HTTP error, timeout, empty or malformed reply, truncated output, or output that lost most of the input) types the raw transcript, and the reason is logged.

With post-processing on, every take logs one line with timings only, never transcript text or the key. For example (illustrative numbers):

[voxtype] post-process (cerebras): 412 ms
[voxtype] latency: transcribe 966 ms, post-process 412 ms (cerebras, ok), total 1398 ms (speech end to inserted)
  • transcribe runs from your toggle-off to Parakeet’s transcript. It appears in hold mode only; with VAD segmentation the engine’s transcribed N s of audio in M s line covers it.
  • post-process is the cleanup call, including the network round trip. The parenthesis shows ok, or fallback: <reason> such as HTTP 402 payment_required or timed out.
  • total runs from the end of your speech to the text being typed. With VAD segmentation it starts when the transcript arrives instead. If you start and stop a new take before the previous one has finished transcribing, that earlier take is timed from the latest toggle-off, so its numbers read low.

The latency and fallback lines never contain your words. The before/after lines (before: "…", after: "…") contain each take’s full text; set post_process_log_text = false to turn them off. voxtype’s usual one-line previews (typed: "…") still show the start of each take, as they always have.

On an M1 Max, using say-synthesized takes of 64–76 seconds (182–238 words: several requirements, a correction, a topic change, file names, commands and URLs) through Parakeet, voxtype’s real delivery path and the live Cerebras API, with gpt-oss-120b in auto format:

StageMedian95th percentile
Transcription (Parakeet)1.0 s1.2 s
Cerebras cleanup, including network0.39 s1.5 s
Total, end of speech to text typed1.4 s2.5 s

The table is from the final run: 12 takes, spaced 3 s apart, all cleaned. Across all spaced runs, Cerebras usually answered in 0.2–0.5 s but had a long tail. About 1 take in 10 took more than 2 s: with the default post_process_timeout it timed out and was typed raw. The slowest call took 4.2 s. Takes sent back-to-back sometimes got HTTP 429 queue_exceeded from Cerebras; those were typed raw within about 70 ms.

Example (one 64-second take), Parakeet’s transcript:

Okay, so um, for the new dashboard, we need a few things first a login page with OAuth second or settings page, where users can change their email address and their notification preferences, and third an export button that dumps everything to CSV, and maybe also JSON if it is easy. Oh, and the deadline for all of this is Friday, no sorry, Thursday. … And then the last thing is the onboarding email. It is way too long, and honestly, nobody reads it, so we should make it shorter and friendlier.

What voxtype typed (line breaks typed as Shift+Enter):

Okay, so for the new dashboard we need a few things:
- A login page with OAuth. I want the login page done first because the other two depend on it.
- A settings page where users can change their email address and their notification preferences.
- An export button that dumps everything to CSV, and maybe also JSON if it is easy.
- The deadline for all of this is Thursday.
…
Finally, the onboarding email is way too long and nobody reads it. We should make it shorter and friendlier, …

The live tests (pytest tests/test_voxtype_cerebras.py, with CEREBRAS_API_KEY set) check filler removal, self-corrections, paragraphs and lists, short utterances, exact technical terms and URLs, ignored instructions, dictated requests typed rather than carried out, and all three formats. All of them pass.

Limitations.

  • Transcripts leave your Mac.
  • The model mostly restructures faithfully, but it sometimes drops a short aside or an emphasis word (“we really need to move fast”, “honestly”). It also occasionally nests a list or rewords a phrase. It does not fix words Parakeet misheard (“pydesk” for pytest).
  • Latency has a long tail, so about 1 long take in 10 exceeds the 2 s default timeout and is typed raw. Raise post_process_timeout (for example to 4) if you’d rather wait than lose the cleanup.
  • Dictating several takes in quick succession can hit Cerebras’s request-queue limit (HTTP 429); those takes are typed raw.
  • Shift+Enter is unsafe in plain shells (see above).
  • Corporate HTTP proxies are not used; voxtype connects to api.cerebras.ai directly.
  • Formatting is decided by the model, so it can occasionally add structure you didn’t intend. minimal avoids that.
voxtype [flags] run with config + flag overrides
voxtype --set KEY=VALUE ... set any config key for this run (repeatable)
voxtype setup [--config PATH] [--force] interactive walkthrough -> writes config
voxtype init [--config PATH] [--force] write the commented sample config to edit
voxtype hotkey press a chord; prints the config line
voxtype skill install the voxtype skill into Claude + Codex
voxtype post-process [TEXT] [--provider P] [--format F] [--style S] [--set KEY=VALUE]
clean TEXT (or stdin) once
voxtype --version print the installed version
voxtype --help full flag reference (per-subcommand: e.g. voxtype setup --help)

Flags mirror the config keys: --mode, --engine, --segmentation, --parakeet-model, --model-arch, --language, --hotkey, --wake-word, --stop-phrase, --no-sounds, --no-overlay, --config PATH. Every other key, and these too, can be set with --set KEY=VALUE (see the top of this page).

double_tap_key adds a second way to start and stop recording, next to the hotkey chord: tap one modifier key twice, by itself. It exists for the laptop keyboard, where a chord like Ctrl+; is awkward without an external keyboard; right_alt (the right Option key) is a good choice because nothing else uses it alone.

  • Both triggers stay active at once; use whichever is under your hand.
  • The taps must be clean: press, release, press, release, with no other key in between and within double_tap_ms of each other (press to press). Holding the key to type an Option-shortcut or an accented character never triggers it.
  • The modifier is never swallowed — voxtype only observes it — so Option, Command, and friends keep working everywhere.
  • macOS only (it rides on the same event tap as the chord).

Both spellings work everywhere a chord is accepted:

hotkey = "<ctrl>+;" # pynput style
hotkey = "ctrl+;" # bracket-less
hotkey = "cmd+shift+f5" # named keys too

Easiest of all: run voxtype hotkey, press the combo you want, and paste the printed line into your config. On macOS matched chords are fully suppressed — the focused app never sees them — and context-dependent keys like Esc are only intercepted while recording.

Grant these to your terminal app (System Settings → Privacy & Security), once each:

  • Microphone — to hear you
  • Accessibility — to type into other apps
  • Input Monitoring — for the global hotkeys
  • Every utterance’s fate is logged to the terminal (typed: ..., heard (awaiting wake word): ..., dropped, decoded to empty text) — nothing is discarded silently. Read these lines first.
  • Wake word not firing? Check the heard lines for how the model actually spelled it and add that to wake_word_aliases; prefer a two-word phrase (“hey claude”) over a bare word.
  • Quiet dynamic mic (Shure MV7 class)? Automatic gain control is built in; if speech still isn’t detected, move closer to the mic.
  • take was silent (...): microphone muted, held by another app, or its stream went stale — reopening the microphone? voxtype measured no signal at all during that take (a dead mic reads about a millionth of full scale; even a quiet room reads a thousand times more). Two known causes: a meeting app (Zoom) left the mic muted at the system level — unmute there, or tap the mic’s own mute button — or the audio stream went stale after the device setup changed (opening the lid, plugging in a mic). voxtype reopens the stream on its own, so the stale case fixes itself: just dictate again. Hold mode only; in wake/vad mode a dead mic simply never hears anything.
  • Dictated into the wrong window? Set paste_hotkey and re-type the last session anywhere.