From 0cabcf0dfb03164e637c030ae30c5207669cc8eb Mon Sep 17 00:00:00 2001 From: joshrpowell Date: Tue, 4 Aug 2026 09:02:25 -0400 Subject: [PATCH 1/2] fix(skill): clarify box topic IDs --- skills/hey/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/hey/SKILL.md b/skills/hey/SKILL.md index 31596894..8073aebf 100644 --- a/skills/hey/SKILL.md +++ b/skills/hey/SKILL.md @@ -161,7 +161,7 @@ hey box 123 --json # List emails in box (by ID) Box names: `imbox`, `feedbox`, `trailbox`, `asidebox`, `laterbox`, `bubblebox` -**Response format:** `hey box` returns `{"box": {...}, "postings": [...]}`. Each posting has: `id` (posting ID), `topic_id` (topic ID), `name` (subject), `seen` (read status), `created_at`, `contacts`, `summary`, `app_url`. Use `topic_id` for `hey threads` and `hey reply`. +**Response format:** `hey box` returns `{"box": {...}, "postings": [...]}`. Each posting has an `id` (posting ID), plus fields such as `name` (subject), `seen` (read status), `created_at`, `contacts`, `summary`, and `app_url`. It does not currently guarantee a `topic_id`. ### Email - Threads @@ -170,7 +170,7 @@ hey threads --json # Read full email thread hey threads --html # Read with raw HTML content ``` -**ID note:** `hey box` returns postings with an `id` (posting ID) and a `topic_id` (topic ID). `hey threads` and `hey reply` expect the **topic ID** — use `topic_id` directly. The `app_url` field also contains the topic ID as a fallback (e.g. `https://app.hey.com/topics/123` → `123`). +**ID note:** `hey threads` and `hey reply` expect a **topic ID**, not a posting ID. When a posting's `app_url` contains `/topics/`, use that ID. If it does not, do not substitute the posting ID: the current CLI has no supported lookup from posting ID to topic ID, so ask the user to open the thread in HEY instead. See issue #156. ### Email - Reply & Compose From 90be0bb9b5cbdd784dfa5dc8c05c26571916056d Mon Sep 17 00:00:00 2001 From: joshrpowell Date: Tue, 4 Aug 2026 09:42:28 -0400 Subject: [PATCH 2/2] fix(skill): document bundle postings and app_bundle_url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous revision told agents to give up whenever a posting's app_url was not topic-shaped. That discards the bundles that wrap a single message, which carry their topic in app_bundle_url and read fine — 70 of 238 bundles (29%) in a 500-posting sample. Document the two posting kinds instead. A kind=topic posting always has a /topics/ app_url; a kind=bundle posting has a contact-shaped app_url and is resolvable via app_bundle_url only when it wraps one message. A bundle of several messages names a contact rather than a thread, so no topic ID exists for it and there is no CLI command to list its contents. Also correct the documented envelope ({ok, data:{...}} rather than {box, postings}), note that a bundle's name concatenates several subjects, and state plainly that no posting carries a topic_id rather than that one is not "guaranteed". Co-Authored-By: Claude Opus 5 --- skills/hey/SKILL.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/skills/hey/SKILL.md b/skills/hey/SKILL.md index 8073aebf..9c77724b 100644 --- a/skills/hey/SKILL.md +++ b/skills/hey/SKILL.md @@ -161,7 +161,12 @@ hey box 123 --json # List emails in box (by ID) Box names: `imbox`, `feedbox`, `trailbox`, `asidebox`, `laterbox`, `bubblebox` -**Response format:** `hey box` returns `{"box": {...}, "postings": [...]}`. Each posting has an `id` (posting ID), plus fields such as `name` (subject), `seen` (read status), `created_at`, `contacts`, `summary`, and `app_url`. It does not currently guarantee a `topic_id`. +**Response format:** `hey box --json` returns `{"ok": true, "data": {...box fields..., "postings": [...]}}`. Each posting has an `id` (posting ID), plus fields such as `kind`, `name` (subject), `created_at`, `contacts`, `summary`, `app_url`, and — on bundles — `app_bundle_url`. No posting carries a `topic_id`; see the ID note under Threads for resolving one. + +Postings come in two kinds: + +- `kind: "topic"` — a single message. `app_url` is `/topics/`. +- `kind: "bundle"` — HEY's per-contact digest, wrapping one or more messages from one sender. `app_url` is `/contacts/`, and `name` is a `•`-joined concatenation of the bundled subjects rather than one email's subject. ### Email - Threads @@ -170,7 +175,12 @@ hey threads --json # Read full email thread hey threads --html # Read with raw HTML content ``` -**ID note:** `hey threads` and `hey reply` expect a **topic ID**, not a posting ID. When a posting's `app_url` contains `/topics/`, use that ID. If it does not, do not substitute the posting ID: the current CLI has no supported lookup from posting ID to topic ID, so ask the user to open the thread in HEY instead. See issue #156. +**ID note:** `hey threads` and `hey reply` expect a **topic ID**, not a posting ID. Resolve one from the first `/topics/` URL the posting offers: + +1. `app_url` — present on every `kind: "topic"` posting. +2. `app_bundle_url` — a `kind: "bundle"` posting has a contact-shaped `app_url`, but a bundle wrapping a single message still points at that one topic here. + +If neither is topic-shaped, the posting is a bundle of several messages: it names a contact, not a thread, so no topic ID exists for it. Do not substitute the posting ID — `hey threads ` requests `/topics//entries` and returns not-found. The CLI has no command to list the topics inside a bundle, so ask the user to open it in HEY instead. See issue #156. ### Email - Reply & Compose