The command changes every time. Sift still counts it as one.
Sift mines your shell history for the long commands you keep retyping, catches the ones that vary by a single argument, and hands you a ready-to-paste alias. All in the browser, nothing uploaded.
You have typed git commit -m "..." a few hundred times this year. The
message is different every time, so the obvious trick,
grep 'git commit' ~/.zsh_history | sort | uniq -c, reports each line as
unique, finds nothing worth aliasing, and moves on. But it is the same
command. You are paying the same tax on git commit -m over and over, and
no history tool ever points at it.
Sift is the tool that does. Drop your
.zsh_history or .bash_history onto the page and, in under a second, it
hands you a ranked table of the commands you keep retyping, a ready-to-paste
alias or function for each one, and the exact number of keystrokes it
will save you going forward.
Mining, not searching
History search (Ctrl+R, fzf, atuin) answers "what was that command I
ran?" so you can run it again right now. Sift answers a different question:
"across my whole history, which shapes of command have I retyped enough to
be worth automating?" Search looks at one command. Sift treats the entire
file as a corpus to mine.
The mechanism that makes it more than sort | uniq -c is n-gram template
matching. Sift tokenizes each history line into words, then mines repeated
n-gram patterns across every command. A line like git commit -m "fix nav"
and another like git commit -m "bump deps" share the n-gram
git commit -m, so they collapse into a single candidate that varies only
in its trailing argument, rather than getting counted as two unique lines
that each look one-off. That is the whole trick: recognizing that a command
which changes every time is still the same command.
Once a candidate is found, its shape decides what Sift proposes. If nothing
varies, you get a plain alias. If an argument varies, you get a shell
function with a positional parameter, because a plain alias cannot take
an argument and proposing one for a command that actually varies would hand
you something broken:
alias gs="git status --short --branch" # fixed command
function gc() { git commit -m "$1"; } # varying argument
Ranked by what it actually saves
The obvious way to rank the results is by frequency, and it is the wrong
one. A command you ran 500 times that is already only six characters long
is not worth a second thought. A command you ran 20 times that is 80
characters long absolutely is. So Sift ranks by total keystrokes saved:
(chars per use - chars with the alias) x times seen. That single change
turns the output from "a list of your most common short commands" into "a
list of the commands where an alias buys you the most typing back," which
is the only list you care about.
It never leaves the tab
Shell history is personal. It is full of paths, hostnames, and flags that
quietly describe your infrastructure, and occasionally a token or password
someone pasted inline. So the entire pipeline, parser and miner and
proposer, is a Go program compiled to GOOS=js GOARCH=wasm and run in your
browser. There is no upload, no server, no network request. Point the WASM
binary at a file, get an answer back, and nothing crosses the wire. As a
bonus, hosting it is trivial: it is a static bundle that drops onto any
subpath with no backend to run or pay for.
One honest limitation lives in the classification step, and it is the part
that took the most care. Deciding whether a candidate is "fixed" or "varies
by one argument" is a judgment call the miner has to get right before the
proposer runs, because a wrong call produces a syntactically valid alias
that does the wrong thing. It also means Sift deliberately refuses to bake a
password or inline token into a proposal, even when that command clears the
frequency bar. Better to skip a suggestion than to hand you an alias that
commits a secret to your .zshrc.
Try it
Open Sift and drag your real
.zsh_history (or .bash_history) onto the page. Look at the top row: it
is almost certainly a command you did not realize you typed that often.
Nudge the minimum-occurrence and minimum-savings sliders to cut the noise,
copy the alias block, and paste it straight into your shell config. If you
want to read the miner before you trust it with your history, the
code is on GitHub.
This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.
Loading comments…