One file, one line,
and the bench is in your terminal.
hh is the tools API with the ceremony removed: `hh lock taxes.pdf` instead of a curl invocation with three flags you have to look up. It is a single POSIX shell script — no bash, no jq, no python, nothing to keep updated — and it is generated from the same contract as the API itself, so it can never offer a tool the server does not have or miss one it does.
curl -fsSL https://hushhh.cc/install.sh | shIt downloads one file to ~/.local/bin/hh, checks it against a checksum this page was built with, and makes it executable. No sudo, nothing else touched, and it tells you if that directory is not on your PATH instead of leaving you with a command not found.
Read it first. It is served as plain text for exactly that reason, and so is the installer: piping a URL into a shell should be a decision, not a leap. install.sh · hh
Or skip the installer entirely — it is one file and it is not a secret:
curl -fsSL https://hushhh.cc/hh -o ~/.local/bin/hh && chmod +x ~/.local/bin/hh| hh pdf-unlock statement.pdf | Remove PDF passwords · page · api |
| hh pdf-merge cover.pdf body.pdf appendix.pdf | Join several into one · page · api |
| hh pdf-split report.pdf --mode keep --range 1-3,8 | Extract or remove pages · page · api |
| hh pdf-rotate scan.pdf --angle 90 --range 2-end | Turn pages the right way up · page · api |
| hh webp photo.png --quality 80 | WebP, JPG, PNG, AVIF · page · api |
| hh diff old.conf new.conf --format unified | Every difference, marked · page · api |
| hh lock taxes.pdf | Lock and unlock with a password · page · api |
| hh pass --mode words --words 5 | Strong passwords and passphrases · page · api |
| hh hash ubuntu.iso --expected 3a1f… | MD5, SHA-1, SHA-256 · page · api |
hh b6bf4943 · `hh --version` prints a fingerprint of the contract it was built from. When this page says a different one, the client is older than the API.
Every command takes a file and writes the result next to it, named after what happened to it: report.pdf becomes report-unlocked.pdf. It never overwrites without --force. `hh <command> --help` prints that command's flags with what each one means, and `-o -` sends the result to standard output so it can go into a pipe.
hh pdf-split report.pdf --mode keep --range 1-3\nhh file-hash ubuntu.iso -o -\nhh pdf-unlock --helpA password is never put in the URL and never passed as an argument to curl: it goes in a header, written to a temporary config file that is deleted when the command ends. A query string is recorded by proxies and by your own shell history, and an argument is visible in `ps` to everyone else on the machine. If a command needs a password and you did not give one, it asks at the terminal with the echo off — --password and --password-stdin are there for scripts, which have no terminal to ask at.
Set HUSHHH_HOST to run against another instance: HUSHHH_HOST=http://localhost:3000 hh hash file.iso. That is also how the test suite drives it, against a server it started itself.
It is one file. Delete it, or run the installer with --uninstall.
curl -fsSL https://hushhh.cc/install.sh | sh -s -- --uninstallThe file. That is the difference between this and the tool pages, where the work happens in your browser and nothing leaves the machine. Here the work happens on the server, so the bytes travel — over HTTPS, held in memory for the length of the request, never written to disk, to a log or to a database. If that trade is not one you want to make for a particular file, the page for that tool does the same job without it.
The same one thing is counted as on the pages: which tool ran, whether it worked, and an IP address with its last part zeroed. Not the file, not its name, not its size, not the result.
Frequently Asked Questions
Q: Why a shell script and not a real package?
Because the machine you want it on already has sh and curl, and probably does not have node, python or brew set up the way a package would need. One file also means the whole thing is readable in a minute before you run it, which matters more for something installed with a pipe into a shell than any amount of packaging would.
Q: Is `curl | sh` not a bad idea?
It is a bad idea when you cannot see what you are running. Both files are served as plain text so you can read them first, the installer verifies the client against a checksum built into it, it asks for no privileges, and everything it writes is one file in your own home directory. If you would rather not pipe it, download hh yourself and chmod +x it — that is the whole install.
Q: Does it work offline?
No, and it cannot: the work happens on the server. The tool pages do work offline, because there the work happens in your browser. Two different answers because they are two different things.
Q: How do I update it?
Run the installer again. `hh --version` prints the version it was built from, which is a fingerprint of the API contract — if it does not match the one on this page, there is something new.
Q: Windows?
Under WSL or Git Bash it works, since both have sh and curl. There is no native PowerShell client; the API is plain HTTP and Invoke-WebRequest does the same job in one line.
The same idea, applied to sending things rather than changing them.