SuperAPI AI Directory

supsub-focus

General & other

View repository

Updated 10-16 09:34

About this skill

supsub-focus Skill

A "focus" is a topic-aggregated content stream in SupSub: it spans multiple sources (WeChat Official Accounts MP, websites WEBSITE, Twitter X) and gathers articles on the same topic together. This skill handlesviewingthe focus list,browsingthe content in a focus (distinguishing read/unread), anddeletinga focus.

Difference from supsub-sub :sub manages "subscription sources" (a specific Official Account/website, and the articles under it);focus manages the "topic aggregation view" (a content stream across multiple sources). Do not confuse the two. Difference from supsub-search :search does one-off full-text search by keyword;focus browses an existing, continuously updated topic stream.

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 manager npm i -g @supsub/cli / pnpm add -g @supsub/cli
  • Logged in:supsub auth status shows Authenticated (on first use, first supsub auth login)
  • When unauthorized (exit 2 / UNAUTHORIZED), do not stop at "you are not logged in": directly run supsub auth login to open browser authorization for the user (the command will automatically open the browser and block waiting for authorization, so use a sufficiently long timeout, e.g. 10 minutes; the user only needs to click confirm in the browser and does not need to type anything in the terminal), and retry the original command after authorization succeeds. In a browserless / headless environment, fall back to prompting the user SUPSUB_NO_BROWSER=1 supsub auth login。

Commands

List focuses (focus list)

supsub focus list

No parameters. Fields per line:id, icon(emoji), title, unreadCount。

# 列出全部关注点
supsub focus list

# JSON 输出
supsub focus list -o json

JSON shape: {"success":true,"data":[{"id":42,"icon":"🤖","title":"...","unreadCount":3}, ...]}

Read/unread: each focus's unreadCount is the focus's current unread item count. When the user asks "which of my focuses still have unread items / how many are left unread in each focus", read this field directly; no need to go into contents.


Browse contents in a focus (view focus content)

supsub focus contents --id <focusId> [--unread | --all] [--brief] [--page <n>] [--page-size <n>]
Flag Default Description
--id required Focus ID (positive integer), from supsub focus list 's id
--unread (default) Return only unread content
--all — Return all content (read + unread)
--brief — Condensed output: keep only contentId / title / sourceType / sourceName / publishedAt(+Text) / isRead
--page 1 Page number (positive integer)
--page-size 20 Items per page, 1-100

⚠️ --unread and --all are mutually exclusive: specifying both throws INVALID_ARGS. When neither is passed, the default behavior is equivalent to --unread。

⚠️ "Recent" is not the same as "unread": requests like "show me the recent content of X" or "what's recent in focus X" thatbrowse by timeshould use --all, treat isRead asan annotation("N of these you haven't seen yet") rather than a filter condition; only when the user explicitly says "unread / not yet seen / how many are left unread" should the default be used. Otherwise, once the focus has been read, it will return an empty array and you will reply "no content" — but the user asked about "recent", not "unread".

The focus aggregates multiple sources, so every line carries sourceType / sourceName, making it easy to see which account/website/Twitter this content comes from.

Fields per line:contentId, url, title, coverImage, keywords[], tags[], summary, sourceType, sourceName, publishedAt, isRead。

# 默认(仅未读)—— 等价于 --unread
supsub focus contents --id 42

# 全部内容(含已读)
supsub focus contents --id 42 --all

# 翻到第 2 页 / 一次多拿一些(上限 100)
supsub focus contents --id 42 --page 2
supsub focus contents --id 42 --page-size 100 -o json

# 全部 + JSON
supsub focus contents --id 42 --all -o json

JSON shape: {"success":true,"data":[{"contentId":"...","url":"...","title":"...","coverImage":"...","keywords":[...],"tags":[...],"summary":"...","sourceType":"MP","sourceName":"...","publishedAt":<timestamp 或字符串>,"isRead":false}, ...]}

publishedAt 's raw form varies by backend version (Unix seconds number / "YYYY-MM-DD HH:mm:ss" string), no need to handle compatibility yourself—just read the CLI-populated publishedAtText(always "YYYY-MM-DD HH:mm")。 sourceType may be MP / WEBSITE / X(Twitter).

