- live-verified 2026-06: anonymous .json endpoints are 403-blocked (all
variants) and the official API closed self-service registration in
2025-11 — so the channel now says plainly: every Reddit backend needs
a logged-in session, mainland China needs a proxy
- backends = [OpenCLI, rdt-cli]: OpenCLI rides the browser session
(desktop preferred); rdt-cli stays for servers and existing installs
(upstream unmaintained since 2026-03, noted in the ok message)
- install: desktop routes to OpenCLI, server installs rdt-cli from the
pinned git source (split out as _install_rdt_cli)
- skill/references/social.md: Reddit section rewritten as two backend
command groups + a PRAW note scoped to users who already hold
pre-2025-11 credentials (explicitly not recommended for new users)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- backends becomes the ordered candidate list [OpenCLI, xiaohongshu-mcp,
xhs-cli]; probing order makes the desktop/server split automatic:
OpenCLI never probes alive headless, so servers fall through to
xiaohongshu-mcp; first fully-usable candidate wins, fixable (warn)
candidates only win when nothing is fully usable
- xiaohongshu-mcp probing: HTTP reachability of localhost:18060
(proxy-bypassed) + mcporter config presence; guides through
`mcporter config add` when half-wired
- opencli backend: treat a sleeping extension service worker as ready —
verified live that `daemon status` reports disconnected while any real
command wakes it; disambiguate "sleeping" vs "never installed" via the
Chrome Extensions directory on disk (fixes active_backend flapping
between OpenCLI and xhs-cli across doctor runs)
- install: desktop installs OpenCLI; server prints the xiaohongshu-mcp
guide (binary to ~/.agent-reach/tools/, QR login, mcporter add);
xhs-cli is no longer installed by default (upstream unmaintained since
2026-03) but existing installs keep working as the last candidate
- skill/references/social.md: xiaohongshu section rewritten as three
backend command groups keyed off `doctor --json` active_backend,
including the 120s-timeout and login-first caveats for the mcp path
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- new agent_reach/backends/opencli.py: probes install + daemon/extension
state via `opencli daemon status` (pure query — `opencli doctor`
auto-starts the daemon, a side effect health checks must avoid)
- `agent-reach install --channels opencli`: npm install + Chrome Web
Store guide (extension install cannot be automated — Chrome security
model — so we print the one-click path)
- server env skips OpenCLI (rides a real desktop Chrome session)
- channels will adopt it as a backend candidate in follow-up PRs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- backends is now an ordered candidate list (first = preferred); channels
report the backend actually serving via active_backend, surfaced in the
doctor text report and --json
- new agent_reach/probe.py really executes upstream commands and tells
apart missing / broken (stale venv shebang after a system Python
upgrade) / timeout, with a reinstall prescription for broken installs
- all 13 channels migrated off which()-only checks: fixes bilibili
false-positive "bili-cli 可用" on broken shims, misleading xiaohongshu
"连接失败", rdt OSError crashing doctor, mcporter breakage masquerading
as "未配置"
- twitter: 15s probe + 1 retry (flaky 10s timeout), broken twitter-cli
now falls back to bird instead of aborting the check
- doctor survives per-channel exceptions; config supports per-channel
backend override (<channel>_backend / <CHANNEL>_BACKEND env)
- fix skill install/uninstall crash on symlinked skill dirs (the
"[Errno None] None" warning from shutil.rmtree on a symlink)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Routes the two credential-writing call sites (xfetch session sync, no-Docker XHS cookie fallback) through the same atomic os.open(..., 0o600) pattern Config.save() already uses, closing a TOCTOU window where credential files were briefly world-readable (CWE-732). Also hardens _sync_bird_env() with shlex.quote against a shell-injection breakout in the sourceable env file — verified exploitable on the pre-fix code. Maintainer follow-up: scoped the injection-probe test markers to tmp_path so they can't poison reruns. 107 tests pass.
All three had rotted past honest usability:
- Douyin's upstream (yzfly/douyin-mcp-server) is archived and required a
4-step manual local-server setup nobody could complete
- Weibo depended on an unmaintained personal fork (mcp-server-weibo)
- WeChat full-article reading was increasingly blocked by anti-bot
(#339) while doctor still advertised it as zero-config
Removes the channel files, installers, skill routing/trigger entries,
reference sections and README rows (zh+en). Honest counts: 13 platforms,
6 zero-config. They can return when maintained upstreams exist.
Follows the v1.4.0 precedent of removing Discord/Toutiao (#234).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extracted from #318 (the UTF-8/doctor core, minus the env-wrapper feature):
- new agent_reach/utils/process.py: utf8_subprocess_env() +
mcporter_utf8_env_args() — Windows GBK consoles otherwise corrupt
Chinese output from mcporter/MCP child processes
- weibo/douyin/linkedin checks and weibo install/registration now pass
the UTF-8 env (and register the MCP server with --env PYTHONUTF8=1)
- youtube: extract _has_js_runtime_config() with an OSError guard so an
unreadable yt-dlp config can't crash doctor
- test_skill_command: open SKILL.md with explicit utf-8 (Windows GBK
default broke these tests)
Co-authored-by: chidao <2980933590@qq.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds agent_reach/transcribe.py (download → compress → chunk → transcribe with provider fallback, fully mocked tests). Maintainer follow-up on the branch: wired an agent-reach transcribe CLI subcommand + skill docs so agents can actually invoke it, added the missing configure openai-key branch the error hint referenced, removed two dead static methods. 103 tests pass; wheel-gate clean.
PyPI still only has rdt-cli 0.4.1 while the doctor hint required >=0.4.2, so the suggested install command always failed. Installs from the upstream GitHub repo pinned to the 0.4.2 commit instead, and syncs all four docs that still taught the PyPI path. Verified locally: clean-venv install from the pinned source yields rdt 0.4.2 and rdt status works. 86 tests pass. Fixes#294.
Rewrites the skill description with platform aliases (zh+en) and action triggers so agents reliably auto-invoke the skill. Maintainer follow-up on the branch: removed nonexistent skill_view tool reference, dropped finance category (no references/finance.md), updated the EN-locale test assertion to the new description. YAML validated, 85 tests pass. Fixes#316.
CRITICAL FIX: update.md was telling agents to uninstall bird CLI,
which broke users who had working bird installations. Now:
- twitter.py: prefers twitter-cli, falls back to bird/birdx if installed
- update.md: removed "clean up deprecated tools" step entirely
- Added explicit rule: "Never uninstall any existing tools the user already has"
- Tests cover twitter-cli primary + bird fallback + preference order
78 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Base install now only sets up lightweight zero-config channels (Web, YouTube,
GitHub, RSS, Exa, V2EX, Bilibili basic). Optional channels (Twitter, Weibo,
WeChat, Xiaoyuzhou, XiaoHongShu, Reddit, Bilibili full, Douyin, LinkedIn)
are installed on demand via --channels flag.
- Add --channels param to install subcommand
- Extract twitter/xhs/reddit/bili into independent install functions
- Remove heavy deps (weibo/xiaoyuzhou/wechat/twitter-cli/xhs-cli) from
default _install_system_deps() and _install_mcporter()
- Cookie import only triggers when cookie-needing channels are selected
- Doctor output: inactive optional channels summarized in one line
- install.md: two-step flow (basics → ask user which channels)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Discord only returns server metadata (no messages without Bot Token),
not useful enough. Toutiao search was fragile (HTML scraping). Both
can be revisited when better upstream tools appear.
75 tests passing.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Zero-config channel (tier=0). Uses Discord Invite API to read public
server info (no auth), and Exa via mcporter for content search.
Tested: discord.gg/python returns 419K members, description, channel.
104 tests passing.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Zero-config channel (tier=0). Searches so.toutiao.com by scraping
embedded JSON from script tags. Fixes URL extraction order from PR #207
(article_url is the primary field, not display.info.url). Adds read()
via Jina Reader. 89 tests passing.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Reddit blocks nearly all non-browser access at IP level (including ISP proxies).
Switch Reddit channel to use Exa exclusively:
- Search: web_search_exa with includeDomains: ["reddit.com"]
- Read: crawling_exa for full post + comments
- check() now verifies Exa availability instead of probing Reddit API
- tier changed from 1 (needs config) to 0 (zero config)
- Removed reddit_proxy from config, CLI, and setup guide
- Updated all docs (README, README_en, install.md, SKILL.md, references)
- Fixed xreach→bird references in references/social.md
Fixes#218, Fixes#222, Fixes#221
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Xueqiu stock API requires a login session token (xq_a_token) that
is generated by Xueqiu's frontend JavaScript and cannot be obtained by
simply visiting the homepage. This caused persistent HTTP 400 (error
code 400016) for all users.
Changes:
- _ensure_cookies(): add three-level priority — config file (saved by
--from-browser) → live Chrome cookies via browser_cookie3 → homepage
fallback. The homepage-only approach only ever got acw_tc (anti-DDoS
token), never xq_a_token.
- _get_json(): switch User-Agent from "agent-reach/1.0" to a real Chrome
UA, and add Referer: https://xueqiu.com/ to all API requests.
- get_hot_posts(): replace the defunct /statuses/hot/listV3.json endpoint
(returns empty body) with the v4 public timeline endpoint; correctly
parse item.data as a JSON string to extract author, text, and likes.
- cookie_extract.py: add Xueqiu to PLATFORM_SPECS and configure_from_browser
so that `agent-reach configure --from-browser chrome` now also saves
Xueqiu cookies (only when xq_a_token is present).
- check(): improve error message to direct users to --from-browser instead
of suggesting a proxy.
- Fix urllib.parse.quote usage (was using urllib.request.quote).
- Update tier and backends description to reflect cookie requirement.
- Add 2 new tests: cookie loading from config, Referer/UA header verification.
- Update docs: README, install guide, troubleshooting, SKILL.md, CHANGELOG.
- Add 'agent-reach skill --install/--uninstall' command for explicit skill management
- Make 'agent-reach doctor' auto-install skill if not present (fixes#154)
- Add format_xhs_result() to strip bloated XHS JSON to essential fields (fixes#134)
- Add 'agent-reach format xhs' CLI command (pipe mcporter output to clean it)
- Update SKILL.md with XHS formatter usage tip
- Add tests for both features (11 new tests, 73/73 total pass)
Co-authored-by: Panniantong <panniantong@users.noreply.github.com>
* feat: add Xueqiu (雪球) channel for stock quotes and community posts
Add a Tier 0 (zero-config) channel for Xueqiu, China's popular stock
market and investment community platform. Uses auto-generated session
cookies via http.cookiejar — no login required.
Supported methods:
- get_stock_quote(symbol) — real-time quotes (A/HK/US markets)
- search_stock(query) — search by name or code
- get_hot_posts(limit) — trending community posts
- get_hot_stocks(limit, stock_type) — popular stocks leaderboard
Inspired by https://github.com/jackwener/opencli xueqiu implementation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add Xueqiu to README platform tables, remove stale Instagram ref
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: fernando_jacob <f.jacob1996@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
PR #170 added Rich markup tags to doctor output, but the test
still asserted against plain text. Strip markup before assertion.
Co-authored-by: Panniantong <panniantong@users.noreply.github.com>
- Replace xreach CLI with bird (@steipete/bird) as Twitter/X backend
- bird uses AUTH_TOKEN/CT0 env vars (simpler than xreach's session.json)
- Accept both 'bird' and 'birdx' binary names
- Remove version detection logic (bird v0.8.0 is the baseline)
- Write credentials.env to ~/.config/bird/ for easy sourcing
- Keep xfetch session.json sync for backward compatibility
- Update SKILL.md commands: bird search/read/user-tweets/thread
- Update install/uninstall to use npm @steipete/bird
- All 52 tests pass
* feat(channels): add V2EX support via public API
V2EX provides a public JSON API that requires no authentication.
This PR adds:
- agent_reach/channels/v2ex.py: V2EXChannel (tier=0, zero-config)
- can_handle() matches v2ex.com URLs
- check() verifies API reachability via urllib (no extra deps)
- Register V2EXChannel in channels/__init__.py
- SKILL.md: add V2EX section with curl examples for hot topics,
node browsing, topic detail, replies, and user info
- tests/test_channels.py: URL matching + mocked ok/warn check tests
V2EX API endpoints used:
GET /api/v2/topics/hot — hot topics
GET /api/topics/show.json — node topics / topic detail
GET /api/replies/show.json — topic replies
GET /api/members/show.json — user info
* feat(channels): expand V2EX channel with data-fetching methods
Add get_hot_topics, get_node_topics, get_topic, get_user, and search
methods to V2EXChannel using stdlib urllib only (no new dependencies).
Update unit tests and SKILL.md with Python call examples.
* feat(v2ex): add data fetching methods to V2EXChannel
- YouTube: warn when only Node.js is installed but yt-dlp config file
is missing (previously returned "ok" incorrectly)
- Douyin: use `mcporter list` instead of calling with a hardcoded
invalid share URL that always fails
- cli: replace bare `except:` with `except Exception:` in
`_detect_environment` to avoid catching KeyboardInterrupt/SystemExit
- cli: fix unclosed file handle for cloud VM detection
- config: use `os.open()` with 0o600 mode to eliminate permission
race window when saving credentials
Before: everything under tier 0 showed ✅ with vague descriptions
After: each channel shows its actual capability and limitations
Changes:
- GitHub: 'Public repos only. Set github_token for private repos'
- Twitter: shows 'Full access' vs 'Read-only' depending on birdx
- Bilibili: ⚠️ warning on servers about potential IP blocks
- XiaoHongShu: friendly message when no cookie (was showing Jina 451)
- Doctor format: tier 0 items now show detailed status messages, not just ✅
- README: platform table updated to match reality (removed exaggerated claims)
- README: doctor example updated to show new honest format