Browse by type
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡿⠏⠻⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣶⣶⣤⠀⠀⠀⣿⠃⠀⠀⠘⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠉⠹⣷⣄⠀⣿⡀⠀⠀⠀⠈⢿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣶⣶⣶⣶⣶⠀⠀⠀⠀⠀⠀⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⡀⠀⠀⠀⠀⢠⣶⣶⣶⣶⣶⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⣿⡆⠀⠘⣿⣦⣿⡇⠀⠀⠀⠀⠘⣿⡆⠀⠀⢀⣀⣀⣀⡀⠀⠸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⣾⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣾⡿⣷⣄⢻⣧⠀⠀⠈⢿⣿⣷⡆⠀⠀⠀⠀⢸⣿⣠⣶⠿⠛⠛⠛⣿⣆⠀⢹⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡏⠉⠉⠉⠉⠉⠉⠙⠻⣿⣿⣿⣿⣆⠀⠀⣸⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠘⢿⣾⣿⡆⠀⠀⠈⢿⣿⣧⠀⠀⠀⠀⠀⣿⣿⠁⠀⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣄⣀⣀⣀⣀⣠⣿⣿⣿⣿⣿⣧⣀⣀⣀⣀⡀⠀⠀⠀⢹⣿⣿⣿⣿⡄⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣷⠀⠀⠻⣿⣿⡄⠀⠀⠈⢿⣿⡆⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⢻⣿⣿⣿⣷⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣇⠀⠀⠘⢿⣷⡀⠀⠀⠘⠻⣿⡀⠀⠀⣿⡏⣿⡇⠀⠀⠀⠀⢸⣿⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣾⡿⢿⣾⣿⣆⠀⠀⠈⢻⣷⡀⠀⠀⠀⠉⠀⠀⢀⣿⠃⢹⣧⠀⠀⠀⠀⣿⡇⠀⢸⣿⣿⣿⣿⠁⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢹⣧⠀⠙⢿⣿⣆⠀⠀⠀⠹⠷⠀⠀⠀⠀⠀⠀⢸⣿⠀⢸⣿⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢿⣧⠀⠀⠙⢿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⢸⣿⠀⠀⢀⣿⠇⠀⢸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⢻⣷⡀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣧⣾⡏⠀⠀⣼⡟⠀⠀⠸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⢿⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⣷⣦⣄⣀⡀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠛⠛⠻⠟⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
A CLI and TUI for HEY.
Read and send emails, manage boxes, calendars, todos, habits, time tracking, and journal entries — all from your terminal.
macOS / Linux / WSL2
curl -fsSL https://hey.com/install-cli | bash
Windows (PowerShell)
irm https://hey.com/install-cli.ps1 | iex
On Windows 11 with Smart App Control, see Troubleshooting if the install is blocked.
hey
The first time you run hey at a terminal it walks you through setup: it signs you in
(browser-based OAuth), shows the mail accounts linked to your HEY identity, and offers to
connect your coding agents (Claude Code, Codex). After that, hey tui opens the app and
bare hey prints the help. hey setup reruns the wizard any time; hey login and
hey logout are shortcuts for hey auth login and hey auth logout.
Logged-out data commands at a terminal (hey boxes, say) offer to sign you in on the spot.
Piped or --json runs never prompt: they fail with Not logged in (exit 3) so scripts and
agents can handle it.
Both scripts download the release for your platform, verify its SHA-256 checksum, and — when cosign is installed — verify the release's keyless Sigstore signature (cosign v3 as-is, v2.6+ with --new-bundle-format=true; older versions skip signature verification with a warning). Set HEY_VERSION to pin a release and HEY_BIN_DIR to choose the install directory.
Other installation methods
Homebrew (macOS / Linux):
brew install --cask basecamp/tap/hey
Arch Linux / Omarchy (AUR):
yay -S hey-cli
Linux (deb/rpm/apk):
# Download from https://github.com/basecamp/hey-cli/releases/latest
sudo apt install ./hey-cli_*_linux_amd64.deb # Debian/Ubuntu
sudo dnf install ./hey-cli_*_linux_amd64.rpm # Fedora/RHEL
sudo apk add --allow-untrusted ./hey-cli_*_linux_amd64.apk # Alpine
Arm64: substitute arm64 for amd64 in the filename. Verify the SHA-256 checksum from checksums.txt before installing unsigned Alpine packages.
Scoop (Windows):
scoop bucket add basecamp https://github.com/basecamp/homebrew-tap
scoop install hey
Nix:
nix profile install github:basecamp/hey-cli
Go install:
go install github.com/basecamp/hey-cli/cmd/hey@latest
From source (requires Go 1.26+; mise installs the right version):
mise install # install Go 1.26
make install # build and install into /usr/local/bin/hey
GitHub Release: download from Releases. Every release ships checksums.txt and a keyless Sigstore signature checksums.txt.bundle, verifiable with:
cosign verify-blob --bundle checksums.txt.bundle \
--certificate-identity "https://github.com/basecamp/hey-cli/.github/workflows/release.yml@refs/tags/v<VERSION>" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com checksums.txt
That command is for cosign v3. With cosign v2.6–v2.x add --new-bundle-format=true; older versions cannot verify the bundle.
hey upgrade
hey upgrade 0.2.0-rc.1 # target a specific release, e.g. a prerelease
Upgrading only ever moves forward: a requested version at or below the installed one is a no-op, and package-manager installs always follow their manager's own version (a pinned version is refused there).
What happens depends on how hey was installed:
~/.local/bin or ~/bin): upgrades in place. hey downloads the release for your platform, verifies its Sigstore signature (the keyless checksums.txt.bundle published by the release pipeline, identity-pinned to the release workflow and tag) and SHA-256 checksum, swaps the executable transactionally, and confirms the installed binary reports the new version. On failure the previous binary is restored; in the worst case — restoration itself fails mid-swap — the error names the preserved backup file next to the binary so you can put it back by hand.brew upgrade --cask basecamp/tap/hey / scoop update hey, then verifies the manager-installed binary actually reports the new version.go install builds: never touched. hey upgrade exits nonzero with upgrade guidance for that install method (the exact command where it can be known, e.g. go install or yay -S hey-cli; otherwise which package manager to use).hey upgrade exits 0 only when there is no update, or the update was applied and confirmed. Every other outcome is a structured failure ("ok": false in JSON) with one of these codes:
| Code | Meaning |
|---|---|
upgrade_required |
An update exists but hey won't apply it for this install method (or this is not a release build) — the hint carries the right next step |
upgrade_incomplete |
The package manager exited 0 but the binary still reports the old version |
upgrade_unverified |
The upgrade may have worked, but the installed version could not be confirmed |
upgrade_failed |
The update check, download, signature/checksum verification, or executable swap failed — the previous binary remains installed (or the error names the preserved backup if restoration also failed) |
hey version prints the installed version; hey version --json adds the commit, build date, Go version and build source (release, go install or dev). hey doctor warns when a newer release is available.
# Browser-based OAuth against HEY's own OAuth server (primary method)
hey auth login
# Or use a pre-generated token
hey auth login --token TOKEN
# Or use a browser session cookie
hey auth login --cookie COOKIE
Tokens refresh automatically on expiry. Credentials are stored in the system keyring (with file fallback at ~/.config/hey-cli/credentials.json).
hey auth status # check auth status
hey auth token # print the bearer token for scripting (refuses a --cookie login)
hey auth refresh # force token refresh
hey auth logout # clear credentials
hey login and hey logout are top-level shortcuts for hey auth login and hey auth logout.
One HEY login exposes every mail account linked to that identity. List the available filters, persist a default, or select one for a single invocation:
hey accounts list # list All Accounts and each linked account
hey accounts use 12345 # persist a linked account as the default mail filter
hey accounts use all # return to All Accounts
hey --account 12345 boxes # override the default for one invocation
HEY_ACCOUNT_ID=12345 hey search "quarterly planning"
The default is all. Selection precedence is --account, HEY_ACCOUNT_ID, trusted local
.hey/config.json, the global default for the active server, then All Accounts. Global
account defaults are stored separately for each server origin, so development and production
selections cannot affect one another. Explicit and persisted IDs are validated against the
signed-in identity before mail requests, so an unavailable account fails closed.
The first command that would use a repository-local server or account setting asks whether to
use it once, always trust its current values, or cancel. Non-interactive and JSON commands fail
closed until you explicitly run hey config trust-local from that directory. Changes to the
local server or account invalidate trust. Review trust with hey config trusted-locals and
remove it with hey config untrust-local.
Compose and contact creation use an individually selected account; replies and forwards use the thread's account. Calendars, todos, habits, time tracking, and journal entries remain identity-wide.
Run hey tui to launch the interactive terminal UI (it offers to sign you in first if
needed). Bare hey prints the help — or, logged out at a terminal, runs first-time setup.
For identities with multiple linked mail accounts, press Ctrl+A to switch between All
Accounts and individual email addresses.
Switching cancels requests from the previous account and reloads the active section;
Calendar and Journal remain identity-wide.
Navigate between Mail, Contacts, Calendar, and Journal. Mail navigation includes HEY boxes plus separate Labels and Collections tabs. Press Shift+L or Shift+K to choose one. Every list keeps going: scroll towards the bottom of a box, label, or collection and the next threads are read in behind you, so there are no pages to step through. Use / to search, Enter to open a thread, r to reply, f to forward, m to move, g to manage labels, k to add or remove the selected thread from collections, t to trash, s to mark as spam, - to ignore, and + to stop ignoring. Select threads with Space and press b to preview every bulk-reply recipient before writing and sending one reply to all selected threads. A delayed bulk reply can be recalled with u while HEY's undo window remains open. Search results retain the matching-message summary and keep going as you scroll, like every other list.
The mail list follows the server. HEY tells the TUI when a box changed over the same
Action Cable connection hey watch uses, and the box on screen is read again a moment
later, keeping your place in the list and anything you had selected. A change that arrives
while a form or a picker is open waits for it to close. Press Ctrl+R to read the box again
yourself; if the connection goes away for good, the list says so and Ctrl+R is how you
catch up.
The Screener keeps up too. When a first-time sender writes, the count above the threads changes on its own, and if you have The Screener open the new sender appears in the queue without moving your place in it.
Press Ctrl+S from the mail list to open The Screener. When senders are waiting, the mail
list says so above the threads. In The Screener, y screens the selected sender in and n
screens them out, Tab moves to Screener History and back, X clears the whole Screener
after a confirmation, and Escape or q returns to mail. Both lists keep going as you
scroll, the same way the mail list does.
The Imbox can wear cover art, the way the HEY web app does: everything you have already
read goes under it, so the box ends at what still wants your attention instead of trailing
off into a month of receipts. The divider stays and says how much is under there — press
v to peek, v again to close it.
Press Ctrl+V to choose one: blobs, grid, peace, terrazzo, topo or waves, the
same six covers redrawn as characters, so they work in any terminal rather than only the
ones that can show images. The picker draws whichever you have highlighted. They are
painted in your terminal's own colors, so a cover matches your theme and follows it when
you switch.
Your choice is remembered in ~/.config/hey-cli/config.json, on this machine. It is not
the cover you picked on the web: HEY keeps that one server-side but serves it to nobody, so
the iOS and Android apps each keep their own local choice too, and this is the same.
Thread attachments always appear with their filename, media type, and size. Use [ and ] to select an attachment, s to save it without replacing an existing file, and o to download and open it in an external application. Attachments never open automatically. Kitty and Ghostty can show inline images. Foot and other terminals use visible text markers.
Press Shift+O to open Contacts. Use Enter to view a contact, a to add, e to edit, n to edit the private note, x twice to delete a note, h to hide, and u to show the most recently hidden contact again. Escape or q goes back.
Press Shift+C to open Calendar, then c to manage time track categories. Create a category with n, rename the selected category with Enter or r, and press x twice to delete it. Time tracks in a deleted category become uncategorized.
In Calendar, press a to create a habit. Habits visible in the current calendar range can be selected with [ and ], edited with e, and deleted by pressing x twice. Habit forms use Tab to move between fields and Ctrl+S to save.
Structured data commands support --json for full output and --jq '<expression>' to
filter that output without an external jq binary. --jq implies --json and filters
th
browse all types & interfaces →
$ claude mcp add hey-cli \
-- python -m otcore.mcp_server <graph>