Should I vibe code
Expand local text snippets from abbreviations with forms and simple variables
You are giving a background process you vibe coded permission to read every keystroke in every app.
?
Their verdict, the Individual price and the build-time estimate come from their entry, MIT-licensed. Checked 2026-08-04.
?
Our verdict, the regret score and everything below it. Editorial and unsponsored — nobody can pay to be moved.
The honest answer
why the verdict is what it is
The first version is delightful and takes an evening: watch for an abbreviation, delete it, type something longer. Then you notice what you actually built. To match an abbreviation anywhere, the process has to see every keystroke in every application — on macOS that means granting Accessibility and Input Monitoring to a binary you compiled this afternoon, which is a keylogger with a polite intention and no code review. And snippets are where people keep the things they type often, which turns out to mean API keys, wifi passwords, a support macro with a customer's name in it, and the ssh command with the host in it. Neither of those ends the world — this is your own machine, and the blast radius is one laptop. What makes it DEMO ONLY is that Espanso already exists and is very good, and the last twenty per cent of a text expander is where homemade ones go to die: Electron apps that eat backspaces, password fields, IME input, cursor placement, undo.
What actually breaks
not "if". the specific failures.
- The debug log — the one you added at 1am while fixing a matching bug, which writes the keystroke buffer to a file, and which is still there in March
- Expansion inside a password field, where the trigger fires, the characters are deleted and something long and personal is typed into a box that will submit it somewhere
- The delete-and-retype race in a slow Electron app, so half the abbreviation survives and your address goes out as "addr17 Bridge Street"
- The snippet file itself, which ends up in a dotfiles repo with a live API token in it because it was just text and text goes in git
- Case, cursor placement and tab stops — the boring parts that make the difference between a demo and a tool you trust mid-sentence
- The permission grant, which macOS revokes or invalidates when the binary changes, so the expander silently stops working after a rebuild or an OS update
- Cloud sync, if you add it, because that is the point where a local-only utility becomes a plaintext store of your credentials on someone's server
Is that you?
the verdict is a default, not a law
- It runs on your machine only, with no sync and no network access at all
- No snippet contains a password, a token, a customer's details or anything you would not paste into a public chat
- The keystroke buffer lives in memory, is bounded, and is never written anywhere
- You want a specific behaviour Espanso does not have, rather than wanting a text expander
- Snippets hold secrets and the snippet file is in a repo, a shared drive or a backup you have not thought about
- There is any logging of raw input, even behind a debug flag
- You are building shared team snippets, which is a sync service holding other people's canned text and a different project
- You would not be able to say, from memory, exactly what your matcher does when the focused field is a password box
If you build it anyway
the checklist, then the prompt that enforces it
- Never write raw input to disk or to a log, at any level, even temporarily. Keep a bounded in-memory ring buffer that clears on match, on a delimiter and on a short timeout.
- Detect secure input and password fields and disable matching entirely while one is focused. Fail closed: if you cannot tell what has focus, do not expand.
- Require an explicit trigger character or key to fire an expansion rather than matching on every keystroke boundary. It halves the accidental-expansion surface and makes the code simpler.
- Keep secrets out of snippets as a rule, and if one must be reachable, store a keychain reference and resolve it at expansion time rather than putting the value in the file.
- Ship an app denylist that includes terminals and password managers by default, and let the user add to it. Expansions in a shell are the ones with consequences.
- Never append a newline or send Enter as part of an expansion. An expander that can submit a form or run a command is a different tool with a different verdict.
- If you add sync, encrypt the snippet store on the device with a key that never leaves it — and ask yourself first whether the snippets are worth a network dependency.
I am building a text expander: it watches what I type, matches abbreviations and replaces them. Assume the input stream is the most sensitive thing in the project and build the safety rails before the features.
1. Establish the no-logging rule first and put it in the README: raw keystrokes are
never written to disk, never sent over a network and never printed — not behind
a debug flag, not in a crash report, not temporarily. If I ask for a keystroke
log to debug matching, refuse and build a synthetic input harness instead.
2. Keep the match buffer in memory, bounded to the longest abbreviation, cleared
on match, on any delimiter and on a short idle timeout.
3. Before any matching logic, implement focus detection: if a password field is
focused or secure input is active, disable expansion entirely. Fail closed when
the focused element cannot be determined.
4. Require an explicit trigger key or character rather than matching continuously,
and explain the difference in accidental-expansion risk.
5. Never emit Enter or a trailing newline as part of an expansion, and never build
a snippet type that executes a shell command. An expander that can submit or
execute is a different and much worse tool.
6. Ship a default denylist of applications — terminals, password managers, remote
desktop clients — where expansion never fires.
7. Snippets live in one plain, documented, human-readable file. Warn me in the
README that this file will end up in a git repo and must never hold a secret.
8. If I want a secret in a snippet, store an OS keychain reference and resolve it
at expansion time. Refuse to write the value into the snippet file.
9. Handle the replace carefully: measure what to delete, verify it matches what
you expected, and abort rather than deleting characters you are unsure about.
A mangled half-expansion in a message box is the common bug.
10. Keep it offline. No sync, no telemetry, no update check that phones home. If I
ask for sync later, encrypt on device first and tell me what I am trading.
11. Out of scope on purpose: team snippet sharing, usage analytics, cloud backup,
any AI rewriting of what I typed.
12. Finish by pointing me at Espanso and asking whether I want a text expander or a
text expander project.That one keeps you out of trouble. For the prompt that actually builds it, canivibecodeit.com has one.
their build prompt ↗Or don’t build it
the boring option, and the way back out
You are sharing snippets across a team, or you want it to work on a phone. $4.16 per user a month month-to-month, or $3.33 billed annually, buys team libraries, an audit of who changed which canned response, and per-app behaviour somebody else has already debugged. For one person on one machine the honest comparison is not TextExpander but Espanso, which is free, mature and does the awkward parts correctly.
$4.16/mo is cheaper than your weekend.
Keep snippets in one plain YAML or JSON file with a documented shape, one snippet per entry, no binary blobs. That file imports into Espanso in about five minutes and into TextExpander with a small script, which means abandoning your own expander costs you an afternoon and nothing else. Rotate anything that ever lived inside a snippet before you archive the repo.
Mature cross-platform open-source text expander; the default answer for one person on one machine.
Long-running Linux desktop automation and expansion tool, still receiving commits.
Questions
Alfred and BetterTouchTool are SHIP IT here and both do snippets. Why is this one not?
Because of what the process has to watch. A launcher reacts when you summon it; a hotkey tool reacts to a chord you defined. A text expander has to observe every character you type in every application in order to work at all, and it holds a file people fill with the things they type most often — which is where the tokens and passwords end up. Same neighbourhood, one extra permission, and the permission is the whole story.
Is a homemade expander actually a keylogger?
Structurally it is the same program with a different intention. It requires the same operating system permission, it observes the same stream, and the only difference is that it discards what it sees instead of storing it. That distinction lives entirely in your code, which is why the first rule is that nothing writes the buffer anywhere, and why a debug log added in a hurry is the specific failure worth naming.
What makes the last twenty per cent so hard?
Applications that do not behave. Electron apps that swallow synthetic backspaces, editors with their own autocomplete, IME composition for non-Latin input, fields that reset the cursor after a paste, and undo stacks that treat your replacement as forty separate edits. Espanso has years of these fixes in it. Your evening's work will handle your text editor beautifully and mangle something in a chat window by Thursday.
Every week, someone ships something they shouldn’t have.
New verdicts, the worst thing that landed in the trap, and the occasional incident report. No other email, ever.
last reviewed 2026-08-04 · verdict is editorial and unsponsored · shared entry data from canivibecodeit under MIT · not legal advice