bolotype 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. bolotype-0.1.0/LICENSE +21 -0
  2. bolotype-0.1.0/PKG-INFO +351 -0
  3. bolotype-0.1.0/README.md +297 -0
  4. bolotype-0.1.0/pyproject.toml +98 -0
  5. bolotype-0.1.0/setup.cfg +4 -0
  6. bolotype-0.1.0/src/bolotype/__init__.py +1 -0
  7. bolotype-0.1.0/src/bolotype/__main__.py +3 -0
  8. bolotype-0.1.0/src/bolotype/accessibility/__init__.py +0 -0
  9. bolotype-0.1.0/src/bolotype/accessibility/linux_atspi.py +597 -0
  10. bolotype-0.1.0/src/bolotype/asr/__init__.py +0 -0
  11. bolotype-0.1.0/src/bolotype/asr/base.py +18 -0
  12. bolotype-0.1.0/src/bolotype/asr/moonshine_asr.py +54 -0
  13. bolotype-0.1.0/src/bolotype/asr/nemotron_asr.py +328 -0
  14. bolotype-0.1.0/src/bolotype/cli.py +128 -0
  15. bolotype-0.1.0/src/bolotype/config.py +204 -0
  16. bolotype-0.1.0/src/bolotype/control.py +47 -0
  17. bolotype-0.1.0/src/bolotype/daemon.py +366 -0
  18. bolotype-0.1.0/src/bolotype/editor.py +121 -0
  19. bolotype-0.1.0/src/bolotype/input/__init__.py +0 -0
  20. bolotype-0.1.0/src/bolotype/input/linux.py +139 -0
  21. bolotype-0.1.0/src/bolotype/installer.py +137 -0
  22. bolotype-0.1.0/src/bolotype/llm.py +140 -0
  23. bolotype-0.1.0/src/bolotype/resources/default_settings.json +26 -0
  24. bolotype-0.1.0/src/bolotype/resources/default_system_prompt.txt +18 -0
  25. bolotype-0.1.0/src/bolotype.egg-info/PKG-INFO +351 -0
  26. bolotype-0.1.0/src/bolotype.egg-info/SOURCES.txt +28 -0
  27. bolotype-0.1.0/src/bolotype.egg-info/dependency_links.txt +1 -0
  28. bolotype-0.1.0/src/bolotype.egg-info/entry_points.txt +2 -0
  29. bolotype-0.1.0/src/bolotype.egg-info/requires.txt +34 -0
  30. bolotype-0.1.0/src/bolotype.egg-info/top_level.txt +1 -0
