Deep Read = an AI deep breakdown of asinglearticle. It is not a summary (sub contents in summary is the summary),
but a structured breakdown with a critical perspective: is it worth reading, where is the substance, what is the author's stance, are the sources credible, where is the weakest link in the argument.
Prerequisites
- Install:
curl -fsSL https://raw.githubusercontent.com/SupSub-AI/supsub-cli/master/scripts/install.sh | bash(native install, installed to~/.local, supports automatic background updates); 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; 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). After successful authorization, retry the original command. In a browserless / headless environment, fall back to prompting the userSUPSUB_NO_BROWSER=1 supsub auth login。 - Deep Read requires a paid plan; when there is no permission, the backend returns a business error (exit 1). Relay it truthfully and stop; do not retry.
Two hard gates (read these two first, then look at the commands)
① Spending gate: before initiating a Deep Read, you must confirm the quota
Deep Readdeducts from the monthly quota per use, and there is no "cancel/refund quota" operation. The quota limit changes with plan/backend adjustments;always use the deepread quota returned by limit / remaining for that call as the standard; do not repeat the balance to the user from memory. Therefore:
- First
supsub deepread quota -o jsonget{limit, used, remaining}; - Repeat to the user:which articles are to be deep-read (list titles), how many uses it will consume, and how many remain this month;
- Only after receiving a clear affirmative reply, execute
deepread run。
For batches, list the titles one by one for the user to confirm,do notexpand the scope on your own just because the user said "deep read them all".
When the user has already explicitly named a single article ("deep read this one" + only one article in context), one quota + one sentence "This will consume 1 use, N remain this month, start now?" is enough; there is no need to ask layer by layer.
Articles that have already been deep-readwill notbe charged again:
runwill first detect the status; if it hitsdoneit returns the result directly (quotaSpent: false). So there is no need to ask the user "has this been read before"; just rundeepread getand you will know.
② Value gate: contentId can only come from the context
contentId is an opaque string,mustcome from the real return of sub contents / focus contents / search in this session.
| User's wording | Action |
|---|---|
| "Deep read the 3rd one" | Refers to the 3rd item in the list above → directly use its contentId |
| "Deep read the one about XX" | Fuzzy-match by title in the list above:exactly 1 matchexecute only; if 0 or ≥2 articles match → ask the user back, do not take the first one |
| there is no article list in the above context | first sub contents --brief / search list the candidates,stop and wait for the user to name one, do not take it upon yourself to pick the latest article |
| the user directly pastes an article URL | CLI there is no URL → contentId interface. State this honestly, and instead locate this article from subscriptions/follows/search |
neverhave the user manually type the contentId,neverconstruct or guess from memory. The cost of guessing wrong is spending one quota read on the wrong article.
Workflow
A. Single-article close reading (most common)
# 1. 定位文章(拿 contentId + sourceType)
supsub sub contents --source-id 25 --type MP --brief -o json
# 2. 查额度 → 向用户确认 → 才执行
supsub deepread quota -o json
# 3. 发起并等待(默认前台等,实测 20~40 秒)
supsub deepread run --type MP --content-id <cid> --title "<标题>" --source-name "<源名>" -o json
--title / --source-name / --url aredisplay info for the local cache, the close-reading interface itself does not return the title;
include them so the local Markdown has a decent title line, and later list can also recognize which article it is.always include。
B. Batch close reading → comprehensive brief (the most valuable usage of CLI+agent)
On the web you can only click one at a time; the agent can queue them all at once and harvest them all at once, amortizing the latency (5 articles ≈ the time of 1):
# 1. 取候选 → 列标题 + 消耗次数给用户确认(门禁 ①)
# 2. 并发排队,不等
supsub deepread run --type MP --content-id <c1> --title "…" --no-wait -o json
supsub deepread run --type MP --content-id <c2> --title "…" --no-wait -o json
# 3. 一次等完
supsub deepread list --wait -o json
then based on each article's essence / quality.grade / keyPoints do cross-comparison and synthesis.
When you need the details of a certain article, read its cachePath(local Markdown full text)——do notstuff all full texts into the context.
C. Cross-session retrieval (inbox)
The user asks the next day "was that article from yesterday finished being read closely" "which close readings have I not looked at yet":
supsub deepread list -o json
- default view = in progress + finished but not yet told to the user(
fresh: true), after broadcasting, a watermark is automatically set, so it will not be repeated every day. - to see all history use
--all(--allwithout moving the watermark). - ⚠️ The queue islocal to this machine: close readings initiated from the web are not visible here, and those initiated from the CLI are not visible on the web either (the backend has no cross-client close-reading list interface). State this honestly when the user asks.
D. Sharing (confirm separately)
supsub deepread share --type MP --content-id <cid> -o json
before generating, you must confirm separately with the user, restating these three points:
this will generate a
https://supsub.net/s/<code>page,anyone who gets the link can open it (no login required), and the current API has no interface to revoke sharing. Confirm generation?
when the user just wants to "see the full text themselves"do notuse share —— the close-reading result is already in the output, and the full text is also locally at cachePath.
share is only for "sending to others". Repeatedly sharing the same article will reuse the existing share code (reused: true), and will not produce a second public link.
Commands
deepread run — initiate close reading
supsub deepread run --type <MP|WEBSITE|X> --content-id <cid> [--title <t>] [--source-name <n>] [--url <u>] [--no-wait] [--timeout <sec>] [--brief]
| Flag | Default | Description |
|---|---|---|
--type |
required | MP MP official account / WEBSITE WEBSITE website / X X Twitter |
--content-id |
required | contentId from contents / search |
--title / --source-name / --url |
— | display info written into the local queue,recommended to always include |
--no-wait |
— | only initiate without waiting (use when queuing in batches) |
--timeout <sec> |
180 | foreground wait limit, 1–600 |
--brief |
— | Omit the body sections in the output; keep only essence/qualityGrade/keyPoints/annotation |
Behavior: first GET probe status → none/failed only then POST initiate → by default poll until done.
When done is already cached locallyzero network requestsreturn directly.
Note on the agent side: by default it waits in the foreground; measured at 20–40 seconds. When running it with the Bash tool, set the timeout to 120 seconds or more(the default 120s is usually enough; when a long article approaches the limit, 180s is more reliable), or switch to --no-wait + deepread list --wait。
JSON shape:
{"success":true,"data":{
"sourceType":"MP","contentId":"…","title":"…","status":"done","version":"v1",
"quotaSpent":true,
"cachePath":"/Users/…/.supsub/deepread/u101/MP_xxxx.md",
"content":{"essence":"…","quality":{"grade":"高","comment":"…"},"keyPoints":["…"],
"body":{"sections":[{"title":"…","markdown":"…"}]},
"annotations":{"background":"…","stance":"…",
"credibility":{"grade":"中","reason":"…"},"weakestLink":"…"}}}}
status values:none not initiated / pending in progress / done completed / failed failed.
A timeout or still being pending is not an error, the exit code is still 0 — branch on the status field, do not look at the exit code to determine whether it has finished.
failed when you can rerun deepread run to retry (whether fees are charged again is unconfirmed; inform the user before retrying).
deepread get — view results (prefer local cache)
supsub deepread get --type <t> --content-id <cid> [--brief] [--refresh] [--wait] [--timeout <sec>] [--out <file>] [--title <t>] [--source-name <n>] [--url <u>]
done is a terminal state and the result is immutable, so by default it uses the local cache directly (zero requests);--refresh force a fetch from the server.
--out <file> Export the deep-read full text as a Markdown file. Querying content that has never been deep-read returns status:"none", exit code 0。
deepread list — local deep-read queue (inbox)
supsub deepread list [--all] [--wait] [--timeout <sec>]
Only query back pending items (done no longer bothers the server).--wait Wait until all in-progress items in the queue have settled.
Each item contains essence / qualityGrade / cachePath / fresh。
deepread quota — this month's quota
supsub deepread quota
JSON shape: {"success":true,"data":{"limit":100,"used":7,"remaining":93}}
(the values are examples only; the actual quota is based on the response at that time)
deepread share / show / drop
supsub deepread share --type <t> --content-id <cid> # 生成公开链接,先确认(见 Workflow D)
supsub deepread show --share-code <code> [--brief] # 读别人分享的,无需登录
supsub deepread drop --type <t> --content-id <cid> # 移出本地队列
drop Only deletes the local cache; the server-side result is still there, and later get can fetch it back anddoes not deduct quota—so it is not a dangerous operation and needs no second confirmation.
Agent Usage Notes
- Use
-o jsonuniformly for parsing data; responses are all{"success":true,"data":<payload>}。 - Deep read ≠ full text. The CLI has no interface to fetch the original article text. When the user wants the "original text", give them
urlto open it themselves; do not pass off the deep-read result as the full text. - Deep read ≠ summary. When they only want to know "what it says,"
sub contentsthe ready-madesummaryin it is enough,do notspend a quota on this. Only use deep read when the user explicitly wants "breakdown / is it worth reading / is it reliable / is there substance." - One deep-read result is about 4–6KB,the whole thing can go into context; for batches (>5 articles) use
--brief, and when details are needed, read individual articles bycachePath. - Local cache directory
~/.supsub/deepread/<账号>/, two files per article (.jsonmetadata +.mdfull text). To find things in past deep reads, grepping this directory directly is faster and cheaper than deep-reading again. - This skill is not responsible for: browsing the article list (→
supsub-sub/supsub-focus), keyword-searching articles (→supsub-search), marking as read (→supsub-unread)。 - Exit codes:
0OK (includingpending/none),2UNAUTHORIZED,64INVALID_ARGS(--typeinvalid,--content-idempty,--timeoutout of range),10network error,1business errors (such as no paid plan, quota exhausted),11server-side errors.