For batch enumeration always add --brief: complete output has every entry with summary / keywords / tags, about 90KB for 100 entries, which will exceed the tool output limit and be forced to disk;--brief likewise about 14KB for 100 entries. Only use full output when you need to explain the content to the user.

Pagination strategy: for browsing-type requests only fetch page 1 and report the total; for "all / statistics / export"-type requests use --page-size 100 to automatically loop through pages, do not ask the user page by page. See supsub-unread。


Mark a focus as read (mark the entire focus as read)

supsub focus mark-read --id <focusId> --all
Flag Required Description
--id yes Focus ID (positive integer)
--all yes Confirm that the entire focus is marked as read (irreversible)

⚠️ Only entire-focus read is supported; there is no single-article read. articles have no "detail / read" step, so a natural single-article read event cannot be produced, therefore the CLI only retains the user's explicit "I've finished reading this focus". Passing --content-id / --type / --source-type will throw INVALID_ARGS. When the user says "mark this article as read", truthfully explain that it is not supported.

⚠️ --all is required and irreversible(no mark-as-unread). Before executing you mustdouble-confirmwith the user: restate the focus title + current unreadCount, and only execute after obtaining explicit consent.

The CLI will not ask again: this command (as well as focus remove) has no interactive confirmation prompt; it takes effect as soon as it is executed. If you hand the command to the user to run in their own terminal, do not say "the CLI will prompt for confirmation after execution"—that safety net does not exist.

# 整个关注点已读(需用户确认后执行)
supsub focus mark-read --id 42 --all -o json

JSON shape: {"success":true,"data":{"message":"已标记该关注点全部内容为已读(不可逆)"}}


Remove a focus (delete a focus)

supsub focus remove --id <focusId>
Flag Required Description
--id yes Focus ID (positive integer)
supsub focus remove --id 42
supsub focus remove --id 42 -o json

JSON shape: {"success":true,"data":{"message":"..."}}

⚠️ Destructive and irreversible: after deletion the CLI has no command for adding a new focus(no focus add), once deleted it cannot be recreated. Be sure to confirm with the user before executing.


Read / unread (important)

Read status is maintained by theserver side, and the CLI can both read and mark it (can only mark as read,cannot mark back to unread):

  • focus list each item's unreadCount = the number of unread entries for that focus. This is the fastest entry point for determining "which focus still has unread items".
  • focus contents default (or explicitly --unread) only returns unread entries;--all returns all (read + unread).
  • focus contents each item's isRead(boolean) = whether that entry is read: rendered in the table as the read column (read shows ✓, unread is empty).
  • To mark as read use focus mark-read --all: only "entire focus read" is available, there is no single-article read.
  • There is no command to unmark as read: if marked by mistake it cannot be restored in the CLI.--all level operations are irreversible, and you must double-confirm with the user before executing.
  • For the cross-source + focus unread overview and the "clear unread" workflow, see supsub-unread(supsub unread — see everything with one command).

Agent Usage Notes

  • When parsing data, always use -o json; table output has truncation and column width limits, and is not suitable for downstream processing.
  • All JSON responses are of the {"success":true,"data":<payload>} structure (from src/ui/output.ts)。
  • Getting focusId the only source of supsub focus list is idof--id ; if INVALID_ARGS is not a positive integer, it reports
  • When a user asks "what content/articles are in this focus", it usually means --all(including read); when asking "what else haven't I read / unread", use the default --unread。
  • focus contents defaults to 20 items per page; use --page / --page-size(maximum 100) to page through and get earlier content.
  • focus mark-read only marks the entire focus as read (marking a single article as read is not supported: articles do not have a detail/read step);--all is required and irreversible, and you must confirm with the user a second time before executing。
  • This skill is not responsible for: adding, deleting, or querying subscription sources (→ supsub-sub), subscription groups (→ supsub-group), cross-source unread overview and the clear unread workflow (→ supsub-unread), keyword full-text search (→ supsub-search), discovering new official accounts (→ supsub-mp). focus has no add.
  • Exit codes:0 OK,2 UNAUTHORIZED,64 INVALID_ARGS(--id / --page / --page-size validation failure,--all and --unread are mutually exclusive, mark-read did not provide --all or a single-article parameter was mistakenly passed),1 business error (backend 4xx, such as focus does not exist),10 network error,11 server error (5xx).