of the unread workflowentry skill: answers "what unread items do I have" and completes the loop of "overview → drill down → mark all as read". The commands involved span unread / sub / focus three command trees; this document is organized by workflow.
Prerequisites
- Installation:
curl -fsSL https://raw.githubusercontent.com/SupSub-AI/supsub-cli/master/scripts/install.sh | bash(native install, installs to~/.local, supports background auto-update); or package managernpm i -g @supsub/cli/pnpm add -g @supsub/cli - Logged in:
supsub auth statusshows Authenticated (on first use, firstsupsub auth login) - When unauthorized (exit 2 / UNAUTHORIZED), do not stop at "you are not logged in": directly run
supsub auth loginto open browser authorization for the user (the command will automatically open the browser and block waiting for authorization, so use a sufficiently long timeout, such as 10 minutes; the user only needs to click confirm in the browser and does not need to enter anything in the terminal), and retry the original command after successful authorization. In a browserless / headless environment, fall back to prompting the userSUPSUB_NO_BROWSER=1 supsub auth login。
Read model: only "mark all as read", no "mark individual as read"
This is the easiest point to get wrong in this skill; remember it first:
- The CLI can only do two things:
sub mark-read --all(I have finished reading this account),focus mark-read --all(I have finished reading this focus). - There is no mark individual as read. The reason is product-side: articles in SupSub do not have a "details / reading" step, so there is no natural event of "the user finished reading this article"; therefore the CLI only preserves the user'sexplicitly expressedintent to mark all as read.
- When the user says "mark this article as read":truthfully explain that it is not supported, then ask whether to mark the entire source / entire focus as read. Do not try to use
--content-idto bypass it (it will throwINVALID_ARGS), and do not fake per-article read status by calling in a loop. - There is also no group-level mark-as-read command. When the user wants to "clear a group": first
group subslist the sources in the group, confirm each source, then mark each onesub mark-read --all,each source must be within the confirmed scope。
Workflow (three-step loop)
- Overview:
supsub unread -o json→ get allunreadCount > 0subscription sources and focuses at once. - Drill down: pull the unread list for the source/focus the user cares about (the default is unread):
- Subscription source →
supsub sub contents --source-id <sid> --type <t> -o json - Focus →
supsub focus contents --id <fid> -o json
Using the default (unread) here is correct—this skill's context is inherently "what have I not read". But if the user switches midway tobrowse by time ("so what has X talked about recently"), switch to
--alland treatisReadas an annotation; seesupsub-sub/supsub-focus。 - Subscription source →
- Mark all as read(only when the user explicitly expresses "finished reading / clear it"):
mark-read --all,must first confirm a second time(see below).
Pagination strategy (do not repeatedly ask the user)
contents defaults to 20 items per page (--page-size upper limit 100). Choose the strategy according to user intent,do not ask page by page during the process:
- Browsing-type intent("see what unread items there are"): only fetch page 1, and with
unreadCountinform "N unread in total, first 20 shown"; when the user says "continue / see more", then--page 2。 - Full-fetch-type intent("all unread", "stats / export"): automatically loop through pages—use
--page-size 100to reduce the number of requests; when the number of returned items < page-size, that is the last page;unreadCountcan estimate the page count.For this kind of batch fetch, always add--brief(keep only contentId/title/time/read status; about 14KB for 100 items; without it about 90KB, which will blow past the tool output limit and force writing to disk). - Note: "clear unread"does not needto first fetch all articles—marking everything as read is a single command, and a full fetch is only done when the user wants to view / get stats.
--all secondary confirmation (mandatory rule)
Before executing sub mark-read --all or focus mark-read --all ,you mustcomplete the following in order:
- Restate the scope of impact: source/focus name + current
unreadCount(obtained fromsupsub unreador the list command); - Explicitly ask the userand obtain an affirmative answer;
- only then may you execute.Do not execute without confirmation—the operation is irreversible, and there is no mark-as-unread.
⚠️ The CLI itself will not ask again.
mark-read --all(as well asgroup remove/focus remove) has no interactive confirmation prompt; the command takes effect immediately once run. This confirmation stepexists only between you and the user, and there is no fallback at the CLI layer. Therefore,when you hand the command to the user to execute themselves in the terminal (for example, when blocked by permissions/guardrails), you must never say "after execution the CLI will prompt you to confirm"— that is a safety net that does not exist, and if the user follows it they will directly clear the entire source. Truthfully explain that "this command takes effect as soon as it is executed and cannot be undone."
When the user vaguely says "mark all as read / clear unread": first show an unread overview,confirm item by item, and do not presume to loop through and clear all sources.
Commands
Unread overview
supsub unread [--all]
| Flag | Default | Description |
|---|---|---|
--all |
— | Show all (including items with unreadCount=0 ); by default only show those with unread items |
Concurrently aggregate "subscription source list + focus list" in one go, equivalent to sub list + focus list two queries.
supsub unread
supsub unread -o json
supsub unread --all -o json
JSON shape: {"success":true,"data":{"subscriptions":[{"sourceType":"MP","sourceId":25,"name":"量子位","unreadCount":194,...}],"focuses":[{"id":674,"icon":"🔖","title":"...","unreadCount":299}]}}
Mark a source as read (mark an entire subscription source as read)
supsub sub mark-read --source-id <sid> --type <MP|WEBSITE|X> --all
| Flag | Required | Description |
|---|---|---|
--source-id |
yes | Information source ID (positive integer) |
--type |
yes | MP / WEBSITE / X(Twitter) |
--all |
yes | Confirm marking the entire source as read (irreversible, confirm twice first) |
--allisrequiredintent flag: if not provided it throwsINVALID_ARGS, to avoid accidentally clearing a source. Passing--content-idalso throwsINVALID_ARGS(no single-article read).
# 整源已读(需用户确认后执行)
supsub sub mark-read --source-id 25 --type MP --all -o json
JSON shape: {"success":true,"data":{"message":"已标记该订阅源全部内容为已读(不可逆)"}}
Mark a focus as read (mark an entire focus as read)
supsub focus mark-read --id <fid> --all
| Flag | Required | Description |
|---|---|---|
--id |
yes | Focus ID (positive integer, from focus list) |
--all |
yes | Confirm marking the entire focus as read (irreversible, confirm twice first) |
Likewise:
--allrequired; passing--content-id/--type/--source-typethrowsINVALID_ARGS(no single-article read).
# 整个关注点已读(需用户确认后执行)
supsub focus mark-read --id 674 --all -o json
JSON shape: {"success":true,"data":{"message":"已标记该关注点全部内容为已读(不可逆)"}}
Agent Usage Notes
- When parsing data, uniformly use
-o json; all JSON responses are{"success":true,"data":<payload>}structure. supsub unreadis thepreferred first stepfor "what haven't I read"-type requests: one command covers two checks, and by default it only returns items with unread content, so it can be reported directly.- Marking as read has only two paths: entire source / entire focus, both require
--all. When the user wants to mark a single article, truthfully explain that it is not supported, and offer "mark entire source as read" as an alternative for them to decide. --allmust first be confirmed with the user a second time(restate the scope + unread count → explicit consent → execute); after marking is complete, restate the scope actually executed; you can usesupsub unreadto verify it has been reset to zero.- There is no mark-as-unread: if something is marked incorrectly, it cannot be restored. Better to clear only one source at a time than to loop in batches.
- This skill is not responsible for: subscribe/unsubscribe (→
supsub-sub), focus deletion (→supsub-focus), group management (→supsub-group), keyword search (→supsub-search)。 - Exit codes:
0OK,1business errors (backend 4xx, such as source/focus does not exist),2UNAUTHORIZED,64INVALID_ARGS (no--allprovided, single-article parameters passed by mistake, invalid ID),10network errors,11server errors (5xx).