Skip to content

Architecture

Chris Schroedinger edited this page Jul 3, 2026 · 1 revision

Architecture

For the full design document with rationale, see DESIGN.md in the repository. This page is the short version.

Daemon + thin clients

┌─────────────────────────────────────────────────┐
│ agentwhisperd (the daemon)                      │
│                                                 │
│  hotkey listener ─▶ state machine ─▶ engine     │
│  (XGrabKey)         (debounced)      (whisper)  │
│         │                 │             │       │
│  audio capture      DesktopBackend (X11):       │
│  (sounddevice)      type / clipboard / notify   │
│                                                 │
│  IPC: unix socket, JSON-lines protocol          │
└───────▲──────────────▲──────────────────────────┘
        │              │
   agentwhisper     tray icon + menu
   CLI              (GTK/AppIndicator)
  • The daemon owns all state: hotkey, microphone, model, recording lifecycle. Binding its socket doubles as the single-instance lock — a second launch says "already running" and exits.
  • The tray and the CLI are clients. A broken tray can never take dictation down.

Design principles

  1. No silent failures. Every integration (GTK bindings, desktop tools, model, hotkey grab) is verified at startup; every error message contains its fix.
  2. Pure-logic core. The recording state machine has no I/O — the debounce against X11 key auto-repeat is fully unit-tested.
  3. Interfaces at the boundaries. Engine (speech-to-text) and DesktopBackend (typing/clipboard/notifications) are small protocols. Wayland support or a cloud engine are new modules, not rewrites.
  4. Text is never lost. Clipboard first, then typing — if typing fails, the notification says the text is in the clipboard.

Components

Module Responsibility
daemon.py Wires everything; IPC server; lifecycle
state.py Recording state machine (pure logic, debounce)
hotkey.py Exclusive key grab via X11 XGrabKey
audio.py Microphone capture + live level (sounddevice)
engines/ Engine protocol + faster-whisper implementation
desktop/ DesktopBackend protocol + X11 implementation
tray.py Tray icon and menu (GTK/AyatanaAppIndicator)
visualizer.py The recording OSD with the level bars
cli.py, ipc.py Client commands and the socket protocol
config.py TOML config, strict validation

Development

./install.sh          # environment (system Python + GTK bindings)
uv run pytest         # 53 tests
uv run ruff check .

Tests cover the state machine (including a simulated X11 auto-repeat storm), config validation, the IPC protocol, and the full record→transcribe→deliver pipeline with fake hardware.

Clone this wiki locally