/hey - HEY Email Workflow Command

SkillCommunication

Interact with HEY via the HEY CLI. Read and send emails, manage contacts, boxes, labels, collections, calendars, todos, habits, time tracking, and journal entries. Use for ANY HEY-related question or action.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the /hey - HEY Email Workflow Command skill

What this skill tells your AI

The instructions your AI receives, as published by basecamp/hey-cli in skills/hey/SKILL.md and read by ahel’s review.

CLI for HEY: mailboxes, labels, collections, email threads, contacts, replies, compose, calendars, todos, habits, time tracking, and journal entries.

Agent Invariants

MUST follow these rules:

  1. Choose the right structured output — use --jq '<expression>' to filter or extract fields and --json for the full response. Never pipe to an external jq; --jq is built in and implies --json.
  2. Reuse stored authentication — run the requested data command; it uses stored credentials and refreshes expiring OAuth tokens automatically. If it returns an auth error, report the task as blocked. Use hey auth status --json when an explicit authentication check is needed. Never run hey auth login unattended; use it only for interactive recovery with the user present.
  3. HTML output is available via --html for commands that return HTML content
  4. Linked mail accounts share one login — use hey account list --json, then --account <id|all> when a task must target one account
  5. Local HEY configuration requires human trust — never run hey config trust-local without the user's explicit approval

Output Filtering

--jq filters the full JSON success envelope, so result data is under .data. String results print as plain text; objects and arrays print as formatted JSON. Use --quiet --jq when the expression should run against result data directly. Errors retain their complete structured envelope. Commands with dedicated raw output (auth token, completion, skill, tui, and --version) reject --jq.

hey box list --jq '.data[] | {id, name}'
hey search "quarterly planning" --jq '.data[].id'
hey box list --quiet --jq '.[].name'

An empty result is an empty array rather than null, so .data[] is safe to run against a listing that found nothing.

For the two commonest shapes there is no need for an expression at all: --ids-only prints one ID per line and --count prints a bare number, both on stdout with any pagination notice on stderr. Both need list data, so they work on hey box list, hey box view, hey label list, hey label view, hey collection list, hey collection view, hey workflow list, hey workflow view, hey clip list, hey snippet list, hey draft list, hey search, hey contact list, hey screener list, hey screener history, hey calendar list, hey event list, hey event day, hey event week, hey todo list, hey habit list, hey timetrack list, hey journal list and hey attachment list. On hey box view they count and list its postings, not the box itself.

Quick Reference

