Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

v2ex-cli

npm GitHub release Release date release workflow License: MIT

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 public

V2EX 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 --json flips every command into structured mode with stable keys.
  • Deterministic exit codes: 0 ok · 1 API/network error · 2 missing/invalid auth.

Install

npm install -g @pengyanai/v2ex-cli
# or run without install
npx @pengyanai/v2ex-cli hot

Node.js ≥ 18 required.

Auth (optional)

V2EX's public API serves most read endpoints anonymously. You only need a token for:

  • v2ex auth — token check itself
  • v2ex notifications — your own notifications
  • v2ex 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=xxxxxxxx

or ~/.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 3

Search showcase

OR across many terms with | (Elasticsearch query_string syntax):

v2ex search '家庭|矛盾|孩子|教育|原生家庭|父母|养老|婚姻|婆媳' --size 10

Exact phrase with quotes:

v2ex search '"distributed lock"' --size 5

Required term + nice-to-have:

v2ex search '+rust 性能 OR 内存'

Restrict to a node and a user:

v2ex search 性能 --node 25 --user livid

Top 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.
  • search uses 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 nodes ships a curated set, override via the nodes key 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

About

AI-agent friendly CLI for V2EX. Dense, scriptable, JSON-first.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages