MCPcopy Create free account
hub / github.com/basecamp/hey-cli

github.com/basecamp/hey-cli @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
771 symbols 2,628 edges 94 files ⚖ MIT 232 documented · 30% updated 3d ago★ 11819 open issues

Browse by type

Functions 651 Types & classes 120
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

hey-cli

⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡿⠏⠻⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣶⣶⣤⠀⠀⠀⣿⠃⠀⠀⠘⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠉⠹⣷⣄⠀⣿⡀⠀⠀⠀⠈⢿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣶⣶⣶⣶⣶⠀⠀⠀⠀⠀⠀⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⡀⠀⠀⠀⠀⢠⣶⣶⣶⣶⣶⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⣿⡆⠀⠘⣿⣦⣿⡇⠀⠀⠀⠀⠘⣿⡆⠀⠀⢀⣀⣀⣀⡀⠀⠸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⣾⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣾⡿⣷⣄⢻⣧⠀⠀⠈⢿⣿⣷⡆⠀⠀⠀⠀⢸⣿⣠⣶⠿⠛⠛⠛⣿⣆⠀⢹⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡏⠉⠉⠉⠉⠉⠉⠙⠻⣿⣿⣿⣿⣆⠀⠀⣸⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠘⢿⣾⣿⡆⠀⠀⠈⢿⣿⣧⠀⠀⠀⠀⠀⣿⣿⠁⠀⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣄⣀⣀⣀⣀⣠⣿⣿⣿⣿⣿⣧⣀⣀⣀⣀⡀⠀⠀⠀⢹⣿⣿⣿⣿⡄⢰⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣷⠀⠀⠻⣿⣿⡄⠀⠀⠈⢿⣿⡆⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⢻⣿⣿⣿⣷⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣇⠀⠀⠘⢿⣷⡀⠀⠀⠘⠻⣿⡀⠀⠀⣿⡏⣿⡇⠀⠀⠀⠀⢸⣿⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣾⡿⢿⣾⣿⣆⠀⠀⠈⢻⣷⡀⠀⠀⠀⠉⠀⠀⢀⣿⠃⢹⣧⠀⠀⠀⠀⣿⡇⠀⢸⣿⣿⣿⣿⠁⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢹⣧⠀⠙⢿⣿⣆⠀⠀⠀⠹⠷⠀⠀⠀⠀⠀⠀⢸⣿⠀⢸⣿⠀⠀⠀⢸⣿⠀⠀⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣽⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢿⣧⠀⠀⠙⢿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⢸⣿⠀⠀⢀⣿⠇⠀⢸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠈⢻⣷⡀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣧⣾⡏⠀⠀⣼⡟⠀⠀⠸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢻⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⢿⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⣷⣦⣄⣀⡀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠛⠛⠻⠟⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

A CLI and TUI for HEY.

Read and send emails, manage boxes, calendars, todos, habits, time tracking, and journal entries — all from your terminal.

Install

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.

Getting started

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.

Upgrading

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:

  • Installer script / tarball (a binary under your home directory, e.g. ~/.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.
  • Homebrew / Scoop: delegates to brew upgrade --cask basecamp/tap/hey / scoop update hey, then verifies the manager-installed binary actually reports the new version.
  • System packages (apt/dnf/apk, AUR, Nix) and 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.

Authentication

# 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.

Linked accounts

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.

TUI

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.

CLI Commands

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

Extension points exported contracts — how you extend this code

browse all types & interfaces →

Core symbols most depended-on inside this repo

browse all functions →

Shape

Function 487
Method 164
Struct 108
TypeAlias 9
FuncType 2
Interface 1

Languages

Go100%

Modules by API surface

internal/tui/mail.go29 symbols
internal/tui/calendar_views.go27 symbols
internal/tui/calendar.go24 symbols
tests/smoke/helpers_test.go23 symbols
internal/tui/mail_test.go22 symbols
internal/output/writer.go22 symbols
internal/cmd/sdk.go21 symbols
internal/tui/tui_test.go20 symbols
internal/tui/tui.go18 symbols
internal/auth/store.go18 symbols
internal/tui/journal.go17 symbols
internal/config/config.go17 symbols

For agents

$ claude mcp add hey-cli \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page