TaskCommand
List linked mail accountshey account list --json
Set default mail accounthey account use <id|all>
Run once for one accounthey --account <id> box list --json
Review trusted local settingshey config trusted-locals --json
Trust this repository's settingshey config trust-local (requires explicit user approval)
List mailboxeshey box list --json
List emails in a boxhey box view imbox --json
List labelshey label list --json
List emails with a labelhey label view <label_id> --all --json
Add a label to a threadhey label add <id> --to <label_id>
Create and add a labelhey label create "Travel receipts" <id>
Remove labelshey label remove <id> --from <label_id|all>
List collectionshey collection list --json
List collection threadshey collection view <collection_id> --all --json
Create a collectionhey collection create "Kitchen remodel"
Update a collectionhey collection update <collection_id> --name "Kitchen renovation"
Add a thread to a collectionhey collection add <topic_id> --to <collection_id>
Remove a thread from a collectionhey collection remove <topic_id> --from <collection_id>
List Set Aside threads with their grouphey set-aside view --all --json
List Set Aside groupshey set-aside group list --json
List a group's threadshey set-aside group view <group_id> --json
Gather threads into a new grouphey set-aside group create <id> <id>
File threads into a grouphey set-aside group add <id> --to <group_id>
Take threads out of their grouphey set-aside group remove <id>
Break a group uphey set-aside group delete <group_id>
List workflowshey workflow list --json
View workflow stageshey workflow view <workflow_id> --json
List clipshey clip list --json
List snippetshey snippet list --json
Search emailhey search "quarterly planning" --json
List search filtershey search filters --json
List contactshey contact list --json
View contacthey contact show <id> --json
Add contacthey contact add --name "Jane Doe" --email jane@example.com
Edit contacthey contact update <id> --name "Jane Dawson"
Hide contacthey contact hide <id>
Show contact againhey contact show-again <id>
Bundle a contact's mailhey contact bundle <id>
List a contact's mail separatelyhey contact unbundle <id>
Read private contact notehey contact note show <id> --json
Set private contact notehey contact note set <id> "Prefers email"
Delete private contact notehey contact note delete <id>
Read email threadhey thread read <topic_id> --json
Get a sharing linkhey share <thread_id>
Turn off a sharing linkhey unshare <thread_id>
Reply to emailhey reply <topic_id> -m "Friday works for me."
Forward emailhey forward <topic_id> --to alice@example.com -m "For your review"
Compose emailhey compose --to alice@example.com --subject "Lunch plans" -m "Are you free Friday?"
Compose with CC/BCChey compose --to alice@example.com --cc bob@example.com --bcc carol@example.org --subject "Kitchen remodel timeline"
List draftshey draft list --json (--all/--page follow the cursor)
Draft an email for human reviewhey compose --to alice@example.com --subject "Lunch plans" -m "Free Friday?" --draft
Draft a reply for human reviewhey reply <topic_id> -m "Drafting this." --draft
Read a draft backhey draft show <draft_id> --json
Change a drafthey draft edit <draft_id> --to alice@example.com --subject "New subject"
Send a drafthey draft send <draft_id>
Trash draftshey draft delete <draft_id>...
Who is waiting in The Screenerhey screener list --json (clearance IDs)
Number waitinghey screener list --count
Let a sender throughhey screener approve <clearance_id>
Turn a sender awayhey screener deny <clearance_id>
Who was already screenedhey screener history --json
Preview a bulk replyhey bulk-reply preview <id> <id> --json
Send a bulk replyhey bulk-reply send <id> <id> -m "Thanks for the update."
Recall a bulk replyhey bulk-reply undo <delivery_id>
List calendarshey calendar list --json
List calendar eventshey event list --json
Today's schedule, recurrences expandedhey event day --json
Add a calendar eventhey event add "Design review" --starts-on 2026-09-02 --start-time 14:00
List todoshey todo list --json
Add todohey todo add "Draft the quarterly report"
Complete todohey todo complete 123
Uncomplete todohey todo uncomplete 123
Delete todohey todo delete 123
Wait for new mailhey watch --box imbox --exit-on-first
Follow every changehey watch
Mark as seenhey seen 12345
Mark as unseenhey unseen 12345
Move email threadshey move 12345 --to feed
Remove Reply Laterhey move 12345 --to imbox
Bubble a thread up nowhey bubble up 12345 --now
Bubble a thread up on a datehey bubble up 12345 --on 2026-09-04
Bubble a thread up this weekendhey bubble up 12345 --weekend
List bubbled-up and scheduled threadshey bubble list --json
Cancel a bubble-uphey bubble pop 12345
Move email threads to Trashhey trash 12345
Mark email threads as spamhey spam 12345
Ignore email threadshey ignore 12345
Stop ignoring email threadshey stop-ignoring 12345
List habitshey habit list --json
Create habithey habit create "Morning strength training"
Edit habithey habit edit 123 --days mon,wed,fri
Delete habithey habit delete 123
Complete habithey habit complete 123
Uncomplete habithey habit uncomplete 123
Start time trackinghey timetrack start
Stop time trackinghey timetrack stop
Current timerhey timetrack current --json
List time entrieshey timetrack list --json
Export completed time entrieshey timetrack export > tracked-time.csv (--json etc. need --output)
Save a time tracking exporthey timetrack export --output tracked-time.csv --json
List time track categorieshey timetrack categories --json
Create time track categoryhey timetrack category create "Client work"
List journal entrieshey journal list --json
Read journal entryhey journal read 2024-03-15 --json
Write journal entryhey journal write "Shipped the pagination fix." (empty content removes the entry)
Check auth statushey auth status --json
Print bearer tokenhey auth token (refuses a --cookie login)
Launch TUIhey tui (Ctrl+A switches linked mail accounts)

