Builds
snip Puts Every Project Command in the Repo, Not Your Head
I built snip so every forgotten deploy command lives in a committable .snips file with fuzzy and natural-language matching. MIT, no fzf dependency.

Last updated: October 3, 2026 · 4-minute read
Every repository has five commands someone always forgets: the deploy one with the weird flag, the seed one that only works after the migration one, the command buried in docs/ three folders deep. The shell history holds the answer for whoever typed it last, which is why new teammates get to re-discover everything by archaeology. I built snip to end that. It is a CLI backed by a .snips file that lives in the repo — commit it once, and every person and every agent who clones the project inherits the same commands. It is MIT-licensed at github.com/Bilal140202/snip.
Commands are project state
The core idea is one sentence: commands are project state, not personal state. The .editorconfig settled formatting arguments; the lockfile settled dependency arguments; .snips settles the "how do I run this" problem the same way — by putting the answer in version control where it belongs.
A .snips file is TOML, on purpose. TOML is readable without documentation, diffs cleanly, and does not need a parser library in whatever language the next contributor uses:
[seed] cmd = "python scripts/seed.py --truncate {{confirm}}" desc = "Reseed the dev database"
Placeholders use {{var}} syntax, and snip prompts for them at run time. Nobody pastes a command with someone else's environment variable in it again.
Zero memorization, two ways
The first lookup path is fuzzy matching with no fzf dependency — snip dep finds deploy, snip seed prod offers the right entry. The second is the one people do not expect: natural-language lookup. snip "start the frontend" matches the entry whose description says "Start the Vite dev server". The descriptions carry the semantics, so the matcher has something to work with. That is also why the file rewards being written well — a .snips file with honest descriptions is a tiny runbook.
There is a third path that costs nothing: auto-detection. snip scans 11 common file types — package.json scripts, Makefile targets, docker-compose services, Taskfile entries and more — and offers to import what it finds as starter entries. Existing projects get a usable .snips in under a minute, which matters, because a tool that only helps after an hour of curation never gets adopted.
The agent angle changed the stakes
I originally built this for humans. What became obvious while shipping agent-heavy workflows: agents inherit .snips too. An AI coding agent reading the repo finds the same file, the same descriptions, the same vetted commands. That turns the file into a safety mechanism — the agent runs snip test instead of guessing an unvetted incantation, and the team's actual deploy command (flags included) is what executes. Everyone already curates context for agents; a .snips file is curation that doubles as team documentation. The same instinct behind persistent memory for coding agents applies at repo scale.
What a good .snips file looks like
After using this across my own repos, three habits separate a useful file from a decorative one. Write descriptions as searches: "Deploy to Cloudflare staging (wrangler, env var)" beats "Deploy" on every lookup path, fuzzy and natural-language alike. Keep one command per entry — a compound command that chains four steps belongs in a script, not in snip, because the failure you will actually hit is step three. And delete ruthlessly: the file's value is trust, and an entry that no longer works costs more than no entry at all.
The team workflow falls out of the git model. A new teammate clones, runs snip, and the five commands that used to live in an onboarding doc are already there. When someone fixes a flag, the fix lands in a commit every reviewer sees — command drift becomes a diff, not folklore. That is the whole thesis in one sentence: the team's memory should merge like code, because it is code's shadow.
How it compares to the alternatives
Shell aliases are personal, machine-local, and invisible to teammates — snip is the repo-scoped complement, not a replacement. Makefiles and task runners are excellent at orchestration but tax every reader with their syntax; a .snips entry is one line of TOML plus one line of description. README code blocks are where commands go to rot: they are documentation-shaped, never executed, and never updated. snip's niche is deliberately narrow — the gap between "documented" and "runnable" — and staying narrow is why it fits next to all three without fighting any of them.
The honest caveats
Three of them. First, snip is deliberately dumb: it runs commands, it does not resolve dependencies between them, and if you need orchestration you need a task runner — snip sits happily next to one. Second, secrets belong in your environment, never in .snips; the file is in version control, so treat it like a README, not a vault. Third, the natural-language matcher is heuristic, not an LLM — it is fast and offline, but it will occasionally surprise you, and the fuzzy path remains the precise one.
None of these are accidents. A command runner that tries to be smart about your infrastructure is a liability; one that just remembers correctly is a tool.
Get started
The repo is github.com/Bilal140202/snip, MIT licensed. If you adopt it, the highest-leverage habit is adding the five commands you personally get asked about most — that is where the time goes back to the whole team. For more workflow tooling, my git aliases post covers the keyboard half of the same problem, and the full stack I actually use puts snip in context. Everything else I build is in the projects section.
---
Not affiliated with fzf or any task runner mentioned. Sources: the snip repository and README.