Add label workflows to the CLI and TUI
Summary
Add HEY label workflows to both the CLI and the Mail TUI, using the same Labels terminology as the web UI while retaining the server and SDK's internal folder resource names.
- add
hey labelsandhey label <id>with cursor pagination, limits, complete traversal, and structured/styled output - add
hey label add|create|removefor existing labels, new labels, individual removal, and removing every label - append labels to Mail navigation and add
n/plabel pagination - add a height-aware
glabel picker for adding, creating, and removing labels - pin the released
hey-sdk/go@v0.6.1pagination API
Behavior
Mail
├── HEY boxes
└── Labels
├── open labeled threads
├── n / p: next or previous page
└── g: manage labels
├── add an existing label
├── create and add a label
├── remove one label
└── remove every label
CLI commands:
hey labels
hey label <label-id> [--limit N | --all | --page CURSOR]
hey label add <thread-id>... --to <label-id>
hey label create <name> <thread-id>...
hey label remove <thread-id>... --from <label-id|all>
Label reads expose posting IDs, derived topic IDs, next_page, and total_count. Mutations validate positive, unique thread IDs before making requests.
Scope and compatibility
- Uses existing typed HEY JSON operations; no server API change or HTML scraping.
- Discovers labels through
/my/navigation.jsonand reads them through the SDKFolders()service. - Preserves
hey-sdkand wire-level folder names such as/foldersandfolder_idas implementation details. - Labels remain separate from box move destinations and cannot capture HEY box shortcuts, icons, or colliding IDs.
- Label discovery and page loads reject stale responses, preserve known labels on transient failures, and support retry.
- Markdown output now sanitizes terminal control characters and escapes table layout characters for all commands.
- No migrations, feature flags, configuration, or deployment ordering are required. Rollback is a revert of this PR.
Validation
GOWORK=off make check
PASS
GOWORK=off make race-test
PASS
GOWORK=off make coverage
73.021% (5,700 / 7,806 statements), floor 70.8%
GOWORK=off make build
PASS
cd tests/smoke && GOWORK=off go test -count=1 -v -run '^TestLabel'
PASS
git diff --check
PASS
Unit coverage includes CLI request contracts, validation-before-request behavior, pagination, styled/Markdown sanitization, TUI navigation and picker workflows, retry and stale-response handling, pagination key scoping, and box/label identity collisions. Independent and Copilot reviews identified actionable CLI, TUI, output-contract, and smoke-cleanup edge cases. This head resolves every finding and both suggestions suppressed by Copilot’s follow-up review; all review threads are resolved, and focused re-review found no remaining P0/P1/P2 issues.
Reviewer focus
internal/cmd/label.goandinternal/folders/navigation.go: command contracts, opaque pagination cursors, and label discovery.internal/tui/mail.goandinternal/tui/folders.go: source lifecycle,n/pscoping, stale-response guards, and label picker behavior.internal/output/writer.go: shared Markdown sanitization and escaping.
Traceability
- Basecamp card: https://app.basecamp.com/2914079/buckets/48521764/card_tables/cards/10206892850
- SDK pagination PR: https://github.com/basecamp/hey-sdk/pull/90
- SDK release: https://github.com/basecamp/hey-sdk/releases/tag/v0.6.1
This PR must not be merged without explicit approval.
Summary by cubic
Adds Labels to the CLI and Mail TUI so users can list and manage labels without the web app. Previously labels were unavailable; now Mail shows labels after HEY boxes, supports per‑label n/p pagination, and a height‑aware g picker to add, create, or remove labels. Markdown output now sanitizes terminal controls, escapes table pipes while preserving backslashes, and renders newlines as
.
- CLI:
hey labels;hey label <id>with cursor pagination (--limit,--all,--page);hey label add|create|removewith positive, unique thread ID validation. - TUI: discovers labels via
/my/navigation.json; reads label pages with SDKFolders().GetPage; g manages add/create/remove; n/p paginates per label; guards reject stale navigation, keep known labels on transient failures; preserves boxes alongside labels on ID/name collisions; move picker excludes labels from destinations. - Implementation notes: label file/unfile via
Postings().File/Unfile; create viaPostings().CreateFolder; “folders” remain an internal term. Fixeshey boxthread ID display to prefer topic ID and fall back to posting ID. Pinsgithub.com/basecamp/hey-sdk/gotov0.6.1. Help,.surface, README,skills/hey, API coverage, and tests (unit and smoke) updated. No server changes, migrations, or flags; rollback is a revert.
Reviewer focus
- CLI:
internal/cmd/label.gofor command contracts, validation, pagination; curated help ininternal/cmd/help.go. - TUI:
internal/folders/navigation.gofor label discovery;internal/tui/mail.goandinternal/tui/folders.gofor per‑label pagination, picker behavior, and stale‑response guards;internal/tui/move.goandinternal/tui/nav.gofor excluding labels from move destinations and preserving boxes when IDs/names collide. - Output:
internal/output/writer.goMarkdown sanitization and escaping.