关于 hey
hey skill 为 Agent 使用 HEY CLI 提供操作指引,涵盖邮件、联系人、日历项目及相关工作流。它强调查阅命令帮助、正确处理 ID、明确选择输出模式,并遵守认证和邮件发送方面的安全规则。
主要功能
- 01按命令查阅帮助
- 02邮件、联系人与日历工作流
- 03结构化输出与筛选
- 04ID 与分页安全规则
- 05发送邮件与认证规则
适用场景
- 01为任务查找合适的 HEY 命令
- 02阅读或整理邮件会话
- 03创建或查看日历项目
- 04遵循发送保护规则撰写邮件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ basecamp/ skills --skill hey安装后在 Claude Code 中输入/hey确认已加载。
详细介绍
/hey - HEY 邮件工作流命令
HEY 命令行工具:邮箱、标签、集合、邮件会话、联系人、回复、撰写、日历、待办事项、习惯、时间跟踪和日志条目。
请将已安装的命令行工具用作命令参考。本技能包含适用于各命令的规则;不复制命令目录,因为二进制文件自带的帮助信息才是权威来源,并且始终与当前运行的版本一致。
先探索的工作流
对于每项任务:
-
根据用户的描述,推断最可能的最深层叶子命令。
-
除非本次对话中的工具结果已明确其参数和标志,否则先查看该叶子命令的帮助,再运行它:
hey <group> <subcommand> --agent --help -
如果该叶子命令不存在,则查看最近的父命令组。只有在无法确定顶层命令组时,才查看根命令的帮助:
hey <group> --agent --help # fallback hey --agent --help # last resort hey commands --json # every command with its agent_notes -
将叶子命令的
short、long、agent_notes和flags视为权威信息。不要猜测位置参数、标志、可接受的值或限制。 -
使用明确的输出模式运行命令,然后先查看结构化错误,再决定下一步操作。
查看叶子命令的帮助开销很小;根命令的帮助和 hey commands --json 会打印整个目录,开销较大。全局标志(--json、--jq、--quiet、--account、--stats)适用于支持它们的所有命令。
不可妥协的规则
- 选择正确的结构化输出。 使用
--jq '<expression>'筛选或提取字段,使用--json获取完整响应。切勿通过管道传给外部jq;--jq是内置功能,并且会隐式启用--json。 - 复用已存储的身份验证信息。 运行用户请求的数据命令;它会使用已存储的凭据,并自动刷新即将过期的 OAuth 令牌。如果返回身份验证错误,请先按照身份验证中的重试步骤操作,再报告任务受阻。需要明确检查身份验证时,使用
hey auth status --json(它会报告已存储的凭据,不会联系 HEY)。无人值守时切勿运行hey auth login;仅在用户在场时将其用于交互式恢复。 - 已关联的邮件账户共用一次登录。 使用
hey account list --json,然后在任务需要针对某个账户时使用--account <id|all>。 - 本地 HEY 配置需要获得用户信任。 未经用户明确批准,切勿运行
hey config trust-local。 - 发送失败并返回
not_delivered时,切勿重新发送。 请参阅发送。 - 修改邮箱项目时先确认。 请参阅ID:HEY 不会报告未匹配到任何项目的 ID。
输出
--jq 会筛选完整的 JSON 成功响应封装,因此结果数据位于 .data 下。字符串结果会以纯文本形式打印;对象和数组会以格式化后的 JSON 形式打印。如果表达式应直接作用于结果数据,请使用 --quiet --jq。错误会保留完整的结构化响应封装。具有自身原始输出的命令(auth token、shell-completion generate、setup、skill、tui、--version,以及不带 --output 的 timetrack export)不接受 --jq。hey watch 每行写入一个原始 JSON 事件,不带响应封装,也不应用 --jq。
hey box list --jq '.data[] | {id, name}'
hey search "quarterly planning" --jq '.data[].topic_id'
hey box list --quiet --jq '.[].name'
- 空结果是空数组,而不是
null,因此在没有找到任何内容的列表上使用.data[]是安全的。 - HEY 的回答中未包含的字段会保持缺省,不会猜测补全。帖子的
seen仅在值为 true 时才会出现,因此可用.seen != true检查未读项。 --ids-only每行打印一个 ID,--count则只打印一个数字。它们适用于列表:所有list命令、主题列表、hey workflow view、hey search、hey screener history、hey event day|week、hey timetrack categories、hey attachment list,以及hey thread read(其条目从索引读取,不含正文)。两者都只针对已读取的内容返回结果;除非使用--all或--limit读取更多内容,否则读取的都是第一页。并非所有列表都会提示还有更多页面;例外是hey screener list --count,它会统计整个队列。对于主题列表,它们统计的是帖子数量,而不是帖子周围的邮箱、标签或联系人数量。--all会在达到页面上限时停止,具体上限可在各列表的帮助中查看。达到上限的读取会说明如何继续:对于hey box view这类游标列表,使用next_page;对于hey search或hey contact list这类编号列表,则根据notice中指出的--page值继续。请从那里继续,而不要将列表视为完整列表。--html会将hey thread read、hey journal read和联系人私人备注的原始 HTML 写入管道或文件;不允许写入终端。
ID
每个邮件线程都有两个 ID:id,即其邮箱条目 ID(某个邮箱中的一封邮件),以及 topic_id,即其线程 ID。线程列表中的每封邮件都包含 id、topic_id、kind(汇总行时为 bundle)、name(主题)、created_at 和 app_url;线程行还包含 contacts、summary 和 visible_entry_count。
- 邮箱条目 ID(
id):hey seen、unseen、move、label add|remove|create、trash、spam、ignore、stop-ignoring、bubble up|pop、set-aside group、bulk-reply和bundle view。 - 线程 ID(
topic_id):hey thread read|update、share、unshare、attachment list、reply、forward、compose --thread-id、collection add|remove和workflow add|move|remove。 - 邮件条目 ID:来自
hey thread read的邮件条目id;hey clip create需要此 ID,且邮件正文中必须包含对应片段。 - 来自
hey contact list或联系人数据的联系人 ID、来自hey screener list的审核 ID(其中还会提供决策前要读取的线程的topic_id)、来自hey box list的邮箱 ID、来自hey label list的标签 ID。切勿混用不同类型的 ID,也不要用电子邮件地址代替联系人 ID。
线程列表(hey box view、label view、collection view、bundle view、contact threads、search)会同时提供这两个 ID,但有两个例外:汇总行可能不包含 topic_id;如果搜索结果对应的线程在你的邮箱中没有条目,则会省略 id。
传入错误类型的 ID 不会自动重定向。不会报告不匹配的 ID:HEY 只会检查调用中是否有任意一个邮箱条目 ID 属于你,并对所有匹配项执行更改。只有当所有 ID 都不匹配时,hey trash、spam、label add|remove|create 和 bubble up|pop 才会返回 not_found;hey seen、unseen、move、ignore、stop-ignoring 和 set-aside group create|add|remove 则从不检查(如果没有匹配的 ID,group create 会留下一个空组)。因此,混合批次即使只部分成功,也会被报告为整体成功;输入错误会被静默跳过;恰好与某个邮箱条目 ID 相同的 topic_id 会作用于不相关的线程;同样,传给 hey thread read 的邮箱条目 ID 也可能读取不相关的线程。应进行确认,而不要只相信响应:
hey box view imbox --json --all --jq '{notice, next_page: .data.next_page, match: [.data.postings[] | select(.id == 12345) | {id, topic_id, seen}]}'
如需确认标记操作,可检查标记状态;如需确认移动操作,可读取目标邮箱。如果 match 为空但仍设置了 next_page,则说明邮箱内容多于 --all 读取的范围:请使用 --page <next_page> 继续读取,而不要将其判定为不匹配。
汇总行。 当一封邮件的 kind 为 bundle 时,表示将同一发件人的邮件汇总到一行中,该行显示的是发件人,而非线程。只有当其中恰好包含一个未读线程时,才会提供 topic_id。切勿将汇总行的 id 传给 hey thread read。hey bundle view <id> 会列出其中未读线程的 topic_id;hey contact threads <contact_id> 会列出该发件人的所有线程,无论是否已读;邮件被读取后,只有这里会继续列出汇总中的邮件。使用 hey contact bundle|unbundle <contact_id> 更改分组方式。
发送
- 发送(
compose、reply、forward、draft send)会返回新消息的id和消息所属会话的topic_id;使用hey thread read <topic_id>读取该会话。 delayed: true表示“撤回发送”仍在暂缓发送;在消息发出之前,HEY 不会将它放入会话中:hey thread read会显示不含该消息的会话,或者对于由该消息发起的会话返回not_found。请稍后再次读取,不要误以为发送失败。- 如果 HEY 拒绝发送(通常是因为账户达到发送上限),发送会以
not_delivered失败(退出码 7)。HEY 会将消息保留为草稿,并在错误中以draft_id标明;稍后使用hey draft send <draft_id>发送。不要重新发送消息,否则会创建第二份草稿。 - 如果希望任何内容发出前都由他人审核,请在
compose或reply中添加--draft;返回结果会附带草稿 ID,可用于hey draft show|edit|send|delete。他人可以在任意 HEY 应用中审核并发送,也可以由你稍后使用hey draft send发送。 hey bulk-reply:先运行preview,再运行send。如果误发了邮件,可以在撤回窗口仍开启时使用hey bulk-reply undo <delivery_id>撤回。
编写内容
默认情况下,消息正文、草稿、日志条目、片段和联系人备注都使用 Markdown(无论通过 -m、--content、--note、位置参数内容、stdin 还是 $EDITOR);发送时会将其转换为富文本。剪藏内容、事件备注和时间跟踪备注则是纯文本。每个 Markdown 标志都有对应的 HTML 标志(例如 --message-html、--note-html、--content-html),用于输入原始 HTML;同一对标志不能同时使用。围栏代码块的语言会保留,但仅限 HEY 支持语法高亮的语言(Ruby、Python、JavaScript、TypeScript、Go、Rust、Java、C#、C++、PHP、Swift、HTML 和 CSS);其他语言标记会被丢弃。
日历中的所有内容都是一条记录,每种记录都有自己的命令:hey event、hey todo、hey journal、hey habit、hey timetrack。如果不指定日期,这些命令会读取账户时区以确定今天;指定日期即可跳过读取账户信息。
向整篇内容中添加内容
hey contact note set 和 hey journal write 会替换整条备注或日志条目,不支持追加。若要添加内容,请先读取,再修改,然后写回完整内容。请保留 &&:读取失败时不得继续写入。读取和写入不是原子操作,因此读取后应立即写入。
联系人备注。 当 note_markdown_lossless 为 true 时,note_markdown 包含完整备注;读取操作会检查此标志本身,如果它为 false 则会失败,因此不会写入任何内容:
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 12345
当它为 false 时,备注中包含 Markdown 无法保留的标记。请改为添加到 HTML 中:
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>"
日志条目。 处理方式相同,使用 content_markdown_lossless;如果某天没有日志条目,读取也会失败:
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-15
entry=$(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>"
身份验证
数据命令会使用 HEY 已存储的凭据,并自动刷新即将过期的 OAuth 令牌。无需先执行登录检查,直接运行所需的数据命令即可。
如果数据命令返回退出代码 3,且包含 "code": "auth",或失败并提示 could not read stored credentials,则该进程无法进行身份验证。在 macOS 上使用 Codex 时,沙盒可能会隐藏 HEY CLI 存储在 Keychain 中的凭据。在报告任务受阻之前,请使用执行环境的常规审批流程,在提升沙盒权限的情况下重试一次 hey auth status --json。仅对此只读命令提升权限。如果响应中的 data.authenticated 为 true,请通过单独的一次性命令审批,仅重新运行用户请求的那条确切 hey 命令。如果 data.authenticated 为 false,请报告任务受阻,并告知用户在 Terminal 中运行 hey auth login;不要在无人监督的情况下代用户运行。如果状态命令失败,例如出现 exit status 36 之类的密钥环错误,则问题并非登录所致,hey auth login 也无法解决;请报告任务受阻,转达错误中的 hint,然后停止。
绝不要运行 macOS 的 security 命令读取 Keychain 内容、打印或复制凭据,或将凭据移入文件;绝不要全局禁用沙盒;绝不要将 HEY_NO_KEYRING=1 作为身份验证的变通方法。
通过管道运行的命令、机器输出命令和非 TTY 命令都不会提示登录。当 Agent 执行环境通过 PTY 运行命令时,请设置 HEY_NONINTERACTIVE=1,这样缺少登录信息时会返回相同的可操作身份验证错误,而不会打开交互式提示。