@pengyanai/v2ex-cli
v0.4.0
Published
AI-agent friendly CLI for V2EX. Dense, scriptable, JSON-first.
Maintainers
Readme
v2ex-cli
AI-agent friendly CLI for V2EX. Dense, scriptable, JSON-first.
npm install -g @pengyanai/v2ex-cli
v2ex hot --limit 5 # no token needed for read commands
v2ex topics qna --limit 5 # also publicV2EX is a public forum — most read commands work anonymously. Set V2EX_TOKEN only when you need your own notifications / member info.
Why
Existing V2EX terminal clients are interactive TUIs — great for humans, hostile to LLM tool use. v2ex-cli inverts that: every subcommand is non-interactive, fails with a stable exit code, and emits either dense plain text (default) or JSON (--json) so an agent can pipe it into jq and reason about the result.
Design rules:
- Single shot: one command, one network call (or the minimum needed), one exit.
- High info density: TSV-shaped default output. No boxes, no spinners, no colors-by-default.
- JSON on demand: top-level
--jsonflips every command into structured mode with stable keys. - Deterministic exit codes:
0ok ·1API/network error ·2missing/invalid auth.
Install
npm install -g @pengyanai/v2ex-cli
# or run without install
npx @pengyanai/v2ex-cli hotNode.js ≥ 18 required.
Auth (optional)
V2EX's public API serves most read endpoints anonymously. You only need a token for:
v2ex auth— token check itselfv2ex notifications— your own notificationsv2ex member(without username) — your own profile
Everything else (hot, latest, nodes, topics, topic, replies, member <username>) works with no setup.
When you do want auth, get a token at https://www.v2ex.com/settings/tokens, then either:
export V2EX_TOKEN=xxxxxxxxor ~/.v2ex.json:
{
"token": "xxxxxxxx",
"proxy": "http://127.0.0.1:7890",
"nodes": [{ "name": "openai", "title": "OpenAI" }]
}HTTPS_PROXY / http_proxy env vars are also honored.
Verify: v2ex auth (exit 0 = ok, exit 2 = bad token).
Commands
| Command | Auth | Purpose |
|---|---|---|
| v2ex auth | yes | verify token, print authenticated user |
| v2ex nodes [name] | no | list curated nodes; with name → fetch node metadata |
| v2ex topics <node> | no | topics under a node, paginated |
| v2ex topic <id> [--with-replies] | no | topic body + meta, optionally inline first replies page |
| v2ex replies <topicId> | no | replies of a topic, floor-numbered |
| v2ex hot [--limit N] | no | front-page hot topics |
| v2ex latest [--limit N] | no | latest topics across the site |
| v2ex member [username] | optional | named user → public; own profile (no arg) → token |
| v2ex notifications | yes | your notifications |
| v2ex search <kw...> | no | search topics via SOV2EX (third-party index) |
Universal flags: --json, --no-color, -V/--version, -h/--help. Per-command: -p/--page, -l/--limit where applicable.
Examples for AI agents
Top 5 hot titles only:
v2ex hot --json --limit 5 | jq -r '.[].title'Find unanswered "问与答" topics:
v2ex topics qna --json | jq '[.[] | select(.replies == 0)]'Read a topic with replies in one call:
v2ex topic 1213548 --with-replies --json | jq '{title, replies, first_reply: .replies_list[0].content}'Search across all of V2EX (multiple shell args are AND-joined; SOV2EX runs on Elasticsearch so its query syntax is available too):
v2ex search 遛娃 --size 5
v2ex search openai gpt-5 --json | jq -r '.hits[].title'
v2ex search docker --sort created --size 3Search showcase
OR across many terms with | (Elasticsearch query_string syntax):
v2ex search '家庭|矛盾|孩子|教育|原生家庭|父母|养老|婚姻|婆媳' --size 10Exact phrase with quotes:
v2ex search '"distributed lock"' --size 5Required term + nice-to-have:
v2ex search '+rust 性能 OR 内存'Restrict to a node and a user:
v2ex search 性能 --node 25 --user lividTop 3 most-replied hits, titles only:
v2ex search '副业|赚钱' --size 30 --json \
| jq -r '.hits | sort_by(-.replies) | .[0:3][] | "\(.replies)\t\(.title)"'Count how many hits in the last 30 days mention a topic:
v2ex search 'AI 编辑器' --sort created --size 50 --json \
| jq '[.hits[] | select(.created > (now - 30*86400))] | length'Note: SOV2EX is community-run; complex queries that overload its parser may return 400. Quote the whole query string in shells (single quotes work safely with |, +, ").
Pipeline-friendly: every text mode is TSV, so awk -F'\t' works directly.
v2ex hot --limit 10 | awk -F'\t' '{print $1, $2}'See docs/AGENT_USAGE.md for tool-use schemas and longer recipes.
Project notes
- Uses V2EX v2 API where it covers the use case (auth, node metadata, node topics, topic, replies, member, notifications).
- Uses V2EX v1 (
/api/topics/hot.json,/api/topics/latest.json,/api/members/show.json,/api/topics/show.json,/api/replies/show.json) for the read commands, since v1 is publicly accessible. Both share the same token + proxy config. searchuses SOV2EX — V2EX has no official search endpoint. SOV2EX is community-run; treat its uptime as best-effort.- No public list-all-nodes endpoint exists;
v2ex nodesships a curated set, override via thenodeskey in~/.v2ex.json.
The full origin prompt and iteration log lives in docs/PROMPTS.md.
Status
Tracking via issues. Forked from v2erminal and rewritten end-to-end.
License
MIT
