FeaturesPricingBlogDownload

Configuration

Linux Setup

Install dependencies and configure typing, shortcuts, overlays, and voice on Linux with Wayland or X11.

Snipset runs on Linux through the same desktop stack as on Windows and macOS, but that stack makes a few assumptions you need to satisfy by hand: GTK and WebKitGTK for the interface, GStreamer for audio, and platform helpers for text injection and foreground detection. This page covers what to install and how to configure typing, global shortcuts, overlays, and voice on both Wayland and X11.

The guidance below works across distributions. Package names list Arch first, with the Debian and Ubuntu equivalent in parentheses.

Required Packages

# Arch
sudo pacman -S webkit2gtk-4.1 xdotool wl-clipboard \
  gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav \
  gst-plugin-pipewire xorg-xprop

# Debian / Ubuntu
sudo apt install libwebkit2gtk-4.1-0 xdotool wl-clipboard \
  gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
  gstreamer1.0-plugins-ugly gstreamer1.0-libav x11-utils

The GStreamer split is not cosmetic, and on Arch there is no automatic path into it. webkit2gtk-4.1 depends on the GStreamer shared libraries only, and it lists the plugin sets as optional. A plain install of webkit2gtk-4.1 therefore pulls in no GStreamer elements at all.

Two sets matter, for two different reasons:

  • gst-plugins-good provides autoaudiosink. Without it, voice playback fails with Could not open resource for writing.
  • gst-plugins-base provides the decoders for the app's own bundled sound effects (oggdemux and vorbisdec). Without them, Snipset starts and its window works, but the sound effects play nothing at all.

The remaining sets (gst-plugins-bad, gst-plugins-ugly, gst-libav) cover speech codecs. On Debian and Ubuntu, the good plugin package depends on the base plugins and the WebKitGTK package pulls in both, so the apt line above works even though it does not spell the base set out.

AppImage Users

The AppImage bundles the media framework. It ships the same five plugin sets as the list above, so you do not need to install the GStreamer packages from the previous section on a host that only runs the AppImage. That is the point of the bundle: a bare host gets working sound without discovering that webkit2gtk-4.1 left the plugin sets out.

The bundle covers GStreamer and nothing else. A host still needs:

  • A working audio output. The bundled elements end at autoaudiosink; the sink itself is PulseAudio or PipeWire on the host, and an AppImage cannot carry a sound server.
  • speech-dispatcher and espeak-ng for the Voice Profile dropdown and real text to speech. See Speech-to-Text and Text-to-Speech below.
  • ydotool on Wayland for key injection, which is unrelated to audio.

If sound effects are silent on an AppImage host, check the host's own GStreamer registry before suspecting the bundle:

gst-inspect-1.0 oggdemux vorbisdec autoaudiosink

This prints one line per element it can see. A missing element means the host has no plugins, which is worth reporting, since a plain AppImage has no way to import host plugins at run time.

Typing Expansion on Wayland (ydotool)

X11 needs nothing extra: xdotool is enough. On Wayland, key injection goes through ydotool, which needs a running daemon and permission to open /dev/uinput.

# Arch
sudo pacman -S ydotool
# Debian / Ubuntu
sudo apt install ydotool

sudo usermod -aG input "$USER"    # then fully reboot (a re-login is not enough)

Run the daemon as a user service at ~/.config/systemd/user/ydotoold.service:

[Unit]
Description=ydotool daemon for Snipset key injection
After=default.target

[Service]
ExecStart=/usr/bin/ydotoold
Restart=on-failure

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now ydotoold
ls /run/user/$(id -u)/.ydotool_socket   # must exist

Notes:

  • The client resolves the socket via $YDOTOOL_SOCKET, else $XDG_RUNTIME_DIR/.ydotool_socket. A stale socket file with no live daemon behind it fails the same way as a missing one.
  • If no daemon is reachable, Snipset falls back to its built-in uinput injector (which still needs the input group) instead of failing silently.
  • The daemon does not need root. Do not run ydotoold with sudo.

Global Shortcuts on Wayland (Portal)

On Wayland, shortcuts bind through the XDG GlobalShortcuts portal, and the compositor (KDE Plasma, for example) shows an approval dialog on first launch and after every shortcut change in Settings.

Checking Which Shortcuts Are Active

The portal answers a bind with any subset of the requested shortcuts, so a shortcut can come back with no key attached and then do nothing when you press it. Open Settings, then Shortcuts, and read the Shortcut Status list: it shows the compositor's own view of every shortcut, marks each one Active or Not active, and shows the trigger that is really assigned.

A shortcut marked Not active offers a Fix inactive shortcuts action, which opens the portal's own configuration surface. Grant the shortcut there and the status list updates immediately, with no need to restart Snipset.

The status list appears only on sessions that bind through the portal. On X11 and Windows the shortcuts register directly, so there is nothing to report.

