Charlie KrugThe Build Log

← All posts

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.

Sift is live. Free, in your browser, no signup.

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.

Comments

Loading comments…