How to Use Hermit: The Beginner’s Guide (First Init, the bin/ Wrapper Lesson, First Tool Pin, and the Self-Bootstrapping Payoff)
CodexFuse Team · 2026-11-02T09:14:23.986Z · 14 min read min read
Hermit is Cash App’s self-bootstrapping toolchain manager: it vendors exact tool versions into your repo’s bin/ directory so every clone gets the same tools with zero installs. This beginner’s guide covers install, hermit init, the wrapper lesson, your first tool pin, and CI parity.
If you want to know how to use Hermit, the answer fits in one sentence: Hermit is Cash App's open-source tool that vendors the exact versions of your project's developer tools into a bin/ directory inside your repo, so every clone of that repo gets the same toolchain with zero setup. This is a hermit tutorial for beginners — no prior experience with the hermit package manager needed. You will install Hermit once, initialize one project, pin your first tool, and see exactly why a fresh laptop needs nothing more than git clone to be productive. If you are fuzzy on how repositories themselves work, our Git beginner guide covers the repo side of the story; Hermit is what keeps the tools inside that repo consistent, which matters even more once your team grows and everyone works on different machines — or deploys to what is VPS hosting explains the servers where that consistency pays off most.
One disambiguation up front, because the name collides: this guide is about Cash App's hermit (github.com/cashapp/hermit — the cashapp hermit repo), the developer toolchain manager. It is not dylibso's "Hermit," which is a completely different product for portable WebAssembly packaging. Everything below is the Cash App one.
What Is Hermit, Exactly?
The direct answer: Hermit is a package manager that stores isolated, self-bootstrapping sets of developer tools inside each software project's repository. The project's own description says it best: "Hermit manages isolated, self-bootstrapping sets of tools in software projects" (cashapp.github.io/hermit). Instead of asking every developer to install Go, Node, protoc, and lint tools on their own machine, you commit a bin/ directory to your repo. Every file in that directory is a tiny wrapper script. When anyone runs one of those wrappers — on any machine — it bootstraps Hermit itself if needed, downloads the exact pinned version of the tool, and then runs it. Nothing to install, nothing to version-manage by hand.
The mental model to lock in, stated once: Hermit is the toolchain checked into the repo. The versions of your tools stop living on people's laptops and start living in version control, next to the code they build.
Why Does Hermit Exist? The "Works on My Machine" Problem
The direct answer: Hermit exists because teams constantly break on tool-version drift — one developer has Go 1.21 from Homebrew, another has 1.23, and CI has whatever the base image shipped. Hermit's founder described the exact frustration on the lobste.rs discussion thread: developers needed "version X from Homebrew" but CI gave them "version Z," and Hermit fixes it by "versioning all tools in the Git repo in which they are used" — "It's like magic!"
This is a different job from most tools people compare it to. A version manager like mise manages tool versions on your machine via global shims; Hermit vendors a whole tool set into the repo via bin/ wrappers, so the versions travel with the code. That line — per-machine versions versus per-project toolsets — is the one distinction to draw once and never blur. It also explains why the official FAQ says Hermit is "probably most similar to asdf" in mechanics, while the mise-vs-Hermit framing in this guide is my own analysis, not something the docs claim.
What Do I Need Before I Start?
The direct answer: almost nothing — a shell, git, and a Linux or macOS machine. Here is the full checklist:
| Requirement | Details | Why |
|---|---|---|
| Shell | bash, zsh, or fish | Hermit natively supports these three shells (per the official FAQ) |
| git | Any recent version | You commit the bin/ directory to the repo; pinning is version-controlled |
| curl | Preinstalled almost everywhere | The one-line installer downloads the hermit binary with curl |
| OS | Linux or macOS (x86_64 or arm64) | The installer fetches a prebuilt binary for your platform |
| A project directory | Any folder with a git repo | hermit init creates the bin/ environment inside it |
No Go toolchain needed to run Hermit itself — it ships as a prebuilt binary. (Hermit the project is written in Go, but you do not compile anything.)
How Do I Install Hermit?
The direct answer: run the official one-line installer, which downloads Hermit into your user cache and drops a launcher into ~/bin.
curl -fsSL https://github.com/cashapp/hermit/releases/download/stable/install.sh | /bin/bash
Here is what that command does, step by step: it fetches install.sh from the stable release channel, downloads the prebuilt hermit-linux-amd64 (or macOS/arm64 equivalent) binary into ~/.cache/hermit/pkg/hermit@stable/, and writes a small launcher script to ~/bin/hermit. The official Get Started docs say exactly this: the installer "will download and install hermit into ~/bin," and you must make sure ~/bin is on your $PATH.
I ran this exact command on my own machine while writing this guide, and it reported:
Hermit installed as /home/hatch/.cache/hermit/pkg/hermit@stable/hermit Hermit is installed as /home/hatch/bin/hermit $ hermit version v0.55.1 (stable)
So Hermit v0.55.1 on the stable channel is what this tutorial is verified against (checked November 2, 2026; the stable channel moves, so yours may be newer). If hermit is not found afterwards, run export PATH="$HOME/bin:$PATH" in your current shell, or add that line to your ~/.bashrc / ~/.zshrc.
How Do I Initialize My Project with Hermit?
The direct answer: change into your project directory and run hermit init — it creates a bin/ directory containing the whole Hermit environment.
cd my-project hermit init ls bin/
On my machine, hermit init ran silently and produced exactly this bin/ directory:
| File | What it is |
|---|---|
README.hermit.md | Explains that the symlinks here are managed by Hermit and auto-download packages |
hermit | A generated wrapper script that bootstraps Hermit itself on demand |
hermit.hcl | The environment config file (starts with just a github-token-auth {} block) |
activate-hermit | Shell script you source to put this project's tools on your PATH |
activate-hermit.fish | The fish-shell variant of the activator |
Say it once: hermit init does not download your tools yet — it builds the empty house, and you move the tools in next. Everything in bin/ is ordinary files and scripts, which is why the whole environment can live in git.
How Do the bin/ Wrappers Actually Work?
The direct answer: each file in bin/ is a tiny self-bootstrapping launcher: when run, it checks whether the real tool exists locally, downloads it if not, and then hands off to it. The docs phrase it as: "Each link will bootstrap Hermit if necessary, then auto-install the package, before executing the binary."
Here is the core of the generated bin/hermit wrapper, straight from the file hermit init created on my machine (comments trimmed):
#!/bin/bash
# THIS FILE IS GENERATED; DO NOT MODIFY
...
if [ ! -x "${HERMIT_EXE}" ]; then
echo "Bootstrapping ${HERMIT_EXE} from ${HERMIT_DIST_URL}" 1>&2
# downloads the installer, VERIFIES its sha256, then runs it
/bin/bash "${INSTALL_SCRIPT}" 1>&2
fi
exec "${HERMIT_EXE}" --level=fatal exec "$0" -- "$@"
Notice two things. First, the wrapper verifies the installer's SHA-256 checksum before running it — the pinned hash is baked into the script, so a compromised download cannot silently execute. Second, the same pattern applies to every tool you pin: running ./bin/go on a machine that has never seen Hermit will install Hermit, then install Go, then run Go. I verified this end of the mechanism directly: ./bin/hermit version in my test project returned v0.55.1 (stable) through the wrapper alone.
That is the whole self-bootstrapping toolchain trick, said once: the tools install themselves the first time they are invoked. In plain terms, it is a self bootstrapping toolchain: every tool carries its own installer. A fresh machine needs only the repo.
How Do I Pin My First Tool?
The direct answer: search for the tool with hermit search, then install a specific version with hermit install <package>-<version>.
Do not trust the version numbers in old screenshots — check what is actually available today:
$ hermit search go go (1.17rc1, @1, ..., @1.27, @latest, @tip, ..., 1.27.0, 1.27.1, 1.27.2, 1.27.3) Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
That is real output from November 2, 2026: the go package offers numbered versions up to 1.27.3 plus channels like @latest, @tip, and @1.27. (The docs' own example uses go-1.16.3, which is stale — always search first.) Hermit understands three selector formats:
| Selector | Example | Meaning |
|---|---|---|
<package>-<version> | hermit install go-1.27.3 | Pin an exact version — the reproducible choice |
<package>@<channel> | hermit install [email protected] | Track a channel, e.g. latest 1.27.x |
<package> | hermit install go | Take the package's preferred version |
For a team's toolchain, always use the exact-version form — that is the entire point of pinning. Running hermit install go-1.27.3 creates a bin/go wrapper plus a hidden pin record in bin/ (on the Hermit project's own repo you can see entries like .go-1.27.1.pkg next to the wrappers). Package definitions come from HCL manifests synced from their sources every 24 hours, so new versions keep flowing in while your pins stay frozen.
What Happens When a Teammate Clones My Repo?
The direct answer: nothing special — they clone and run the tool, and Hermit installs everything on first use. This is the self-bootstrapping payoff, said once: on a brand-new laptop, the entire onboarding is git clone followed by ./bin/go version, and the exact pinned Go appears. No wiki page titled "dev environment setup," no "install these twelve things first" list, no version drift between your machine and theirs.
The bin/README.hermit.md file that hermit init generates states the contract plainly: "The symlinks in this directory are managed by Hermit and will automatically download and install Hermit itself as well as packages. These packages are local to this environment." Local to the environment is the key phrase — Hermit never touches your system tools, so your global Go, your OS package manager's Go, and your project's Go can all coexist without fighting.
Commit the bin/ directory to git so the whole team shares it. The docs never print a literal "git add bin/" instruction, but the founder's design statement makes the workflow explicit: "Hermit solves that by versioning all tools in the Git repo in which they are used." The wrappers and their pin records are plain files; git is their home.
How Do I Activate Hermit in My Shell?
The direct answer: source the activator — . ./bin/activate-hermit — and your project's tools take precedence on your PATH while you are in that project.
Without activation you can always call tools by their full path (./bin/go), but activation makes plain go resolve to Hermit's pinned version in the current shell. Hermit also ships shell hooks that auto-activate when you cd into a project and auto-deactivate when you leave, and a deactivate-hermit command drops you back to your system tools. Activation is per-shell, so one terminal can run the project's pinned Go 1.27 while another terminal on the same machine uses the system Go — they never interfere.
Hermit vs asdf vs mise vs Nix: What's the Difference?
The direct answer: Hermit is closest to asdf, deliberately narrower than Nix, and solves a different half of the problem than mise. Here is the honest comparison:
| Tool | What it manages | How versions are selected | Key difference from Hermit |
|---|---|---|---|
| Hermit | Per-project tool sets | Wrappers + pin records in bin/, committed to git | — |
| asdf | Per-user / per-project versions | .tool-versions file + plugins | The FAQ's own words: "Hermit is probably most similar to asdf, but their goals differ. Hermit's goal is to make isolated cross-platform tooling consistent, self-bootstrapping, and reproducible at the project level." |
| mise | Per-user tool versions via shims | Global installs, mise use per directory | mise manages versions on your machine; Hermit checks the whole toolset into the repo so clones need zero installs. (This framing is my own analysis — the Hermit docs never mention mise.) |
| Nix | An entire OS's packages | Declarative derivations, full build system | The FAQ's own words: "Nix is the package manager for an entire OS and thus provides vastly more functionality than Hermit, including a full package build system... Hermit is deliberately designed to be narrow in scope, limited to just installing existing packages." The founder adds: "There is no claim that this is competing with Nix. The opposite in fact." |
The one-liner for the hermit vs nix question: Nix builds the world; Hermit installs the tools. And for hermit vs mise: mise answers "which version do I use," Hermit answers "which versions does this project use" — and it answers it in git.
How Do I Use Hermit in CI?
The direct answer: do nothing different — your CI job clones the repo and runs the bin/ wrappers, getting the exact same tools as every developer. That is the whole CI story, and it is why Hermit teams love it: the build that ran on your laptop runs identically on the runner because the toolchain is the same files.
In practice this means your pipeline can be gloriously boring. In a container-based job (see our Docker beginner guide for the container side), the only prerequisites are git, curl, and a shell. In a GitHub Actions beginner guide-style workflow, checkout plus ./bin/go build ./... is a complete build step — the first invocation bootstraps Hermit and the pinned Go automatically. Cache the ~/.cache/hermit directory between runs if you want to skip re-downloading tools on every build.
What Mistakes Do Beginners Make?
The direct answer: seven, and they are all avoidable once you know them:
| Mistake | Why it hurts | Do this instead |
|---|---|---|
Installing tools with bare hermit install go | You get the floating preferred version — drift returns | Always pin: hermit install go-1.27.3 |
Forgetting ~/bin on $PATH | hermit: command not found after installing | Add export PATH="$HOME/bin:$PATH" to your rc file |
| Copying version numbers from old blog posts | Stale pins may not exist or miss security fixes | Run hermit search <tool> and pin a current version |
| Editing the generated wrappers | They are regenerated and checksum-verified — edits get clobbered | Treat bin/ wrappers as read-only; change pins via hermit install |
Not committing bin/ to git | Teammates get none of the benefit — it is just your local setup | git add bin; the repo is the distribution channel |
| Using Hermit for libraries or system packages | That is explicitly out of scope | The FAQ: Hermit is "deliberately not in the business of installing libraries" — reach for Nix for system-level needs |
| Confusing it with dylibso's Hermit | Different product, different problem (portable Wasm) | If the docs mention WASI, you are reading the wrong Hermit |
Sources
- Hermit — official docs home (the "isolated, self-bootstrapping sets of tools" description; wrapper bootstrap behavior)
- Hermit — Get Started (install command,
hermit init, activation, shell hooks) - Hermit — Package management (install selectors
package-version/package@channel,hermit search) - Hermit — FAQ (asdf comparison, Nix comparison, shells bash/zsh/fish, tools-only scope)
- Hermit — Packaging reference (manifest sources, 24-hour sync)
- Hermit manifest schema (pkg.go.dev) (
sha256/sha256-sourcefields, ScriptSHAs) - cashapp/hermit on GitHub (Apache 2.0 license, created 2021-05-20, 948 stars / 120 forks snapshot Nov 2 2026 — moving numbers;
bin/listing with.pkgpin files) - bin/README.hermit.md (the "managed by Hermit... local to this environment" contract)
- lobste.rs — "Hermit manages isolated, self-bootstrapping sets of tools" (founder Q&A: versioning tools in the git repo, opt-in SHA-256, no Nix competition)
- Author's own verification (this run, Nov 2 2026): installed Hermit v0.55.1 via the official installer; ran
hermit init(verifiedbin/contents); ran./bin/hermit version(self-bootstrap works); ranhermit search go(verified go up to 1.27.3, channels @1.27/@latest/@tip).
Frequently Asked Questions
What is Hermit?
Hermit is Cash App's open-source package manager that "manages isolated, self-bootstrapping sets of tools in software projects." It stores exact versions of developer tools — Go, Node, linters, protoc, and more — as wrapper scripts in your repo's bin/ directory, so every developer and CI job uses the same toolchain with zero manual setup.
How do I install Hermit?
Run the official installer: curl -fsSL https://github.com/cashapp/hermit/releases/download/stable/install.sh | /bin/bash. It downloads Hermit into ~/bin (per the docs: "This will download and install hermit into ~/bin"), so add that directory to your $PATH. This guide was verified with Hermit v0.55.1 on the stable channel.
How do I add a tool to my project?
Run hermit init in your project, activate with . ./bin/activate-hermit, search with hermit search <tool>, then pin an exact version, e.g. hermit install go-1.27.3. Always prefer exact versions over channels for a team toolchain. Commit the bin/ directory to git.
Do new contributors need to install anything?
No. They clone the repository and run the bin/ wrappers; each wrapper bootstraps Hermit and auto-installs the pinned package on first run. As the docs put it, each link "will bootstrap Hermit if necessary, then auto-install the package, before executing the binary."
Can Hermit install libraries or system packages like CUDA?
No. The FAQ is explicit: "Hermit is deliberately not in the business of installing libraries… Hermit is deliberately designed to be narrow in scope, limited to just installing existing packages" — development tools only. If you need full OS-level package management, the FAQ itself suggests Nix.