Keeping Snipset and KDE in Step

Snipset stores each shortcut in its own preferences, and KDE Plasma stores the same shortcut in its own global shortcut registry. Snipset reaches that registry through the portal and, on KDE Plasma, through kglobalaccel, so both sides stay in step automatically:

  • Changed in KDE: while Snipset runs, a key changed in KDE System Settings works at once and the Shortcut Status list updates. Any Snipset change for that shortcut that is still waiting to reach KDE is dropped, so the KDE choice wins. The value stored in Snipset's Settings, an open settings form, and the was changed outside Snipset log line follow at the next portal session, which starts at launch or at the next shortcut save.
  • Changed in Snipset: on KDE Plasma (since linux 0.6.876), saving sets the new key on the desktop through kglobalaccel and reads it back to confirm. This covers every shortcut Snipset binds through the portal. A key already taken by another action is not moved, and the log says so: portal: could not move '<id>' to <key> on the desktop: the key is already taken by <holder>. Other desktops still rely on the portal dialog.

A shortcut with no live KDE binding is handled according to its state. A combination that KDE already owns is authoritative and Snipset follows it. If KDE reports no binding and the stored combination is known to be structurally refused, Snipset may restore that slot's safe default. If the stored combination is otherwise portable, Snipset preserves it and reports the shortcut as inactive instead of silently changing it.

Why a Shortcut Can Be Refused

Two different situations both look like a refusal in the log, and they need different fixes:

SituationWhat it looks likeWhat to do
The desktop environment will not represent that combination, for example bare Ctrl plus punctuation, Ctrl plus a digit, or Super plus punctuation.Log: this desktop environment does not grant that combination.Nothing to do. After the portal reports no live binding, Snipset may restore the slot default. Pick a different combination if you prefer.
Another application already holds the combination.Log: the compositor declined this binding, most likely because another app already holds it.Choose a different combination.
Two Snipset shortcuts share one combination.Settings shows a collision naming both slots.Only the first can fire. Change one of them.

Earlier builds reported every case as a cleared or rejected binding and asked you to re-enable it in Settings, which could not succeed, because re-saving simply presents the same dialog and the compositor refuses again. The messages above name the actual cause and a remedy that works.

Launching the App

Launch the app from its existing desktop icon or autostart entry. Do not launch it as a bare binary from a terminal. The portal identifies the app from its systemd scope and desktop-file association, so a terminal launch can inherit the terminal's application identity and place Snipset's shortcuts under the terminal instead. Symptoms of a misidentified launch are bindings under the wrong application, bindings that never stick, or an app id error.

On KDE Plasma 6, kioclient exec <desktop-id> is not a way to launch an application (it parses the argument as a URL) and kstart --application does not start it. Use systemd-run --user --scope with the app's own unit name, or click the launcher icon.

The portal covers the eight menus, the main-window toggle, smart shorthand, paste queue, password generation, bypass, every per-snippet hotkey, and all four voice shortcuts. Two Wayland specifics apply:

  • Dictate, Translate, and Ask Anything toggle (press to start, press again to stop): the portal delivers no key-release event, so push-to-talk and hold semantics are unavailable there. Read Aloud reads the clipboard aloud on every press, as on X11.
  • Shipped defaults are chosen to bind on KDE. If an old install still holds a combination KDE refuses, Snipset applies the fallback only after the portal reports no live binding. A valid KDE binding is never replaced by this recovery.

On X11, shortcuts register directly, and conflicts with another application are reported the same way.

Overlays and WebKit Rendering Policy

Snipset's overlays, including the speech recording overlay and the Magic Menu, are transparent always-on-top windows. If none of them ever appear, check the WebKit environment policy line in the startup log. On a Wayland session Snipset sets two variables and deliberately does not set two others:

VariableWaylandX11Why
WEBKIT_DMABUF_RENDERER_FORCE_SHMsetnot setKeeps hardware DMABUF out of the path (the WebKitWebProcess crash seen on some Intel and Mesa stacks) and still presents whole frames.
WEBKIT_DISABLE_DMABUF_RENDERERnot setsetWith a transparent window it leaves only the changing rectangles painted: the speech overlay shows its record dot, waveform and transcript but no card.
LIBGL_ALWAYS_SOFTWAREsetsetForces software GL on the same stacks.
WEBKIT_DISABLE_COMPOSITING_MODEnot setsetDisabling accelerated compositing leaves the compositor with no surface to map for a transparent window, so no overlay ever becomes visible.

Symptoms of WEBKIT_DISABLE_DMABUF_RENDERER being active on Wayland (a launcher or shell profile that exports it overrides the policy, and FORCE_SHM does not help while it is set):

  • The speech overlay appears, but only as fragments: a small tile with the record dot and mic icon, the waveform bars, and the transcript line. The card background, border, header text and buttons are missing.
  • Which fragments are visible changes from one dictation to the next.
  • Check with tr '\0' '\n' < /proc/$(pgrep -o snipset-desktop)/environ | rg WEBKIT and remove the variable from the launcher's Exec=env ... line.

Symptoms of the compositing override being active on Wayland:

  • The speech overlay never appears, although recording audio and the tray notification both work. Audio does not need a mapped window, so it is the overlay that fails.
  • The Magic Menu and every other overlay behave the same way, so this is not a speech-specific fault.
  • The overlay diagnostic records visible=false for every attempt, and no attempt ever reports visible=true.

You can override the policy: export any managed variable yourself and Snipset leaves it alone, whatever the value.

# Keep the compositing override only if the machine genuinely needs it,
# and accept that overlays will not map there.
WEBKIT_DISABLE_COMPOSITING_MODE=1 snipset-desktop

Residual risk, stated plainly: a machine whose WebKitGTK really does crash without the compositing override will hit that crash again on Wayland. The crash mitigation is kept through the shared-memory transport on Wayland, together with software GL, precisely to reduce that risk, and the startup log line tells you which mitigations were applied. There is no global setting that is correct for every machine, which is why the decision is logged rather than hidden.

Optional Helpers

ToolEffect when installed
xorg-xprop (x11-utils)Foreground application and title detection on X11: enables per-app snippet whitelists and blacklists, terminal-aware erase, and incognito-title exclusion.
kdotoolThe same foreground detection on KDE Wayland. Without it, or on other Wayland compositors, the foreground application is unknown: whitelisted snippets never expand and blacklists never match.

Installing the helpers is necessary but not sufficient. With kdotool, or xprop on X11, the tracker records the active application name on Linux, and most of its other numbers stay at zero.

Linux Tracker Limitations

The Linux capture path is deliberately reduced compared with Windows:

  • No input-density sample and no screenshot reference ever reaches the database, so screenshots are never collected.
  • With no screenshot hash, the processing queue is never populated and the derived-session pass returns early, leaving derived sessions empty.
  • Input events, tracked duration, and focused duration are all derived from the input-density timeline, which is empty on Linux, so all three read zero.
  • Context switches are counted from the derived sessions, so that count is zero as well.
  • The tracker's focused-time experience credit is unreachable on Linux. The base experience for a tracked day still applies.
  • Browser URL and active file title are unavailable, so the domain and file-title context kinds stay empty on every Linux machine no matter which helpers are installed. Only the application context is populated.

Foreground detection itself still depends on the helper, and the two display servers pick different tools: Wayland needs kdotool, X11 needs xprop. On a Wayland session, xprop is never used even when it is installed.

Speech-to-Text and Text-to-Speech

  • Speech shortcuts bind through the portal like every other shortcut, and on Wayland the voice bindings toggle, except Read Aloud, which reads the clipboard aloud on every press.
  • Dictation falls back to the bundled local Whisper model whenever the Gemini credential is absent. You can drop in a custom model without reinstalling. The SNIPSET_ESPEAK_BIN environment variable overrides the speech binary path.
  • The microphone is captured natively through ALSA or PipeWire, with the speech mic gain boost setting applied. WebKitGTK denies getUserMedia, so the browser path can never deliver samples or meter levels. The Test-Mic meters through the backend with no permission dialog. An empty native buffer stays empty and is never replaced with synthetic audio.
  • Real spoken text to speech needs espeak-ng:
# Arch
sudo pacman -S espeak-ng
# Debian / Ubuntu
sudo apt install espeak-ng

Without it, the app plays synthetic placeholder tones instead of speech.

  • The Voice Profile dropdown is a separate path: it lists the voices the WebView itself reports, and on Linux WebKitGTK asks speech-dispatcher for that list. An empty Voice Profile therefore means that layer is missing, not that Snipset failed. Install both and check it before debugging anything else:
# Arch
sudo pacman -S speech-dispatcher espeak-ng
# Debian / Ubuntu
sudo apt install speech-dispatcher espeak-ng

Confirm the layer works with spd-say "Hello", then restart Snipset. espeak-ng is a formant synthesizer and sounds deliberately robotic, so treat it as a working offline fallback rather than a natural voice.

Known Wayland Limitations

  • There is no global "which window is focused" API on Wayland. Snipset uses the helpers above where available and degrades gracefully otherwise: it never crashes and never injects into the wrong place.
  • The #{browser_url} variable resolves from the clipboard when it holds an http, https, or file URL. Reading the full address bar needs Windows UI Automation and has no Linux equivalent.
  • ydotool and wl-clipboard provide text injection and clipboard integration on Wayland. Both are recommended by the Linux packages.
  • If the window shows a Could not connect to localhost error, you are running a build older than the custom-protocol fix. Update the app.