Decision Trees

Reading Email

Want to read email?
├── Which mailbox? → hey box list --json
├── List emails in box? → hey box view <name|id> --json
├── List labels or labeled email? → hey label list --json / hey label view <label_id> --json
├── Add, create, or remove a label? → hey label add|create|remove
├── List collections or collection threads? → hey collection list --json / hey collection view <collection_id> --json
├── Create, update, add to, or remove from a collection? → hey collection create|update|add|remove
├── See Set Aside with its groups? → hey set-aside view --all --json / hey set-aside group list --json
├── Group, regroup, or ungroup Set Aside threads? → hey set-aside group create|add|remove|delete
├── Search threads and messages? → hey search <query> --json
├── Need available refinements? → hey search filters --json
├── List or view contacts? → hey contact list --json / hey contact show <id> --json
├── Read full thread? → hey thread read <topic_id> --json
├── Get a sharing link? → hey share <thread_id>
├── Turn off the sharing link? → hey unshare <thread_id>
├── Mark as seen? → hey seen <id>
├── Mark as unseen? → hey unseen <id>
├── Move to another box? → hey move <id> --to <box>
├── Remove or unmark Reply Later? → hey move <id> --to imbox
├── Move to Trash? → hey trash <id>
├── Mark as spam? → hey spam <id>
├── Ignore future activity? → hey ignore <id>
├── Stop ignoring? → hey stop-ignoring <id>
├── Who is waiting to be screened? → hey screener list --json
├── Screen a sender in or out? → hey screener approve|deny <clearance_id>
└── Launch interactive UI? → hey tui

Sending Email

Want to send email?
├── Reply to thread? → hey reply <topic_id> -m "message"
│   ├── Open editor? → hey reply <topic_id> (omit -m to open $EDITOR)
│   └── Attach files? → add --attach ./report.pdf (repeatable)
├── Reply to many threads at once? → hey bulk-reply preview <id>... first, then send
│   └── Sent by mistake? → hey bulk-reply undo <delivery_id> (while the window is open)
├── Forward latest message? → hey forward <topic_id> --to <email>
│   └── Add a note? → add -m "note"
├── Compose new? → hey compose --to <email> --subject "Subject"
│   ├── With body? → hey compose --to <email> --subject "Subject" -m "Body"
│   ├── With files? → add --attach ./report.pdf (repeatable; body is optional)
│   ├── With CC? → add --cc <email>
│   └── With BCC? → add --bcc <email>
├── List files in a thread? → hey attachment list <topic_id> --json
│   └── Save one? → hey attachment save <attachment_id> [--output <path>]
├── Draft instead of sending (human reviews in HEY)? → add --draft to compose or reply; the answer carries the draft id
│   ├── Read it back? → hey draft show <draft_id> --json
│   ├── Change it? → hey draft edit <draft_id> --subject/--to/--cc/--bcc/-m (flags replace; omitted fields are kept)
│   ├── Deliver it? → hey draft send <draft_id> (recipients required)
│   └── Discard it? → hey draft delete <draft_id>
└── Check drafts? → hey draft list --json

Managing Todos

Want to manage todos?
├── List todos? → hey todo list --json
├── Add todo? → hey todo add "Task description"
├── Complete? → hey todo complete <id>
├── Uncomplete? → hey todo uncomplete <id>
└── Delete? → hey todo delete <id>

Resource Reference

Email - Boxes

hey box list --json                          # List all mailboxes
hey box view imbox --json                    # List emails in Imbox (by name)
hey box view 123 --json                      # List emails in box (by ID)
hey box view imbox --page next-cursor --json # Continue from an earlier listing

Box names: imbox, feedbox, trailbox, asidebox, laterbox, bubblebox

