Wayland hotkey dictation CLI and daemon; native ASR/LLM fetched on first run.
Project description
Dictum
Dictum is a Python voice-to-text command tool designed for Wayland compositors such as Hyprland and Sway. It is intended to be triggered from a hotkey, record microphone audio, transcribe it with Parakeet TDT v3 0.6B, polish the transcription with a local or cloud LLM, and send the final text to the active window, clipboard, stdout, or a file.
Goals
- Fast hotkey workflow for dictation and text transformation.
- Persistent daemon for state, warm models, and lower latency.
- Companion CLI for key bindings and scripting.
- Pluggable ASR, LLM, recorder, and output backends.
- Wayland-first output through
wtype,ydotool,wl-copy, or stdout.
Architecture
Hyprland/Sway hotkey
-> dictum CLI (thin IPC client)
-> daemon command over local Unix socket
-> record mic audio (sounddevice/PipeWire)
-> transcribe with Parakeet (CrispASR HTTP server, port 8081)
-> polish with LLM (llama.cpp server, port 8080)
-> paste/copy/print/save result
Moving Parts
| Component | Technology | Purpose |
|---|---|---|
| CLI | Python + Typer | Hotkey-friendly commands (toggle, start, stop, once, status) |
| Daemon | Python + asyncio | State machine, IPC server, pipeline orchestration |
| Recorder | sounddevice (PortAudio) | PipeWire/PulseAudio capture, silence watchdog |
| ASR | CrispASR (C++/Vulkan) | Parakeet TDT v3 0.6B GGUF, HTTP server mode (warm) |
| LLM | llama.cpp (C++/Vulkan) | Qwen 3.5-4B GGUF, OpenAI-compatible HTTP server (warm) |
| Output | wtype / ydotool / wl-copy | Wayland text insertion |
| Notify | D-Bus (gdbus) | Desktop notifications |
State Machine
idle -> recording -> transcribing -> polishing -> pasting -> idle
\-> failed (on error) ----------------------------> idle
polishing is skipped if the profile disables LLM rewriting.
Quick Start
1. Prerequisites
- GPU: Discrete GPU with Vulkan support (optional but recommended)
- Vulkan loader:
libvulkan1/vulkan-loader+ a compatible ICD - Python: 3.11+ with
uv(recommended) orpip
2. Install Dictum
# From PyPI, once published
uv tool install dictum-asr
# Or from a local source checkout while developing
git clone https://github.com/hermitm0nk/dictum.git
cd dictum
uv tool install .
The wheel is pure Python and tiny (tens of KB). The native C++ binaries are no longer built from source at install time. Instead, Dictum downloads pinned upstream releases on first use:
llama.cpp→llama-server(Vulkan build,b9699)CrispASR→parakeet-main(Vulkan build,v0.7.2)
Pre-fetch them explicitly (recommended before binding a hotkey):
dictum native install # fetch both, Vulkan variant
dictum native install --lib llama
dictum native install --variant cpu # if no Vulkan ICD is present
dictum native status # show what's installed and where
Binaries land under $DICTUM_NATIVE_DIR when set, otherwise under
$XDG_DATA_HOME/dictum/native/, or ~/.local/share/dictum/native/.
The llama-server binary ships with RUNPATH=$ORIGIN so it finds its
sibling .so files automatically; parakeet-main is statically linked.
No LD_LIBRARY_PATH is required in normal use.
To override the bundled binaries entirely, set DICTUM_LLM_BIN and/or
DICTUM_PARAKEET_BIN to point at your own builds — Dictum will not
attempt to download when an override is set.
3. Download Models
# Parakeet ASR (multilingual, 4-bit quant)
huggingface-cli download cstr/parakeet-tdt-0.6b-v3-GGUF \
parakeet-tdt-0.6b-v3-q4_k.gguf \
--local-dir ~/.cache/dictum/models/
# Qwen LLM (Q3 quant for polishing)
huggingface-cli download unsloth/Qwen3.5-4B-GGUF \
Qwen3.5-4B-Q3_K_M.gguf \
--local-dir ~/.cache/dictum/models/
By default Dictum downloads models on first use into
$DICTUM_MODEL_DIR when set, otherwise into
$XDG_CACHE_HOME/dictum/models or ~/.cache/dictum/models.
4. Configure (Optional)
mkdir -p ~/.config/dictum
cp examples/config.toml ~/.config/dictum/config.toml
# Edit profiles, ASR/LLM settings, output target
Usage
Start the Daemon
# Foreground (testing)
dictum daemon --profile default
# Or as systemd user service (persistent, see below)
Hotkey Commands
# Toggle recording (press once to start, again to stop & process)
dictum toggle --profile default --result paste
# Explicit start/stop
dictum start --profile default
dictum stop --result paste
# One-shot (no daemon needed)
dictum once --result stdout --duration 30
# Status
dictum status
dictum status --json
Output Targets (--result)
| Target | Behavior |
|---|---|
paste |
Types into focused window via wtype/ydotool (fallback: clipboard) |
clipboard |
Copies to clipboard via wl-copy |
stdout |
Prints to terminal |
file |
Writes to /tmp/dictum-output.txt |
none |
No output |
Systemd User Service (Persistent Daemon)
# Install, enable (starts at login), but do not start now
dictum service install
# Install and start immediately
dictum service install --now
# Check status
dictum service status
# Remove the service
dictum service uninstall
The unit file is bundled with the wheel and copied to
~/.config/systemd/user/dictum.service (or $XDG_CONFIG_HOME/systemd/user/).
User units start at graphical/login session, not at boot.
The bundled unit (dictum/data/dictum.service):
[Unit]
Description=Dictum voice dictation daemon
After=graphical-session.target pipewire.service
[Service]
Type=simple
ExecStart=%h/.local/bin/dictum daemon
Restart=on-failure
RestartSec=2
[Install]
WantedBy=default.target
You can still manage the service directly with systemctl --user {start,stop,restart,status} dictum. Edit the installed unit file to
customize ExecStart (e.g. add --profile flags) and run
systemctl --user daemon-reload.
Hyprland Binding
Add to ~/.config/hypr/hyprland.conf:
# Dictum voice dictation (ScrollLock to toggle)
bind = , Scroll_Lock, exec, dictum toggle --profile default --result paste
Reload config:
hyprctl reload
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dictum_asr-0.1.0.tar.gz.
File metadata
- Download URL: dictum_asr-0.1.0.tar.gz
- Upload date:
- Size: 41.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
120fd5c47bee2f32c630e761f56652e4d6f6ab146f22a0e8b94e571dc2ed7485
|
|
| MD5 |
a648421bdce11a3d2aed39fd8f11a96a
|
|
| BLAKE2b-256 |
d2d46a8081716a61ab1aff8f4bafdd254229483d607b9763acd799bf43502dc3
|
Provenance
The following attestation bundles were made for dictum_asr-0.1.0.tar.gz:
Publisher:
pypi-publish.yaml on hermitm0nk/dictum
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dictum_asr-0.1.0.tar.gz -
Subject digest:
120fd5c47bee2f32c630e761f56652e4d6f6ab146f22a0e8b94e571dc2ed7485 - Sigstore transparency entry: 1859753212
- Sigstore integration time:
-
Permalink:
hermitm0nk/dictum@a7b67ab04a812df724f4ba7199c7a06fae605765 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hermitm0nk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yaml@a7b67ab04a812df724f4ba7199c7a06fae605765 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dictum_asr-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dictum_asr-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
897541237858ad4e5b551379023070beadd1838fc4a01cebe68f81ed684cbb4b
|
|
| MD5 |
7872110cd66b1195bbdb4a429808755c
|
|
| BLAKE2b-256 |
7554f0decb9fc4933c16e4c99dc5a17225e4cc6a6c2f581dc79229ecb92d680c
|
Provenance
The following attestation bundles were made for dictum_asr-0.1.0-py3-none-any.whl:
Publisher:
pypi-publish.yaml on hermitm0nk/dictum
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dictum_asr-0.1.0-py3-none-any.whl -
Subject digest:
897541237858ad4e5b551379023070beadd1838fc4a01cebe68f81ed684cbb4b - Sigstore transparency entry: 1859753215
- Sigstore integration time:
-
Permalink:
hermitm0nk/dictum@a7b67ab04a812df724f4ba7199c7a06fae605765 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hermitm0nk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yaml@a7b67ab04a812df724f4ba7199c7a06fae605765 -
Trigger Event:
release
-
Statement type: