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
Metadata
Release files for dictum-asr 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dictum_asr-0.3.0.tar.gz | 48.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dictum_asr-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 88.3 kB
Release files / dictum_asr-0.3.0.tar.gz
| Download URL | dictum_asr-0.3.0.tar.gz |
|---|---|
| Size | 48.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d7380be05944601675f080ef6c6bc3047d4f876c5651a4b4622b0d0e6d71691
|
|
BLAKE2b-256 checksum How to use checksums |
7945fc39337dafe957872d1d95e783c2b5702b275caff1335899864966fef73c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / dictum_asr-0.3.0-py3-none-any.whl
| Download URL | dictum_asr-0.3.0-py3-none-any.whl |
|---|---|
| Size | 39.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35fa2fe2802071679f39da8620af370ae14458f01394ef602e0e1f88c3f2df50
|
|
BLAKE2b-256 checksum How to use checksums |
94be6263a5479c958fb3f0c9366adeeed68290cee41804fbaa88680e596d5c3f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log