Response format: hey box view --json returns the box itself — id, kind, name, app_url, next_history_url, next_page — with a postings array of the email threads in it. Each posting has: id (box item ID), topic_id (thread ID), name (subject), seen (read status), created_at, contacts, summary, app_url, visible_entry_count. Use id for hey seen, hey unseen, hey move, hey label add, hey label remove, hey trash, hey spam, hey ignore, and hey stop-ignoring, and topic_id for hey thread read, hey reply, hey forward, hey share and hey attachment list. A box item id passed to hey thread read answers not_found, and so does a topic_id passed to hey move.

A posting that bundles a contact's mail into one row can omit topic_id: a bundle names its sender rather than a thread, and its name joins the bundled subjects with . A bundle that does carry a topic_id opens as that thread — its one unseen thread — and hey threads reads it as usual. For a bundle without one, never substitute the box item id (hey threads <id> answers not_found); there is no command that lists the threads inside a bundle, so run hey contacts unbundle <contact_id> — the contact is in the posting's contacts — to list that sender's mail as separate rows, or direct the user to open the bundle in HEY.

next_page is the cursor --page takes, and it is the cursor inside next_history_url--page accepts either. --all reads to the end instead.

--ids-only and --count work here too, and answer for the postings: one box item ID per line, or how many threads were read.

Email - Labels

hey label list --json                         # List labels and stable IDs
hey label view 789 --all --json                # List every thread with a label
hey label add 12345 --to 789                   # Add an existing label
hey label create "Travel receipts" 12345       # Create and add a label
hey label remove 12345 --from 789              # Remove one label
hey label remove 12345 --from all              # Remove every label

Label mutations take box item IDs from hey box view, hey label view, or active hey search results. Label IDs come from hey label list. hey label view returns next_page and total_count; pass --page <next_page> to continue or --all to fetch every page. HEY creates a label while adding it to at least one thread, so label create requires one or more thread item IDs.

Email - Collections

hey collection list --json                                 # List collections and stable IDs
hey collection view 321 --all --json                        # List every thread in a collection
hey collection create "Kitchen remodel" --summary "Plans and decisions"
hey collection update 321 --name "Kitchen renovation"
hey collection add 987 --to 321                             # Add a topic ID
hey collection remove 987 --from 321                        # Remove a topic ID

Collection IDs come from hey collection list. hey collection view returns posting id, thread topic_id, next_page, and total_count; pass --page <next_page> to continue or --all to fetch every page. Collection membership commands take topic_id. Creating a collection confirms the mutation, and listing collections provides its ID for later commands.

Email - Set Aside groups

hey set-aside view --all --json                # Set Aside threads, each with box_group_id when grouped
hey set-aside group list --json                # Groups with thread_count
hey set-aside group view 42 --all --json       # Threads in one group; pages like a box
hey set-aside group create 12345 67890         # New group from box item IDs; answers the group id
hey set-aside group add 12345 --to 42          # File threads into a group (moves them out of another)
hey set-aside group remove 12345               # Ungroup; threads stay in Set Aside
hey set-aside group delete 42                  # Dissolve the group; its threads go to Previously Seen

Groups have no name in HEY: a group is its ID and the threads in it. Group commands take posting id values (box item IDs), not topic_id. HEY's group index answers IDs alone, so group list reads each group once for its count; group view returns next_page and total_count and takes --page and --all. HEY removes a group itself once its last thread leaves, so group view or group delete on it answers not_found. group create moves threads into Set Aside if they are in another box. To clear an overflowing Set Aside without losing threads, prefer group create/group add over group delete: deleting a group moves its threads to Previously Seen in the Imbox.

Email - Search

hey search "quarterly planning" --json         # Free-text search
hey search --from jane@example.com --date last_30_days --json  # Refined search
hey search --subject invoice --attachment pdfs --all --json    # Search up to 100 pages
hey search filters --json                      # Available box, date, label, and attachment values

Search refinements are --required, --any, --none, --exact, --from, --to, --subject, --date, --in, --label, and --attachment. --page selects one result page; --all fetches up to 100 pages from that point onward. When the cap is reached, the response notice provides the next --page value for continuation.

--in, --date, --label and --attachment accept only the values hey search filters lists: boxes are imbox, feed, papertrail, trash; dates are last_7_days, last_30_days, last_90_days or a four-digit year; attachment kinds are any, images, pdfs, calendar_invites, documents, spreadsheets, presentations, media, zip_files. The kinds are plural — --attachment pdfs, not pdf. An unrecognized --in, --date or --attachment is refused as a usage error naming the values it accepts, before anything is sent; --label is not checked, so read hey search filters when unsure of a label.

Response format: data contains one item per matching thread. Each result has id (box item ID for organization actions), topic_id (thread ID for hey thread read, hey reply, and hey forward), subject, updated_at, and messages containing the matching message IDs, senders, dates, and summaries. A result can omit id when the thread has no active box item.

Contacts

hey contact list --json                       # List contacts
hey contact list --page 2 --json              # List another page
hey contact show 12345 --json                 # View details, aliases, and private note
hey contact add --name "Jane Doe" --email jane@example.com
hey contact add --name "Jane Doe" --email jane@example.com --alias jane.doe@example.org
hey contact update 12345 --name "Jane Dawson"
hey contact update 12345 --alias=              # Clear aliases
hey contact hide 12345                         # Hide from lists and autocomplete
hey contact show-again 12345                   # Reverse hiding
hey contact bundle 12345                       # Group this contact's mail into one row
hey contact unbundle 12345                     # List this contact's mail separately
hey contact note show 12345 --json
hey contact note set 12345 "Prefers email"
echo "Multiline private note" | hey contact note set 12345
hey contact note delete 12345

hey contact list returns contact IDs, names, email addresses, and update timestamps. hey contact show adds aliases, screening status, and the private note. Contact updates preserve omitted fields. Supplying --alias replaces the complete alias list, and --alias= clears it.

HEY hides contacts instead of permanently deleting them. A hidden contact leaves contact lists, autocomplete, and search results while remaining available by ID; show-again reverses the action. Bundling groups a contact's mail into one row without merging or deleting the underlying threads; unbundle lists those threads separately again. HEY applies bundling when the contact's current delivery setting supports bundles. Contact notes are private and support positional content, --note, stdin, or $EDITOR. Deleting a note leaves the contact unchanged.

Email - Threads

hey thread read <topic_id> --json                 # Read full email thread
hey thread read <topic_id> --html                 # Read with raw HTML content
hey share <thread_id>                         # Get a sharing link
hey unshare <thread_id>                       # Turn off the sharing link

hey thread read returns every entry in the thread, oldest first. Each entry's body is Markdown, converted from HEY's Trix HTML at the edge, so headings, lists, quotes, tables and code survive and links keep their URLs — read it as structure rather than as flattened text. --html returns the original HTML instead. There is no recipients field on an entry; use hey reply, which works the addressing out itself.

hey share returns a URL that shows the entire thread and future emails or replies sent to it. Anyone with the link can open it. hey unshare turns off the sharing link.

ID note: Every email thread has two IDs: an id (its box item ID) and a topic_id (its thread ID). hey seen, hey unseen, hey move, hey label add, hey label remove, hey trash, hey spam, hey ignore, and hey stop-ignoring expect id. hey thread read, hey share, hey unshare, hey attachment list, hey reply, hey forward, hey collection add, and hey collection remove expect topic_id. Passing the wrong one answers not_found, not a redirect.

hey box view --json, hey label view --json, hey collection view --json and hey search --json all carry both — except a bundle posting, which can omit topic_id (see the Boxes section).

Email - Attachments

hey attachment list <topic_id> --json               # List files in every message
hey attachment save 67890:1                    # Save using a returned ID
hey attachment save 67890:1 --output ./reports # Save into a directory
hey attachment save 67890:1 --output ./report.pdf --force

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
366
Forks
44
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
hey
Source
github.com/basecamp/hey-cli