hey
Skill423 starsChanged 8 months agoMITView on GitHub
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.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- basecamp/skillsword for word, first seen Nov 8, 2026
- l3rowniecakez/Claude_Skilltheir own version, first seen Oct 19, 2026
Other versions2 projects use a version of this.
Word for word · 1
- basecamp/skills★ 85100% same
Edited · 0
None found.
Wrote their own version · 1
- l3rowniecakez/Claude_Skill★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/agents.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 3 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 125
Use the installed CLI as the command reference.
- Distinctive: line 138
If the leaf does not exist, read its nearest parent group.
- Very specific: line 146
Treat the leaf's short, long, agent_notes and flags as the source of truth.
- Distinctive: line 147
Run with an explicit output mode, then read structured errors before deciding what to do next.
- Very specific: line 153
Choose the right structured output: Use --jq '<expression>' to filter or extract fields and --json for the full response.
- Very specific: line 155
Linked mail accounts share one login: Use hey account list --json, then --account <id|all> when a task must target one account.
- Very specific: line 156
Local HEY configuration requires human trust: Never run hey config trust-local without the user's explicit approval.
- Very specific: line 217
Contact note: When note_markdown_lossless is true, note_markdown holds the whole note.
- Very specific: line 224
When it is false, the note holds markup Markdown cannot carry.
- Very specific: line 249
Never run the macOS security command to read Keychain contents, print or copy credentials, or move credentials into a file.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/hey - HEY Email Workflow Command
CLI for HEY: mailboxes, labels, collections, email threads, contacts, replies, compose, calendars, todos, habits, time tracking, and journal entries.
Use the installed CLI as the command reference. This skill holds the rules that span commands; it does not copy the command catalog, because the binary's own help is the source of truth and always matches the version you are running.
Discovery-first workflow
For each task:
- Infer the deepest plausible leaf command from the user's words.
Unless its arguments and flags are already established by a tool result in this conversation, read that leaf's help before running it:
hey <group> <subcommand> --agent --helpIf the leaf does not exist, read its nearest parent group. Use root help only when the top-level group itself is unclear:
hey <group> --agent --help # fallback hey --agent --help # last resort hey commands --json # every command with its agent_notes- Treat the leaf's
short,long,agent_notesandflagsas the source of truth. Do not guess positional arguments, flags, accepted values, or limits. - Run with an explicit output mode, then read structured errors before deciding what to do next.
Leaf help is cheap; root help and hey commands --json print the whole catalog and are not. Global flags (--json, --jq, --quiet, --account, --stats) apply wherever a command supports them.
Non-negotiable rules
- Choose the right structured output. Use
--jq '<expression>'to filter or extract fields and--jsonfor the full response. Never pipe to an externaljq;--jqis built in and implies--json. - Reuse stored authentication. Run the requested data command; it uses stored credentials and refreshes expiring OAuth tokens automatically. If it returns an auth error, follow the retry in Authentication before you report the task as blocked. Use
hey auth status --jsonwhen an explicit authentication check is needed (it reports stored credentials and does not contact HEY). Never runhey auth loginunattended; use it only for interactive recovery with the user present. - Linked mail accounts share one login. Use
hey account list --json, then--account <id|all>when a task must target one account. - Local HEY configuration requires human trust. Never run
hey config trust-localwithout the user's explicit approval. - Never resend a send that failed with
not_delivered. See Sending. - Confirm box item mutations. See IDs: HEY does not report IDs that matched nothing.
Output
--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 keep their complete structured envelope. Commands with raw output of their own (auth token, shell-completion generate, setup, skill, tui, --version, and timetrack export without --output) reject --jq. hey watch writes one raw JSON event per line with no envelope and does not apply --jq.
hey box list --jq '.data[] | {id, name}'
hey search "quarterly planning" --jq '.data[].topic_id'
hey box list --quiet --jq '.[].name'- An empty result is an empty array rather than
null, so.data[]is safe on a listing that found nothing. - A field HEY's answer leaves out is left out, never guessed. A posting's
seenis present only when true, so test.seen != truefor unseen. --ids-onlyprints one ID per line and--counta bare number. They work on listings: everylistcommand, the thread listings,hey workflow view,hey search,hey screener history,hey event day|week,hey timetrack categories,hey attachment listandhey thread read(its entries, read from the index without bodies). Both answer for what was read, which is the first page unless--allor--limitreads more, and not every listing warns that more pages exist;hey screener list --countis the exception and counts the whole queue. On thread listings they count the postings, not the box, label or contact around them.--allstops at a page cap, which each listing's help names. A capped read says where to continue:next_pagefor a cursor listing such ashey box view, or thenotice, naming the--pagevalue, for a numbered one such ashey searchorhey contact list. Continue from there rather than treating the list as complete.--htmlwrites the original HTML ofhey thread read,hey journal readand a contact's private note to a pipe or file; a terminal is refused.
IDs
Every email thread has two IDs: id, its box item ID (one posting in one box), and topic_id, its thread ID. Each posting in a thread listing has id, topic_id, kind (bundle for a bundle row), name (subject), created_at and app_url; a thread row also has contacts, summary and visible_entry_count.
- Box item ID (
id):hey seen,unseen,move,label add|remove|create,trash,spam,ignore,stop-ignoring,bubble up|pop,set-aside group,bulk-replyandbundle view. - Thread ID (
topic_id):hey thread read|update|comment,share,unshare,attachment list,reply,forward,compose --thread-id,collection add|removeandworkflow add|move|remove. - Entry ID: an entry's
idfromhey thread read;hey clip createtakes it, and the passage must appear in that message's text. - Contact ID from
hey contact listor contact data, clearance ID fromhey screener list(which also gives thetopic_idof the thread to read before deciding), box ID fromhey box list, label ID fromhey label list. Never substitute one kind for another, or an email address for a contact ID.
Thread listings (hey box view, label view, collection view, bundle view, contact threads, search) carry both IDs, with two exceptions: a bundle row can omit topic_id, and a search result omits id when you have no box item for its thread.
Passing the wrong kind is not redirected. Unmatched IDs are not reported: HEY checks only that some box item ID in a call is yours, and changes every one that matches. hey trash, spam, label add|remove|create and bubble up|pop answer not_found only when none match; hey seen, unseen, move, ignore, stop-ignoring and set-aside group create|add|remove never check (group create with no matching ID leaves an empty group). So a mixed batch is a partial success reported as a whole one, a typo is silently skipped, and a topic_id that happens to equal one of your box item IDs acts on an unrelated thread; likewise a box item ID given to hey thread read can read an unrelated thread. Confirm rather than trust the envelope:
hey box view imbox --json --all --jq '{notice, next_page: .data.next_page, match: [.data.postings[] | select(.id == 12345) | {id, topic_id, seen}]}'for a mark, or read the destination box for a move. An empty match with next_page still set means the box is larger than --all reads: continue with --page <next_page> rather than calling it a non-match.
Bundle rows. A posting whose kind is bundle rolls one sender's mail into one row and names the sender, not a thread. It carries topic_id only while it holds exactly one unseen thread. Never pass a bundle row's id to hey thread read. hey bundle view <id> lists its unseen threads with their topic_id; hey contact threads <contact_id> lists every thread with that sender, seen or not, which is the only place a bundle's mail is listed once read through. Change grouping with hey contact bundle|unbundle <contact_id>.
Sending
- Writing an email for a person goes draft, review, send. Save it with
--draftoncomposeorreply, show the person its From, To, Cc, Bcc, Subject and Body in the conversation (hey draft show <id> --jsonreads it back), change it withhey draft edit <id>as they ask, and runhey draft send <id>when they say to send it. They don't need to open HEY to review it. When the person asks outright for a message to go out,composeorreplywithout--draftsends it in one step. - A send (
compose,reply,forward,draft send) answers the new message'sidand thetopic_idof the thread it landed on; read it withhey thread read <topic_id>. delayed: truemeans Undo Send is still holding it, and HEY leaves it out of its thread until it goes out:hey thread readshows the thread without it, or answersnot_foundfor a thread it started. Wait and read again rather than treating the send as lost.- A send HEY refused (usually the account's sending limit) fails with
not_delivered(exit 7). HEY kept it as a draft, named bydraft_idin the error;hey draft send <draft_id>sends it later. Do not resend the message; that makes a second draft. - A
--draftanswer carries the draft ID forhey draft show|edit|send|deleteand, when the CLI can name it,app_url, the draft's page in HEY. The person can also review and send it from any HEY app. hey thread comment <topic_id> -m "..."adds a note to a thread, which is never emailed but is not private: everyone with access to the thread sees it, HEY for Domains teammates included. The answer lists them invisible_to;--dry-runanswers the same without adding anything. To mail the people on a thread, usehey reply.hey bulk-reply: runpreviewbeforesend. A delivery sent by mistake can be recalled withhey bulk-reply undo <delivery_id>while the window is open.
Writing content
Message bodies, drafts, thread notes, journal entries, snippets and contact notes are Markdown by default (-m, --content, --note, positional content, stdin and $EDITOR alike) and are converted to rich text on the way out; clip passages, event notes and time track notes are plain text. Each Markdown flag has an HTML twin (such as --message-html, --note-html, --content-html) for raw HTML, and each pair is mutually exclusive. A fenced code block's language survives for the languages HEY highlights (Ruby, Python, JavaScript, TypeScript, Go, Rust, Java, C#, C++, PHP, Swift, HTML and CSS); any other is dropped.
Everything a calendar holds is a recording, and each kind has its own command: hey event, hey todo, hey journal, hey habit, hey timetrack. Without a date, those commands read the account's time zone to find today; name the date to skip the account read.
Adding to something written whole
hey contact note set and hey journal write replace the whole note or entry; there is no append. To add, read it, change it, and write all of it back. Keep the &&: a failed read must not go on to write. The read and the write are not atomic, so write straight after reading.
Contact note. When note_markdown_lossless is true, note_markdown holds the whole note; the read checks the flag itself and fails when it is false, so nothing is written:
note=$(hey contact note show 12345 --jq 'if .data.note_markdown_lossless then .data.note_markdown else error("note_markdown would drop part of this note: change note_html with --note-html") end') &&
printf '%s\n\nMoved to the Lisbon office in March.\n' "$note" | hey contact note set 12345When it is false, the note holds markup Markdown cannot carry. Add to the HTML instead:
note=$(hey contact note show 12345 --jq '.data.note_html') &&
hey contact note set 12345 --note-html "$note<p>Moved to the Lisbon office in March.</p>"Journal entry. The same, with content_markdown_lossless; the read also fails for a day with no entry:
entry=$(hey journal read 2026-03-15 --jq 'if .data.content_markdown_lossless then .data.content_markdown else error("content_markdown would drop part of this entry, or there is none: change content with --content-html") end') &&
printf '%s\n\nBooked the venue for the second day.\n' "$entry" | hey journal write 2026-03-15entry=$(hey journal read 2026-03-15 --jq '.data.content // error("no journal entry for this day")') &&
hey journal write 2026-03-15 --content-html "$entry<p>Booked the venue for the second day.</p>"Authentication
Data commands use the credentials HEY already stores and refresh expiring OAuth tokens automatically. Run the requested data command without a login preflight.
If a data command returns exit code 3 with "code": "auth", or fails with could not read stored credentials, authentication is unavailable to that process. On macOS under Codex, the sandbox can hide credentials that the HEY CLI stores in Keychain. Before reporting the task as blocked, use the harness's normal approval flow to retry hey auth status --json once with elevated sandbox permission. Limit the escalation to this one read-only command. If the response's data.authenticated is true, rerun only the exact hey command the user requested through a separate one-command approval. If data.authenticated is false, report the task as blocked and tell the user to run hey auth login in Terminal; do not run it for them unattended. If the status command fails instead, with a keyring error such as exit status 36, the login is not the problem and hey auth login will not fix it: report the task as blocked, relay the error's hint, and stop.
Never run the macOS security command to read Keychain contents, print or copy credentials, or move credentials into a file; never disable the sandbox globally; never set HEY_NO_KEYRING=1 as an authentication workaround.
Piped, machine-output and non-TTY commands do not prompt for sign-in. When an agent harness runs commands under a PTY, set HEY_NONINTERACTIVE=1 so a missing login returns the same actionable auth error instead of opening an interactive prompt.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

