espanso and OpenCues are closer cousins than most pairs on this list: both are open source, both are keyboard-first, and both are configured with plain files you edit. The split is what happens at the trigger: espanso replays something you configured earlier; OpenCues computes an answer from the text around your _.
What each does at the trigger
In espanso, you define matches in YAML: type :date and it becomes today's date, type an abbreviation and it becomes your saved snippet. Its extensions can run a script or read the clipboard, but every behaviour is one you authored ahead of time, keyed to an exact trigger. In OpenCues, capital of france _, translate to german _, and draft a polite decline _ all work without anyone having configured those phrases, because a model interprets the surrounding text at the moment you type _.
The honest trade: static replay vs computed fills
| espanso | OpenCues | |
|---|---|---|
| Fill source | Snippets and scripts you configured | Computed: LLM, live APIs, or local scripts |
| Offline | Fully offline | Offline only with a local model (Ollama) or offline blanks |
| Determinism | Static matches: same trigger, same output; date, shell, and random matches vary | Keyword blanks are deterministic; LLM fills are not |
| Coverage | OS-wide, including native apps | Supported hosts: Chrome, Claude Code, OpenCode, Gemini CLI, terminal |
| Latency | Instant | Instant for local blanks; sub-second to seconds for LLM fills |
| Unanticipated requests | No; triggers must exist first | Yes; that is the point of the _ |
If your need is replaying your address, email signatures, and code boilerplate, espanso is the simpler, faster, fully offline tool, and nothing about OpenCues improves on it for that job.
Where the kinship shows
Both projects believe the same thing about configuration: plain text files, hot-reloaded, shareable. espanso has YAML match files and a package hub; OpenCues has markdown config folders (CUE.md, BLANK.md) under ~/.cues/ and an open standard so the files work across implementations. For the classic expander use case, OpenCues' identity context plays the same role as personal snippets, with the twist that in its default safe mode your stored values are substituted on your machine and never reach the model provider.
Run both
They listen for different things (espanso for its trigger strings, OpenCues for _ and its keyword grammar), so they coexist without conflict. There's even a config-hygiene parallel: espanso users keep match files in version control, and OpenCues' project-level .cues/ is designed for exactly the same habit, with opencues validate as the lint step. Snippets you replay daily belong in espanso; answers you could not have saved in advance belong in a blank. The broader category picture is in OpenCues vs text expanders.
Related: OpenCues vs text expanders · What is a blank? · Ollama vs cloud · GitHub repo