bolotype-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abdullah Baig
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,351 @@
1
+ Metadata-Version: 2.4
2
+ Name: bolotype
3
+ Version: 0.1.0
4
+ Summary: System-wide local voice typing with AI-powered editing
5
+ Author: Muhammad Abdullah Baig
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/baig97/bolotype
8
+ Project-URL: Repository, https://github.com/baig97/bolotype
9
+ Project-URL: Issues, https://github.com/baig97/bolotype/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: openai>=1.0
24
+ Requires-Dist: platformdirs>=4.0
25
+ Provides-Extra: moonshine
26
+ Requires-Dist: moonshine-voice; extra == "moonshine"
27
+ Provides-Extra: nemotron
28
+ Requires-Dist: transformers>=4.47; extra == "nemotron"
29
+ Requires-Dist: torch>=2.0; extra == "nemotron"
30
+ Requires-Dist: accelerate>=1.14; extra == "nemotron"
31
+ Requires-Dist: sounddevice>=0.4; extra == "nemotron"
32
+ Requires-Dist: librosa; extra == "nemotron"
33
+ Requires-Dist: Pillow>=9.1; extra == "nemotron"
34
+ Requires-Dist: numpy<2,>=1.26; extra == "nemotron"
35
+ Requires-Dist: scipy<1.16,>=1.11; extra == "nemotron"
36
+ Requires-Dist: scikit-learn>=1.4; extra == "nemotron"
37
+ Provides-Extra: all
38
+ Requires-Dist: moonshine-voice; extra == "all"
39
+ Requires-Dist: transformers>=4.47; extra == "all"
40
+ Requires-Dist: torch>=2.0; extra == "all"
41
+ Requires-Dist: accelerate>=1.14; extra == "all"
42
+ Requires-Dist: sounddevice>=0.4; extra == "all"
43
+ Requires-Dist: librosa; extra == "all"
44
+ Requires-Dist: Pillow>=9.1; extra == "all"
45
+ Requires-Dist: numpy<2,>=1.26; extra == "all"
46
+ Requires-Dist: scipy<1.16,>=1.11; extra == "all"
47
+ Requires-Dist: scikit-learn>=1.4; extra == "all"
48
+ Provides-Extra: dev
49
+ Requires-Dist: build; extra == "dev"
50
+ Requires-Dist: twine; extra == "dev"
51
+ Requires-Dist: pytest; extra == "dev"
52
+ Requires-Dist: ruff; extra == "dev"
53
+ Dynamic: license-file
54
+
55
+ # BoloType — Type at the speed of sound. Refine with LLMs of your choice.
56
+
57
+ > System-wide voice typing with instant dictation and AI-powered editing.
58
+
59
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
60
+
61
+ > **Platform support:** Linux only. Windows and macOS support is coming soon.
62
+
63
+ ---
64
+
65
+ ## Features
66
+
67
+ - **Instant dictation** — speech inserts at the cursor as soon as a phrase completes. No push-to-talk, no button to hold.
68
+ - **Bring your own LLM** — connect any OpenAI-compatible endpoint: llama.cpp, LMDeploy, vLLM, Ollama, OpenAI, Groq, and more. One setting to change.
69
+ - **Fully local by default** — audio never leaves your machine. LLM calls go only to the endpoint you configure. Nothing is sent anywhere unless you choose a cloud endpoint.
70
+ - **Private and safe** — no cloud account required, no telemetry, no data collection of any kind.
71
+ - **Voice polish commands** — say *"polish this paragraph"* and the LLM rewrites that span in place. Works on a line, paragraph, selection, or the entire field.
72
+ - **Precise undo** — *"undo that"* restores the exact pre-polish text, not a generic Ctrl+Z that may affect unrelated changes.
73
+ - **Two ASR engines** — [Moonshine](https://github.com/usefulsensors/moonshine) is fast, low-latency, and works on CPU. [Nemotron 3.5](https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b) offers higher accuracy and requires a CUDA GPU.
74
+ - **System-wide** — works in any text field reachable via AT-SPI2: GTK apps, browsers, Electron apps, terminals, and more.
75
+
76
+ ---
77
+
78
+ ## Quickstart
79
+
80
+ > Requires Ubuntu/Debian with a CUDA or CPU setup. Moonshine engine used below.
81
+
82
+ ```bash
83
+ git clone https://github.com/baig97/bolotype.git
84
+ cd bolotype
85
+
86
+ python3 -m venv --system-site-packages .venv
87
+ source .venv/bin/activate
88
+
89
+ pip install --upgrade pip setuptools wheel
90
+ pip install -e .
91
+ bolotype install moonshine
92
+ ```
93
+
94
+ Edit `~/.bolotype/settings.json` and set your LLM endpoint and model name (see [Configure](#configure)), then:
95
+
96
+ ```bash
97
+ bolotype run --start-active
98
+ ```
99
+
100
+ Say *"hello world"* — it appears at the cursor. Say *"polish this paragraph"* — the LLM rewrites it in place.
101
+
102
+ ---
103
+
104
+ ## Install
105
+
106
+ > BoloType is not yet published on PyPI. Install from source.
107
+
108
+ ```bash
109
+ git clone https://github.com/baig97/bolotype.git
110
+ cd bolotype
111
+
112
+ python3 -m venv --system-site-packages .venv
113
+ source .venv/bin/activate
114
+
115
+ python -m pip install --upgrade pip setuptools wheel
116
+ pip install -e .
117
+ ```
118
+
119
+ This installs only the lightweight core (CLI, LLM client, config). Then install your ASR engine:
120
+
121
+ ```bash
122
+ bolotype install moonshine # Moonshine — CPU-friendly, low latency (recommended)
123
+ bolotype install nemotron # Nemotron 3.5 — higher accuracy, requires CUDA GPU
124
+ bolotype install # both engines
125
+ ```
126
+
127
+ `bolotype install` also installs Linux system packages (`python3-pyatspi`, `xdotool`, `xclip`, etc.) via apt and creates `~/.bolotype/` with default config files.
128
+
129
+ > **Nemotron note:** Nemotron 3.5 has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use Moonshine.
130
+
131
+ ---
132
+
133
+ ## Voice commands
134
+
135
+ | Command | What it polishes |
136
+ |---|---|
137
+ | `polish this line` | The line the caret is on |
138
+ | `polish this paragraph` | The paragraph the caret is in (blank-line delimited) |
139
+ | `polish everything` | The entire field |
140
+ | `polish the selection` | The currently selected text |
141
+ | `polish this` | Alias for *polish everything* |
142
+ | `undo that` | Restore the last polished span |
143
+
144
+ Commands trigger when a completed phrase exactly matches one of the above after punctuation and whitespace normalization.
145
+
146
+ ---
147
+
148
+ ## Configure
149
+
150
+ All settings live in `~/.bolotype/settings.json`. Only set the keys you want to override — everything else uses the defaults shown below.
151
+
152
+ ### LLM
153
+
154
+ ```json
155
+ {
156
+ "llm": {
157
+ "base_url": "http://127.0.0.1:8000/v1",
158
+ "model": "your-model-name",
159
+ "api_key": "",
160
+ "api_key_env": "OPENAI_API_KEY",
161
+ "timeout_seconds": 20,
162
+ "temperature": 0,
163
+ "max_output_tokens": 1000
164
+ }
165
+ }
166
+ ```
167
+
168
+ | Key | Default | Description |
169
+ |---|---|---|
170
+ | `base_url` | `""` | OpenAI-compatible API base URL. E.g. `http://127.0.0.1:8000/v1` for a local server or `https://api.openai.com/v1` for OpenAI. |
171
+ | `model` | `""` | **Required.** Model name exactly as your server expects it. |
172
+ | `api_key` | `""` | API key value. Leave empty if your local server doesn't require one. |
173
+ | `api_key_env` | `"OPENAI_API_KEY"` | Name of the environment variable to read the key from. Takes precedence over `api_key`. |
174
+ | `timeout_seconds` | `20` | Seconds to wait for the LLM response before raising an error. |
175
+ | `temperature` | `0` | Generation temperature. `0` is deterministic and gives the most consistent edits. |
176
+ | `max_output_tokens` | `1000` | Maximum tokens in the polished response. |
177
+
178
+ ### ASR
179
+
180
+ ```json
181
+ {
182
+ "asr": {
183
+ "engine": "moonshine",
184
+ "language": "en",
185
+ "nemotron_model_id": "nvidia/nemotron-3.5-asr-streaming-0.6b",
186
+ "nemotron_lookahead_tokens": 3,
187
+ "nemotron_vad_threshold": 0.01,
188
+ "nemotron_silence_duration_s": 1.25
189
+ }
190
+ }
191
+ ```
192
+
193
+ | Key | Default | Description |
194
+ |---|---|---|
195
+ | `engine` | `"moonshine"` | ASR engine to use. `"moonshine"` or `"nemotron"`. Can also be set via `--asr-engine` flag or `BOLOTYPE_ASR_ENGINE` env var. |
196
+ | `language` | `"en"` | Language code. Moonshine accepts `"en"`. Nemotron accepts locale codes such as `"en-US"`, `"de-DE"`, or `"auto"`. |
197
+ | `nemotron_model_id` | `"nvidia/nemotron-3.5-asr-streaming-0.6b"` | HuggingFace model ID for Nemotron. Downloaded automatically on first run. |
198
+ | `nemotron_lookahead_tokens` | `3` | Controls the streaming chunk size and right-context window. Supported values: `0` (80 ms), `1` (160 ms), `3` (320 ms), `6` (560 ms), `13` (1120 ms). Lower values reduce latency; higher values give the model more context. |
199
+ | `nemotron_vad_threshold` | `0.01` | RMS energy level that triggers speech onset detection. Increase if background noise causes false triggers; decrease if the first syllable is being clipped. |
200
+ | `nemotron_silence_duration_s` | `1.25` | Seconds of silence after speech ends before the utterance is submitted for transcription. Increase for slower or more deliberate speech. |
201
+
202
+ ### Input
203
+
204
+ ```json
205
+ {
206
+ "input": {
207
+ "backend": "auto",
208
+ "append_space": true
209
+ }
210
+ }
211
+ ```
212
+
213
+ | Key | Default | Description |
214
+ |---|---|---|
215
+ | `backend` | `"auto"` | Keyboard injection backend. `"auto"` picks `xdotool` on X11 and `ydotool`/`wtype` on Wayland. Set explicitly if auto-detection is wrong. |
216
+ | `append_space` | `true` | Append a space after each inserted phrase so the next phrase starts cleanly. |
217
+
218
+ ### Accessibility
219
+
220
+ ```json
221
+ {
222
+ "accessibility": {
223
+ "max_text_characters": 12000
224
+ }
225
+ }
226
+ ```
227
+
228
+ | Key | Default | Description |
229
+ |---|---|---|
230
+ | `max_text_characters` | `12000` | Safety limit. Polish is refused for text spans larger than this. Prevents accidentally sending a very large document to the LLM. |
231
+
232
+ ### Environment variables
233
+
234
+ All settings can also be set via environment variables, which take precedence over `settings.json`.
235
+
236
+ | Variable | Maps to |
237
+ |---|---|
238
+ | `BOLOTYPE_ASR_ENGINE` | `asr.engine` |
239
+ | `OPENAI_BASE_URL` | `llm.base_url` |
240
+ | `OPENAI_API_KEY` | `llm.api_key` |
241
+ | `VOICE_LLM_MODEL` | `llm.model` |
242
+ | `VOICE_LLM_TIMEOUT` | `llm.timeout_seconds` |
243
+ | `VOICE_LLM_TEMPERATURE` | `llm.temperature` |
244
+ | `VOICE_LLM_MAX_TOKENS` | `llm.max_output_tokens` |
245
+ | `BOLOTYPE_CONFIG_DIR` | Config directory (default: `~/.bolotype`) |
246
+
247
+ ### Prompt customization
248
+
249
+ The LLM polish prompt lives at `~/.bolotype/system_prompt.txt` and is created by `bolotype install`. Edit it freely:
250
+
251
+ ```bash
252
+ bolotype prompt-path # prints the path
253
+ nano ~/.bolotype/system_prompt.txt
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Run
259
+
260
+ ```bash
261
+ bolotype run --start-active
262
+ ```
263
+
264
+ All subcommands:
265
+
266
+ ```bash
267
+ bolotype install moonshine # install Moonshine ASR + system deps + create config
268
+ bolotype install nemotron # install Nemotron ASR + system deps + create config
269
+ bolotype install # install both ASR engines + system deps + create config
270
+ bolotype run # start the daemon
271
+ bolotype toggle # start/stop listening
272
+ bolotype polish # polish entire focused field
273
+ bolotype polish-line # polish current line
274
+ bolotype polish-paragraph # polish current paragraph
275
+ bolotype polish-selection # polish selected text
276
+ bolotype undo # undo last polish
277
+ bolotype status # show daemon status
278
+ bolotype shutdown # stop the daemon
279
+ bolotype config-path # print ~/.bolotype
280
+ bolotype prompt-path # print ~/.bolotype/system_prompt.txt
281
+ ```
282
+
283
+ For GNOME keyboard shortcuts, use the absolute path to the venv binary so the shortcut works outside a terminal session:
284
+
285
+ ```bash
286
+ /path/to/bolotype/.venv/bin/bolotype toggle
287
+ ```
288
+
289
+ ---
290
+
291
+ ## Replacement strategy
292
+
293
+ **Native GTK fields** (gedit, GNOME Text Editor, LibreOffice, terminals): AT-SPI `EditableText` writes the span directly.
294
+
295
+ **Browser/Electron fields** (Chrome, Electron apps): AT-SPI `Text.setSelection` selects the span, the polished text is placed on the clipboard via `xclip`/`wl-copy`, and `Ctrl+V` pastes it.
296
+
297
+ Fields exposing neither interface (password fields, some embedded widgets) are unsupported.
298
+
299
+ ---
300
+
301
+ ## Development
302
+
303
+ ```bash
304
+ pip install -e ".[dev]"
305
+ python -m build
306
+ twine check dist/*
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Known issues
312
+
313
+ ### Virtual environment
314
+
315
+ Ubuntu's `pyatspi` and `gi` packages are installed via the system package manager and are not available on PyPI. A normal isolated venv will not see them.
316
+
317
+ **Required:**
318
+
319
+ ```bash
320
+ python3 -m venv --system-site-packages .venv
321
+ ```
322
+
323
+ ### Conda
324
+
325
+ Conda environments may be incompatible with Ubuntu's compiled `gi` bindings due to ABI differences. Recommended pattern: run BoloType in a system-Python venv; run external model servers (LMDeploy, vLLM) in their own conda environment and communicate over HTTP.
326
+
327
+ ### Nemotron: GPU required
328
+
329
+ Nemotron 3.5 is loaded with `device_map="auto"` and has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use the Moonshine engine instead.
330
+
331
+ ### Nemotron: latency
332
+
333
+ Nemotron processes audio in streaming chunks but submits complete utterances for transcription. End-to-end latency depends on GPU speed and utterance length. Detailed benchmarking has not been done. Moonshine is lower latency on both CPU and GPU. You are encouraged to tune `nemotron_lookahead_tokens` and `nemotron_silence_duration_s` to match your hardware and speaking style.
334
+
335
+ ### Browser and Electron accessibility
336
+
337
+ Chromium-based rich text editors may expose only an object-replacement placeholder (`U+FFFC`) via AT-SPI. BoloType searches the AT-SPI subtree for the real text node. If none is found, polish is unsupported for that field.
338
+
339
+ ### Wayland
340
+
341
+ Input injection differs between compositors. X11 via `xdotool` is more reliable. Wayland requires `ydotool` or `wtype`.
342
+
343
+ ### Rich text
344
+
345
+ Targeted replacement through accessibility APIs may flatten formatting or operate only on the exposed accessible node.
346
+
347
+ ---
348
+
349
+ ## License
350
+
351
+ MIT © 2026 Muhammad Abdullah Baig
@@ -0,0 +1,297 @@
1
+ # BoloType — Type at the speed of sound. Refine with LLMs of your choice.
2
+
3
+ > System-wide voice typing with instant dictation and AI-powered editing.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ > **Platform support:** Linux only. Windows and macOS support is coming soon.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Instant dictation** — speech inserts at the cursor as soon as a phrase completes. No push-to-talk, no button to hold.
14
+ - **Bring your own LLM** — connect any OpenAI-compatible endpoint: llama.cpp, LMDeploy, vLLM, Ollama, OpenAI, Groq, and more. One setting to change.
15
+ - **Fully local by default** — audio never leaves your machine. LLM calls go only to the endpoint you configure. Nothing is sent anywhere unless you choose a cloud endpoint.
16
+ - **Private and safe** — no cloud account required, no telemetry, no data collection of any kind.
17
+ - **Voice polish commands** — say *"polish this paragraph"* and the LLM rewrites that span in place. Works on a line, paragraph, selection, or the entire field.
18
+ - **Precise undo** — *"undo that"* restores the exact pre-polish text, not a generic Ctrl+Z that may affect unrelated changes.
19
+ - **Two ASR engines** — [Moonshine](https://github.com/usefulsensors/moonshine) is fast, low-latency, and works on CPU. [Nemotron 3.5](https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b) offers higher accuracy and requires a CUDA GPU.
20
+ - **System-wide** — works in any text field reachable via AT-SPI2: GTK apps, browsers, Electron apps, terminals, and more.
21
+
22
+ ---
23
+
24
+ ## Quickstart
25
+
26
+ > Requires Ubuntu/Debian with a CUDA or CPU setup. Moonshine engine used below.
27
+
28
+ ```bash
29
+ git clone https://github.com/baig97/bolotype.git
30
+ cd bolotype
31
+
32
+ python3 -m venv --system-site-packages .venv
33
+ source .venv/bin/activate
34
+
35
+ pip install --upgrade pip setuptools wheel
36
+ pip install -e .
37
+ bolotype install moonshine
38
+ ```
39
+
40
+ Edit `~/.bolotype/settings.json` and set your LLM endpoint and model name (see [Configure](#configure)), then:
41
+
42
+ ```bash
43
+ bolotype run --start-active
44
+ ```
45
+
46
+ Say *"hello world"* — it appears at the cursor. Say *"polish this paragraph"* — the LLM rewrites it in place.
47
+
48
+ ---
49
+
50
+ ## Install
51
+
52
+ > BoloType is not yet published on PyPI. Install from source.
53
+
54
+ ```bash
55
+ git clone https://github.com/baig97/bolotype.git
56
+ cd bolotype
57
+
58
+ python3 -m venv --system-site-packages .venv
59
+ source .venv/bin/activate
60
+
61
+ python -m pip install --upgrade pip setuptools wheel
62
+ pip install -e .
63
+ ```
64
+
65
+ This installs only the lightweight core (CLI, LLM client, config). Then install your ASR engine:
66
+
67
+ ```bash
68
+ bolotype install moonshine # Moonshine — CPU-friendly, low latency (recommended)
69
+ bolotype install nemotron # Nemotron 3.5 — higher accuracy, requires CUDA GPU
70
+ bolotype install # both engines
71
+ ```
72
+
73
+ `bolotype install` also installs Linux system packages (`python3-pyatspi`, `xdotool`, `xclip`, etc.) via apt and creates `~/.bolotype/` with default config files.
74
+
75
+ > **Nemotron note:** Nemotron 3.5 has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use Moonshine.
76
+
77
+ ---
78
+
79
+ ## Voice commands
80
+
81
+ | Command | What it polishes |
82
+ |---|---|
83
+ | `polish this line` | The line the caret is on |
84
+ | `polish this paragraph` | The paragraph the caret is in (blank-line delimited) |
85
+ | `polish everything` | The entire field |
86
+ | `polish the selection` | The currently selected text |
87
+ | `polish this` | Alias for *polish everything* |
88
+ | `undo that` | Restore the last polished span |
89
+
90
+ Commands trigger when a completed phrase exactly matches one of the above after punctuation and whitespace normalization.
91
+
92
+ ---
93
+
94
+ ## Configure
95
+
96
+ All settings live in `~/.bolotype/settings.json`. Only set the keys you want to override — everything else uses the defaults shown below.
97
+
98
+ ### LLM
99
+
100
+ ```json
101
+ {
102
+ "llm": {
103
+ "base_url": "http://127.0.0.1:8000/v1",
104
+ "model": "your-model-name",
105
+ "api_key": "",
106
+ "api_key_env": "OPENAI_API_KEY",
107
+ "timeout_seconds": 20,
108
+ "temperature": 0,
109
+ "max_output_tokens": 1000
110
+ }
111
+ }
112
+ ```
113
+
114
+ | Key | Default | Description |
115
+ |---|---|---|
116
+ | `base_url` | `""` | OpenAI-compatible API base URL. E.g. `http://127.0.0.1:8000/v1` for a local server or `https://api.openai.com/v1` for OpenAI. |
117
+ | `model` | `""` | **Required.** Model name exactly as your server expects it. |
118
+ | `api_key` | `""` | API key value. Leave empty if your local server doesn't require one. |
119
+ | `api_key_env` | `"OPENAI_API_KEY"` | Name of the environment variable to read the key from. Takes precedence over `api_key`. |
120
+ | `timeout_seconds` | `20` | Seconds to wait for the LLM response before raising an error. |
121
+ | `temperature` | `0` | Generation temperature. `0` is deterministic and gives the most consistent edits. |
122
+ | `max_output_tokens` | `1000` | Maximum tokens in the polished response. |
123
+
124
+ ### ASR
125
+
126
+ ```json
127
+ {
128
+ "asr": {
129
+ "engine": "moonshine",
130
+ "language": "en",
131
+ "nemotron_model_id": "nvidia/nemotron-3.5-asr-streaming-0.6b",
132
+ "nemotron_lookahead_tokens": 3,
133
+ "nemotron_vad_threshold": 0.01,
134
+ "nemotron_silence_duration_s": 1.25
135
+ }
136
+ }
137
+ ```
138
+
139
+ | Key | Default | Description |
140
+ |---|---|---|
141
+ | `engine` | `"moonshine"` | ASR engine to use. `"moonshine"` or `"nemotron"`. Can also be set via `--asr-engine` flag or `BOLOTYPE_ASR_ENGINE` env var. |
142
+ | `language` | `"en"` | Language code. Moonshine accepts `"en"`. Nemotron accepts locale codes such as `"en-US"`, `"de-DE"`, or `"auto"`. |
143
+ | `nemotron_model_id` | `"nvidia/nemotron-3.5-asr-streaming-0.6b"` | HuggingFace model ID for Nemotron. Downloaded automatically on first run. |
144
+ | `nemotron_lookahead_tokens` | `3` | Controls the streaming chunk size and right-context window. Supported values: `0` (80 ms), `1` (160 ms), `3` (320 ms), `6` (560 ms), `13` (1120 ms). Lower values reduce latency; higher values give the model more context. |
145
+ | `nemotron_vad_threshold` | `0.01` | RMS energy level that triggers speech onset detection. Increase if background noise causes false triggers; decrease if the first syllable is being clipped. |
146
+ | `nemotron_silence_duration_s` | `1.25` | Seconds of silence after speech ends before the utterance is submitted for transcription. Increase for slower or more deliberate speech. |
147
+
148
+ ### Input
149
+
150
+ ```json
151
+ {
152
+ "input": {
153
+ "backend": "auto",
154
+ "append_space": true
155
+ }
156
+ }
157
+ ```
158
+
159
+ | Key | Default | Description |
160
+ |---|---|---|
161
+ | `backend` | `"auto"` | Keyboard injection backend. `"auto"` picks `xdotool` on X11 and `ydotool`/`wtype` on Wayland. Set explicitly if auto-detection is wrong. |
162
+ | `append_space` | `true` | Append a space after each inserted phrase so the next phrase starts cleanly. |
163
+
164
+ ### Accessibility
165
+
166
+ ```json
167
+ {
168
+ "accessibility": {
169
+ "max_text_characters": 12000
170
+ }
171
+ }
172
+ ```
173
+
174
+ | Key | Default | Description |
175
+ |---|---|---|
176
+ | `max_text_characters` | `12000` | Safety limit. Polish is refused for text spans larger than this. Prevents accidentally sending a very large document to the LLM. |
177
+
178
+ ### Environment variables
179
+
180
+ All settings can also be set via environment variables, which take precedence over `settings.json`.
181
+
182
+ | Variable | Maps to |
183
+ |---|---|
184
+ | `BOLOTYPE_ASR_ENGINE` | `asr.engine` |
185
+ | `OPENAI_BASE_URL` | `llm.base_url` |
186
+ | `OPENAI_API_KEY` | `llm.api_key` |
187
+ | `VOICE_LLM_MODEL` | `llm.model` |
188
+ | `VOICE_LLM_TIMEOUT` | `llm.timeout_seconds` |
189
+ | `VOICE_LLM_TEMPERATURE` | `llm.temperature` |
190
+ | `VOICE_LLM_MAX_TOKENS` | `llm.max_output_tokens` |
191
+ | `BOLOTYPE_CONFIG_DIR` | Config directory (default: `~/.bolotype`) |
192
+
193
+ ### Prompt customization
194
+
195
+ The LLM polish prompt lives at `~/.bolotype/system_prompt.txt` and is created by `bolotype install`. Edit it freely:
196
+
197
+ ```bash
198
+ bolotype prompt-path # prints the path
199
+ nano ~/.bolotype/system_prompt.txt
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Run
205
+
206
+ ```bash
207
+ bolotype run --start-active
208
+ ```
209
+
210
+ All subcommands:
211
+
212
+ ```bash
213
+ bolotype install moonshine # install Moonshine ASR + system deps + create config
214
+ bolotype install nemotron # install Nemotron ASR + system deps + create config
215
+ bolotype install # install both ASR engines + system deps + create config
216
+ bolotype run # start the daemon
217
+ bolotype toggle # start/stop listening
218
+ bolotype polish # polish entire focused field
219
+ bolotype polish-line # polish current line
220
+ bolotype polish-paragraph # polish current paragraph
221
+ bolotype polish-selection # polish selected text
222
+ bolotype undo # undo last polish
223
+ bolotype status # show daemon status
224
+ bolotype shutdown # stop the daemon
225
+ bolotype config-path # print ~/.bolotype
226
+ bolotype prompt-path # print ~/.bolotype/system_prompt.txt
227
+ ```
228
+
229
+ For GNOME keyboard shortcuts, use the absolute path to the venv binary so the shortcut works outside a terminal session:
230
+
231
+ ```bash
232
+ /path/to/bolotype/.venv/bin/bolotype toggle
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Replacement strategy
238
+
239
+ **Native GTK fields** (gedit, GNOME Text Editor, LibreOffice, terminals): AT-SPI `EditableText` writes the span directly.
240
+
241
+ **Browser/Electron fields** (Chrome, Electron apps): AT-SPI `Text.setSelection` selects the span, the polished text is placed on the clipboard via `xclip`/`wl-copy`, and `Ctrl+V` pastes it.
242
+
243
+ Fields exposing neither interface (password fields, some embedded widgets) are unsupported.
244
+
245
+ ---
246
+
247
+ ## Development
248
+
249
+ ```bash
250
+ pip install -e ".[dev]"
251
+ python -m build
252
+ twine check dist/*
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Known issues
258
+
259
+ ### Virtual environment
260
+
261
+ Ubuntu's `pyatspi` and `gi` packages are installed via the system package manager and are not available on PyPI. A normal isolated venv will not see them.
262
+
263
+ **Required:**
264
+
265
+ ```bash
266
+ python3 -m venv --system-site-packages .venv
267
+ ```
268
+
269
+ ### Conda
270
+
271
+ Conda environments may be incompatible with Ubuntu's compiled `gi` bindings due to ABI differences. Recommended pattern: run BoloType in a system-Python venv; run external model servers (LMDeploy, vLLM) in their own conda environment and communicate over HTTP.
272
+
273
+ ### Nemotron: GPU required
274
+
275
+ Nemotron 3.5 is loaded with `device_map="auto"` and has not been tested on CPU. A CUDA-capable GPU is strongly recommended. If you do not have a GPU, use the Moonshine engine instead.
276
+
277
+ ### Nemotron: latency
278
+
279
+ Nemotron processes audio in streaming chunks but submits complete utterances for transcription. End-to-end latency depends on GPU speed and utterance length. Detailed benchmarking has not been done. Moonshine is lower latency on both CPU and GPU. You are encouraged to tune `nemotron_lookahead_tokens` and `nemotron_silence_duration_s` to match your hardware and speaking style.
280
+
281
+ ### Browser and Electron accessibility
282
+
283
+ Chromium-based rich text editors may expose only an object-replacement placeholder (`U+FFFC`) via AT-SPI. BoloType searches the AT-SPI subtree for the real text node. If none is found, polish is unsupported for that field.
284
+
285
+ ### Wayland
286
+
287
+ Input injection differs between compositors. X11 via `xdotool` is more reliable. Wayland requires `ydotool` or `wtype`.
288
+
289
+ ### Rich text
290
+
291
+ Targeted replacement through accessibility APIs may flatten formatting or operate only on the exposed accessible node.
292
+
293
+ ---
294
+
295
+ ## License
296
+
297
+ MIT © 2026 Muhammad Abdullah Baig