Updating
Hain ships a built-in updater. There’s no need to re-run the curl installer to upgrade; hain update does it in place.
The TL;DR
hain update # upgrade to the latest release on your channel
hain update --check # see what's available without installing
hain update --rollback # go back to the previous version
How the updater works
When you installed Hain, the curl script unpacked the release into a versioned directory and pointed a symlink at it:
~/.local/share/hain/
├── versions/
│ └── 0.1.0-beta.1/
├── current → versions/0.1.0-beta.1
└── state.json
~/.local/bin/hain is a symlink that resolves through current/bin/hain. Running hain update:
- Reads
state.jsonto find your installed version and channel. - Queries the GitHub Releases API for the latest matching release.
- Downloads the tarball, verifies its SHA256.
- Extracts to a staging directory, then runs a smoke test (
hain-cli --version). - Promotes the staged directory to
versions/<new-version>/. - Atomically re-points the
currentsymlink at the new version.
Your existing version stays on disk in versions/, which is what makes --rollback work.
Channels
The channel is fixed at install time:
- A version with a prerelease suffix (e.g.
0.1.0-beta.1) pins the install to beta. - A version without (e.g.
0.1.0) pins the install to stable.
hain update only follows the channel you installed on. To switch channels (for example, from beta to a new stable line), re-run the curl installer with the desired version:
curl -fsSL https://raw.githubusercontent.com/hainlabs/hain-releases/main/install.sh | bash -s -- --version 0.1.0
This is deliberate. hain update won’t ever cross channels on you.
Beta users get notified when stable ships
When a stable release becomes available, beta installs surface a one-line notice on next launch (CLI and TUI) telling you the curl command to switch channels. The in-channel updater stays unchanged. Stable installs are never pushed to beta.
Rollback
hain update --rollback
Repoints current at the previously installed version (as recorded in state.json.previousVersion). If the previous version directory has been pruned, the command refuses with a clear message.
Listing installed versions
hain update --list-installed
Shows what’s still on disk under versions/, marks the current and previous, and reports sizes.
Update notifications
The CLI runs a 24-hour-throttled background check on startup and prints a one-line stderr notice when a newer release is cached:
A new beta release of hain is available: 0.1.0-beta.3 (current: 0.1.0-beta.1).
Run `hain update` to upgrade. Set HAIN_NO_UPDATE_CHECK=1 to suppress this notice.
The notice is suppressed:
- when
HAIN_NO_UPDATE_CHECK=1is set - in
--output stdoutmode (so scripts and LLM tooling stay deterministic) - when stderr isn’t a TTY
- when the user is already running
hain update
The TUI displays the same information as a small text in the status bar.
What the updater never touches
- Your config (
~/.config/hain/) - Your vault directory or the files in it
- The data of any space (every space’s
.context/directory lives inside the folder you designated for that space, wherever that is on disk)
Updates only swap the application binaries.
Disk usage
After a successful update, the previous version is retained for rollback. Older versions are pruned automatically. Each version directory is around 120 MB, so a typical install holds 240 MB across current and previousVersion.
Pass --no-prune to keep older versions:
hain update --no-prune
Currently running TUI or watcher?
hain update works while another hain process is running. The new files go to a different directory; nothing the old process is using gets touched. After the swap, restart any running TUI or watcher to pick up the new version.
Environment variables
| Name | Effect |
|---|---|
HAIN_NO_UPDATE_CHECK=1 | Suppress the 24h background check and the launch-time notice |
HAIN_INSTALL_DIR | Override the install directory (default ~/.local/share/hain) |
HAIN_BIN_DIR | Override the symlink directory (default ~/.local/bin) |
GH_TOKEN / GITHUB_TOKEN | Authenticate API requests to avoid the 60-req/hour anonymous limit |