OpenCLI Documentation

Make Any Website into CLI & Use your logged-in browser by AI agent.

30,516 stars JavaScript JavaScript 129 files · ~125,348 tokens #ai-agent#ai-agents#ai-tools#browser-automation#browser-use#cli#playwright
RAW Doc

Technical Documentation: jackwener/OpenCLI

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

OpenCLI

Convert any website into a CLI & run Browser Use on your logged-in Chrome.
Turn websites and browser sessions into deterministic interfaces for humans and AI agents.
Or run Browser Use against any page — navigate, fill forms, click, extract, automate.





OpenCLI is a general-purpose browser automation CLI for AI agents and an agent-browser alternative. Navigate, inspect, click, fill forms, extract, and screenshot websites without a site adapter. Built-in adapters add reusable, deterministic site commands. See OpenCLI vs agent-browser and migration.

OpenCLI gives you one surface for three different kinds of automation:

  • Use built-in adapters for sites like Bilibili, Zhihu, Xiaohongshu, Reddit, HackerNews, Twitter/X, and many more.
  • Let AI Agents operate any website — install the opencli-browser skill in your AI agent (Claude Code, Cursor, etc.), and it can navigate, click, type/fill, extract, and inspect any page through your logged-in browser via opencli browser primitives.
  • Write new adapters end-to-end with opencli browser + the opencli-adapter-author skill, which guides from first recon through field decoding, code, and opencli adapter test.

Agent command contract

Commands default to JSON: { "ok": true, "data": ... }; failures return
{ "ok": false, "error": { "code": "...", "message": "...", "hint": "..." } }
on stdout with a nonzero exit code. Logs use stderr. Explicit human formats,
help, version and completion retain their own formats; browser follow modes use JSON Lines.

sh
opencli list search --site github
opencli browser open https://example.com --session research
opencli browser network --static --session research
opencli browser chrome describe
opencli adapter check github/search

list returns compact, paginated capabilities (commands, total, nextOffset);
read arguments with <command> --help -f json. Page scope is --session, native
Chrome calls need no session. Adapter authoring is grouped under adapter init|check|test.
state --diagnostics and network --static replace analyze and discover.
This changes CLI syntax and JSON output. JS adapters keep cli({...}),
func(args) and func(page, args); adapter defaultFormat no longer changes the CLI default.

Quick Start

1. Install OpenCLI

For desktop use, start with OpenCLIApp. It bundles the OpenCLI runtime,
keeps the managed opencli command installed, and gives you a system tray UI
for setup, diagnostics, updates, browser-login keepalive, and Web → Markdown.

Option A — OpenCLIApp (recommended for macOS / Windows):
Download the latest app from https://opencli.info/download, install it, then
open the app once and use the System page to install or repair the opencli
command.

Option B — npm global install (CLI-only / CI / servers):
OpenCLI requires Node.js >= 20.18.1 when installed through npm.

bash
node --version
npm install @jackwener/opencli

2. Install the Browser Bridge Extension

OpenCLI connects to Chrome/Chromium through a lightweight Browser Bridge extension plus a small local daemon. The daemon auto-starts when needed.

Option A — Chrome Web Store (recommended):
Install OpenCLI from the Chrome Web Store.

Option B — Manual install:

  1. Download the latest opencli-extension-v{version}.zip from the GitHub Releases page.
  2. Unzip it, open chrome://extensions, and enable Developer mode.
  3. Click Load unpacked and select the unzipped folder.

3. Verify the setup

bash
opencli doctor

4. Optional: name your Chrome profile

Each Chrome profile runs its own OpenCLI extension instance. If you use multiple Chrome profiles, list the connected profiles and assign local aliases:

bash
opencli profile list
opencli profile rename <contextId> work
opencli profile use work
opencli --profile work browser main state

With only one connected profile, OpenCLI uses it automatically. With multiple connected profiles and no default, OpenCLI asks you to choose instead of guessing.

5. Run your first commands

bash
opencli list
opencli hackernews top --limit 5
opencli bilibili hot --limit 5

For Humans

Use OpenCLI directly when you want a reliable command instead of a live browser session:

  • opencli list shows every registered command.
  • opencli <site> <command> runs a built-in or generated adapter.
  • opencli doctor helps diagnose browser connectivity.

Extending OpenCLI

If you want to add your own commands, start with the Extending OpenCLI guide. README keeps this short; the guide covers the directory layout, source-control model, and install commands.

Need Recommended path
Keep personal website commands in your own Git repo opencli plugin create + opencli plugin install file://...
Quickly draft a private local adapter opencli adapter init <site>/<command> in ~/.opencli/clis/
Modify an official adapter locally opencli adapter eject <site> + opencli adapter reset <site>
Publish or install third-party commands opencli plugin install github:user/repo

Close temporary browser tabs after use

To remove temporary owned tabs when a workflow finishes:

bash
export OPENCLI_CLOSE_OWNED_TAB=1
opencli web read --url https://example.com --stdout true
# Multi-step browser sessions stay open between calls; close explicitly at the end:
opencli browser close --session research

This opts into closing only the current lease's owned tab. Chrome closes its
window automatically if no tabs remain; existing user pages and other sessions
are preserved. Bound tabs are detached and kept open. The default reusable
container policy, idle expiry, --keep-tab true, and persistent site sessions
remain unchanged. Use --site-session ephemeral for one-shot reads of adapters
that otherwise keep a persistent site session.

Cleanup uses a dedicated action, so older extensions reject it without releasing
the lease, and requires an extension acknowledgement. If cleanup fails or the extension
is too old, a warning reports it separately from the site action. Retry explicit
browser cleanup, or close a remaining one-shot adapter tab manually; do not
repeat a completed site write. Explicit browser close also exits
with an error; a one-shot adapter can still return its already-completed result.

For AI Agents

OpenCLI's browser commands are designed to be used by AI Agents — not run manually. Install skills into your AI agent (Claude Code, Cursor, etc.), and the agent operates websites on your behalf using your logged-in Chrome session.

Install skills (also refreshes existing installs)

bash
npx skills add jackwener/opencli

Or install only what you need:

bash
npx skills add jackwener/opencli --skill opencli-adapter-author
npx skills add jackwener/opencli --skill opencli-autofix
npx skills add jackwener/opencli --skill opencli-browser
npx skills add jackwener/opencli --skill opencli-usage

Which skill to use

Skill When to use Example prompt to your AI agent
opencli-adapter-author Write a reusable adapter for a new site or add a command to an existing site "Write an adapter for douyin trending" / "Make a command that grabs the top posts from this page"
opencli-autofix Repair a broken adapter when a built-in command fails "opencli zhihu hot is returning empty — fix it"
opencli-browser Drive a real Chrome page ad-hoc — navigate, fill forms, click, extract "Help me check my Xiaohongshu notifications" / "Help me fill out this form" / "Use browser commands to scrape this page"
opencli-usage Quick reference for all OpenCLI commands and sites "What commands does OpenCLI have for Twitter?"

How it works

Once opencli-browser is installed, your AI agent can:

  1. Navigate to any URL using your logged-in browser
  2. Read page content via structured DOM snapshots (not screenshots)
  3. Interact — click buttons, fill forms, select options, press keys
  4. Extract data from the page or intercept network API responses
  5. Wait for elements, text, or page transitions

The agent handles all the opencli browser commands internally — you just describe what you want done in natural language.

Skill references:

Available browser commands include open, state, click, type, fill, select, keys, wait, get, find, extract, frames, screenshot, scroll, back, eval, network, tab list, tab new, tab select, tab close, chrome describe, chrome call, and close.

opencli browser commands require a --session <name> option for page operations. opencli browser --session work open and opencli browser --session work tab new [url] both return a target ID. Use opencli browser --session work tab list to inspect target IDs, then pass --tab <targetId> to route a command to a specific tab. tab new creates a new tab without changing the default browser target; only tab select <targetId> promotes that tab to the default target for later untargeted commands in the same session.

Writing a new adapter

When the site you need is not yet covered, use the opencli-adapter-author skill end-to-end:

  1. Recon the site and pick a pattern (SPA / SSR / JSONP / Token / Streaming).
  2. Discover the right endpoint — network inspection, initial state, bundle search, token trace, or interceptor fallback.
  3. Pick auth — PUBLIC / COOKIE / INTERCEPT / UI / LOCAL.
  4. Decode response fields and design output columns.
  5. opencli browser recon analyze → opencli browser recon init <site>/<name> → write adapter → opencli browser recon verify <site>/<name>.
  6. Site knowledge persists to ~/.opencli/sites/<site>/ so the next adapter for the same site starts from context.

Configuration

Variable Default Description
OPENCLI_PROFILE — Browser Bridge profile alias/contextId to use when multiple Chrome profiles are connected
OPENCLI_WINDOW command default Set to foreground or background to override Browser Bridge window placement. Browser-backed commands also accept --window <foreground|background>.
OPENCLI_SITE_SESSION adapter default Set to ephemeral or persistent to override siteSession metadata for browser-backed adapter commands. ephemeral releases the one-shot tab when the command finishes, and the automation window stays open as a reusable container; persistent reuses the site's session. Per-command --site-session takes precedence.
OPENCLI_CLOSE_OWNED_TAB 0 Set to 1 to close the current owned tab on explicit session close or one-shot adapter cleanup instead of keeping a blank placeholder. Requires a supporting Browser Bridge extension.
OPENCLI_SITE_SLOTS — Pool sites onto warm persistent tabs, e.g. xiaohongshu:1:1500-3000,weibo:2 (site:poolSize[:minMs[-maxMs]]). Each command run borrows one slot tab exclusively (reads included) and queues when all are busy; the optional interval spaces runs by a jittered delay. Tabs share one automation window and only its active tab renders, so with poolSize > 1 render-dependent commands (lazy-loaded lists) can stall on background slots — use 1 for those and for risk-controlled sites. --site-session ephemeral opts one invocation out.
OPENCLI_BROWSER_CONNECT_TIMEOUT 45 Seconds to wait for browser connection
OPENCLI_BROWSER_COMMAND_TIMEOUT 60 Seconds to wait for a single browser command
OPENCLI_BROWSER_IDLE_TIMEOUT extension default Owned session idle timeout in seconds; per-command idleTimeout takes precedence. Does not extend explicit cleanup: ephemeral adapters normally release their tab at command completion. Bound tabs and persistent adapter sessions ignore idle timeouts. Releasing a session keeps its reusable window container open.
OPENCLI_CDP_ENDPOINT — Chrome DevTools Protocol endpoint for remote browsers
OPENCLI_CDP_TARGET — Filter CDP targets by URL substring (e.g. detail.1688.com)
OPENCLI_VERBOSE false Enable verbose logging (-v flag also works)
DEBUG_SNAPSHOT — Set to 1 for DOM snapshot debug output

opencli browser * requires an explicit --session <name> option for page operations, uses a foreground browser window by default, and keeps that session's tab lease until opencli browser --session <session> close or idle cleanup. Browser-backed adapters use a background adapter window and release one-shot tab leases by default. Interactive adapters can declare siteSession: 'persistent' to keep a stable site tab for continuity; pass --site-session ephemeral for a one-shot tab.

Built-in Commands

Site Commands
xiaohongshu search ask note comments feed user download publish follow unfollow notifications creator-notes creator-notes-summary creator-note-detail creator-profile creator-stats
bilibili hot search history feed ranking download comments dynamic favorite following follow unfollow me subtitle summary video user-videos creator-stats
zhihu hot search question download follow like favorite comment answer
hackernews top new best ask show jobs search user
hltv search player-summary player-matches player-form player-map-pool player-vs-team player-teammate-impact player-duel match-map match-series team-matches team-map-pool event-matches
geogebra eval add-point add-line add-circle add-polygon triangle hexagon list info
linkedin connect inbox job-detail jobs-preferences post-analytics posts profile-experience profile-projects profile-read profile-analytics safe-send search services-read sent-invitations thread-snapshot timeline salesnav-search salesnav-inbox salesnav-message salesnav-thread
reddit hot frontpage popular search subreddit read user user-posts user-comments upvote upvoted save saved comment subscribe
twitter trending search timeline tweets lists list-tweets list-create list-delete list-add list-add-batch list-remove list-remove-batch bookmarks post download profile article like likes notifications reply reply-dm thread follow unfollow followers following block unblock bookmark unbookmark delete hide-reply accept
claude ask send new status read history detail
gemini new ask image deep-research deep-research-result
notebooklm status list open current get history summary note-list notes-get source-list source-get source-fulltext source-guide
amazon bestsellers search product offer discussion movers-shakers new-releases rankings
upwork search feed detail
slock message-send message-read message-search channel-list channel-info channel-create channel-members channel-join task-list task-create task-claim task-status task-convert task-delete thread-list thread-follow attachment-upload attachment-download bookmark-add inbox dm-list server-list server-use whoami
huodongxing events
midjourney login whoami settings quota generate describe history status action download

Curated highlights — → see all 100+ supported sites & commands (douyin / weibo / spotify / 1688 / quark / nowcoder / google-scholar / hupu / xianyu / weread / weread-official / xiaoyuzhou / Chess.com / and more).

Download Support

OpenCLI supports downloading images, videos, and articles from supported platforms.

Platform Content Types Notes
xiaohongshu Images, Videos Downloads all media from a note
rednote Images, Videos Downloads all media from a signed rednote note URL
bilibili Videos Requires yt-dlp installed
twitter Images, Videos From user media tab or single tweet
douban Images Poster / still image lists
pixiv Images Original-quality illustrations, multi-page
1688 Images, Videos Downloads page-visible product media from item pages
xiaoyuzhou Audio, Transcript Downloads episode audio and transcript JSON/text with local credentials
zhihu Column articles, answers (Markdown) Exports with optional image download
weixin Articles (Markdown) WeChat Official Account articles

For video downloads, install yt-dlp first: brew install yt-dlp

bash
opencli xiaohongshu download "https://www.xiaohongshu.com/search_result/<id>?xsec_token=..." --output ./xhs
opencli xiaohongshu download "https://xhslink.com/..." --output ./xhs
opencli rednote download "https://www.rednote.com/search_result/<id>?xsec_token=..." --output ./rednote
opencli bilibili download BV1xxx --output ./bilibili
opencli twitter download elonmusk --limit 20 --output ./twitter
opencli 1688 download 841141931191 --output ./1688-downloads
opencli xiaoyuzhou download 69b3b675772ac2295bfc01d0 --output ./xiaoyuzhou
opencli xiaoyuzhou transcript 69dd0c98e2c8be31551f6a33 --output ./xiaoyuzhou-transcripts

opencli xiaoyuzhou download and transcript require local Xiaoyuzhou credentials in ~/.opencli/xiaoyuzhou.json.

Output Formats

All built-in commands support --format / -f with json (default), table, yaml, md, and csv.

bash
opencli bilibili hot -f json    # Pipe to jq or LLMs
opencli bilibili hot -f csv     # Spreadsheet-friendly
opencli bilibili hot -v         # Verbose: show pipeline debug steps

Exit Codes

opencli follows Unix sysexits.h so CI / scripts can branch on failure mode: 0 success, 66 empty result, 69 Browser Bridge down, 75 timeout, 77 auth required, 78 config error, 130 Ctrl-C. Full reference: docs/guide/exit-codes.md.

Plugins

Extend OpenCLI with community-contributed adapters:

bash
opencli plugin install github:user/opencli-plugin-my-tool
opencli plugin list
opencli plugin update --all
opencli plugin uninstall my-tool

Albato, Goofish and Taobao use local adapter-subdirectory installation; see the installation notes.

Plugin Type Description
opencli-plugin-albato JS Albato automation workflow management: scenario inspection, start/pause, failure diagnosis, and retry
opencli-plugin-amap JS AutoNavi / 高德地图 spot & route extraction, coordinate decoders (GCJ-02 & WGS-84), and SSR search
opencli-plugin-github-trending JS GitHub Trending repositories
opencli-plugin-goofish JS Goofish / 闲鱼 buyer orders, favorites, IM chat, profile, item search, and fulfillment stats
opencli-plugin-hot-digest JS Multi-platform trending aggregator
opencli-plugin-juejin JS 稀土掘金 (Juejin) hot articles
opencli-plugin-taobao JS Taobao buyer chat history, order history, bought shops, favorites, and keyword-based chat summaries
opencli-plugin-vk JS VK (VKontakte) wall, feed, and search
opencli-plugin-x-article-publisher JS Publish Markdown with local images as X long-form Articles via OpenCLI and xPoster

See Plugins Guide for creating your own plugin.

Testing

See TESTING.md for how to run and write tests.

Troubleshooting

  • "Extension not connected" — Ensure the Browser Bridge extension is installed from the Chrome Web Store and enabled in chrome://extensions.
  • "attach failed: Cannot access a chrome-extension:// URL" — Another extension may be interfering. Try disabling other extensions temporarily.
  • Empty data or 'Unauthorized' error — Your Chrome/Chromium login session may have expired. Navigate to the target site and log in again.
  • Node API errors / missing fetch / startup crash on old Node — OpenCLI requires Node.js >= 20.18.1. Run node --version, upgrade Node if needed, then retry.
  • Daemon issues — Check status: curl localhost:19825/status · View logs: curl localhost:19825/logs

Star History

License

Apache-2.0


Overview (`cases/README.md`)

Use Cases

Real-world examples of how people use OpenCLI.

Contributing

Want to share your use case? Submit a PR that adds a new .md file to this directory.

Each file is one use case — describe what you wanted to do, which commands you used, and the result.


Overview (`extension/README.md`)

OpenCLI Browser Bridge Extension

The extension connects Chrome tabs to the local OpenCLI daemon. It uses Chrome
extension APIs only as a transport and browser-control layer for explicit CLI
commands.

Permission Notes

  • debugger: sends CDP commands to OpenCLI-controlled or bound tabs.
  • tabs / tabGroups: manages the dedicated OpenCLI automation container and
    reports selected tab metadata back to the CLI.
  • cookies: reads cookies for browser-backed adapters that need authenticated
    fetches.
  • downloads: surfaces download lifecycle to opencli browser wait download.
    The extension observes started / in-progress / completed / failed downloads so
    the CLI can wait for a file triggered by an automation command. OpenCLI
    filters by the command's filename/URL pattern and timeout, and does not modify,
    redirect, or persist browser download history.

Suggested Chrome Web Store justification for downloads:

This extension uses chrome.downloads to surface download lifecycle
(started / in-progress / completed / failed) to the OpenCLI command-line tool,
so agents can wait for downloads triggered during an automation workflow. The
command filters by a user-provided filename or URL pattern and timeout. We do
not modify, redirect, or persist user download history.


Index (`docs/index.md`)


layout: home
hero:
name: OpenCLI
text: Make any website your CLI
tagline: General-purpose browser automation · Reuse Chrome login · Reusable site commands
actions:
- theme: brand
text: Get Started
link: /guide/getting-started
- theme: alt
text: OpenCLI vs agent-browser
link: /guide/agent-browser-alternative
- theme: alt
text: View on GitHub
link: https://github.com/jackwener/opencli

features:

  • icon: 🌐
    title: Browser Automation
    details: "General-purpose browser control for AI agents: navigate, click, fill, extract, and screenshot. No site adapter required."
  • icon: 🔐
    title: Account Safe
    details: Reuses Chrome's logged-in state. Your credentials never leave the browser — no tokens, no exposed passwords.
  • icon: 🤖
    title: AI Agent Ready
    details: "Browser primitives plus adapter-authoring skills give AI agents a repeatable loop for recon, extraction, verification, and adapter writing."
  • icon: 💰
    title: No Built-in LLM Dependency
    details: Commands run without LLM inference. An AI agent choosing actions still has its own model costs.
  • icon: 🔁
    title: Deterministic Adapters
    details: Same command, same output schema, every time. Pipeable, scriptable, CI-friendly.


Adapters Index (`docs/adapters/index.md`)

All Adapters

Run opencli list for the live registry.

Browser Adapters

Site Commands Mode
twitter trending bookmarks profile search timeline thread following followers notifications post reply delete like likes lists article follow unfollow bookmark unbookmark download accept reply-dm block unblock hide-reply 🔐 Browser
reddit hot frontpage popular search subreddit read user user-posts user-comments upvote save comment reply subscribe saved upvoted 🔐 Browser
tieba hot posts search read 🔐 Browser
hupu hot search detail mentions reply like unlike 🌐 / 🔐
huodongxing events 🌐 Public / Browser
bilibili hot search me favorite history feed feed-detail subtitle summary video dynamic ranking following follow unfollow user-videos download creator-stats 🔐 Browser
zhihu hot recommend search question answer-detail answer-comments download follow like favorite comment answer 🔐 Browser
xiaohongshu search ask notifications feed user note comments comment comment-delete download publish follow unfollow creator-notes creator-note-detail creator-notes-summary creator-profile creator-stats 🔐 Browser
rednote search note comments user download feed notifications 🔐 Browser
xiaoe courses detail catalog play-url content 🔐 Browser
xueqiu feed hot-stock hot search stock comments watchlist earnings-date fund-holdings fund-snapshot 🔐 Browser
youtube search video transcript comments channel playlist feed history watch-later subscriptions like unlike subscribe unsubscribe comment 🔐 Browser
youdao note 🌐 Public
zlibrary search info 🔐 Browser
v2ex hot latest topic node user member replies nodes daily me notifications 🌐 / 🔐
bloomberg main markets economics industries tech politics businessweek opinions green crypto pursuits feeds news 🌐 / 🔐
weibo hot search feed user user-posts me post favorites publish delete comments 🔐 Browser
toutiao articles hot recommend 🌐 / 🔐
linkedin search job-detail jobs-preferences people-search post-analytics posts profile-projects profile-read profile-analytics services-read timeline 🔐 Browser
linkedin-learning search trending course 🔐 Browser
coupang search product add-to-cart 🔐 Browser
boss search detail recommend joblist greet batchgreet send chatlist chatmsg invite mark exchange resume stats 🔐 Browser
51job search hot detail company 🔐 Browser
powerchina search 🔐 Browser
ctrip search hotel-suggest hotel-search hotel flight flight-round train bus ferry cruise tour package attraction 🌐 / 🔐
trip search flight flight-round hotel-search hotel attraction train car transfer tour package deals 🔐 Browser
booking search 🌐 Public
reuters search article-detail 🔐 Browser
hltv search player-summary player-matches player-form player-map-pool player-vs-team player-teammate-impact player-duel match-map match-series team-matches team-map-pool event-matches 🌐 Browser
smzdm search 🔐 Browser
jike feed search post topic user create comment like repost notifications 🔐 Browser
ke ershoufang zufang xiaoqu chengjiao 🔐 Browser
jimeng generate history 🔐 Browser
midjourney login whoami settings quota generate describe history status action download 🔐 Browser
yollomi generate video edit upload models remove-bg upscale face-swap restore try-on background object-remover 🔐 Browser
linux-do feed search categories tags topic topic-content user-posts user-topics 🔐 Browser
chaoxing assignments exams 🔐 Browser
grok ask send read history detail export export-all new status image 🔐 Browser
kimi ask send read history detail new status usage model mode copy-message storage-keys 🔐 Browser
chatgpt ask send read history detail deep-research-result new status image model project-list project-file-add 🔐 Browser
gemini new ask image deep-research deep-research-result 🔐 Browser
geogebra eval add-point add-line add-circle add-polygon triangle hexagon list info 🌐 Browser
claude ask send new status read history detail 🔐 Browser
maimai search-talents 🔐 Browser
yuanbao ask send new status read history detail 🔐 Browser
notebooklm status list open current get source-list source-get source-fulltext source-guide history note-list notes-get summary 🔐 Browser
doubao status new send read ask history detail meeting-summary meeting-transcript 🔐 Browser
weread shelf search book ranking notebooks highlights notes 🔐 Browser
douban search top250 subject photos download marks reviews movie-hot book-hot 🔐 Browser
facebook feed profile search friends groups events notifications memories add-friend join-group 🔐 Browser
imdb search title top trending person reviews 🌐 / 🔐
indeed search job 🍪 Browser
upwork search feed detail 🔐 Browser
instagram explore profile search user followers following follow unfollow like unlike comment save unsave saved 🔐 Browser
pinterest search-pins search-boards search-users pin user user-pins user-boards board-pins board-sections download save pin-create pin-update pin-delete board-create board-update board-delete board-section-create board-section-delete 🔐 Browser
medium feed search user 🔐 Browser
mubu doc docs notes recent search 🔐 Browser
sinablog hot search article user 🔐 Browser
substack feed search publication 🔐 Browser
pixiv ranking search user illusts detail download 🔐 Browser
proton login whoami inbox 🔐 Browser
tiktok explore search profile user following follow unfollow like unlike comment save unsave live notifications friends 🔐 Browser
google images news search suggest trends 🌐 / 🔐
jd item 🔐 Browser
amazon bestsellers search product offer discussion movers-shakers new-releases 🔐 Browser
1688 search item assets download store 🔐 Browser
gitee trending search user 🌐 / 🔐
web read 🔐 Browser
weixin search download drafts create-draft 🌐 / 🔐
36kr news hot search article 🌐 / 🔐
uisdc news 🌐 Public
aibase news 🌐 Public
producthunt posts today hot browse 🌐 / 🔐
ones login me token-info tasks my-tasks task worklog logout 🔐 Browser Bridge + ONES_BASE_URL
band bands posts post mentions 🔐 Browser
baidu-scholar search 🌐 Public
zsxq groups dynamics topics topic search 🔐 Browser
bluesky search profile user feeds followers following thread trending starter-packs 🌐 Public
douyin profile videos user-videos activities collections hashtag location stats publish draft drafts delete update 🔐 Browser
google-scholar search cite profile 🌐 Public
gov-law search recent 🌐 Public
gov-policy search recent 🌐 Public
xianyu search item inbox messages chat reply publish 🔐 Browser
quark ls mkdir mv rename rm save share-tree 🔐 Browser
uiverse code preview 🔐 Browser
nowcoder hot trending topics recommend creators companies jobs search suggest experience referral salary papers practice notifications detail 🌐 / 🔐
wanfang search 🌐 Public
eastmoney hot-rank 🔐 Browser
tdx hot-rank 🔐 Browser
ths hot-rank 🔐 Browser
dianping search shop 🔐 Browser
slock message-send message-read message-search channel-list channel-info channel-create channel-members channel-join task-list task-create task-claim task-status task-convert task-delete thread-list thread-follow attachment-upload attachment-download bookmark-add inbox dm-list server-list server-use whoami 🔐 Browser

Public API Adapters

Site Commands Mode
hackernews top new best ask show jobs search user 🌐 Public
bbc news 🌐 Public
devto top tag user 🌐 Public
juejin recommend hot 🌐 Public
dictionary search synonyms examples 🌐 Public
apple-podcasts search episodes top 🌐 Public
xiaoyuzhou podcast podcast-episodes episode history download transcript (local credentials required) 🔑 Local API
yahoo-finance quote 🌐 Public
archive search item wayback snapshots 🌐 Public
arxiv search paper 🌐 Public
dblp search author paper venue 🌐 Public
pubmed search article author citations related clinical-trial review mesh journal 🌐 Public
semanticscholar paper citations recommendations search 🌐 Public
openreview search venue author paper reviews 🌐 Public
paperreview submit review feedback 🌐 Public
barchart quote options greeks flow 🌐 Public
binance price prices ticker pairs trades depth asks klines top gainers losers 🌐 Public
hf top paper models datasets spaces 🌐 Public
sinafinance news rolling-news stock stock-rank 🌐 / 🔐
spotify auth status play pause next prev volume search queue shuffle repeat 🔑 OAuth API
jira issue search comments attachments links 🔑 Atlassian REST API
confluence page search create update 🔑 Atlassian REST API
stackoverflow hot search bounties unanswered tag user read related 🌐 Public
wikipedia search summary random trending 🌐 Public
lesswrong curated frontpage new top top-week top-month top-year read comments user user-posts tag tags sequences shortform 🌐 Public
lobsters hot newest active tag read 🌐 Public
steam top-sellers 🌐 Public
coingecko top coin trending exchanges categories derivatives global 🌐 Public
npm search package downloads 🌐 Public
pypi package downloads 🌐 Public
crates search crate 🌐 Public
mdn search 🌐 Public
nvd cve 🌐 Public
dockerhub search image 🌐 Public
rubygems search gem 🌐 Public
homebrew formula cask popular 🌐 Public
packagist search package 🌐 Public
maven search artifact 🌐 Public
openalex search work 🌐 Public
defillama protocols protocol 🌐 Public
endoflife product 🌐 Public
osv vulnerability query 🌐 Public
github-trending repos 🌐 Public
goproxy module versions 🌐 Public
tvmaze search show 🌐 Public
rfc rfc 🌐 Public
wikidata search entity 🌐 Public
chess stats games game analyze 🌐 Public / Browser
lichess user top 🌐 Public
rest-countries country region 🌐 Public
nuget search package 🌐 Public
flathub search app 🌐 Public
oeis search sequence 🌐 Public
wttr current forecast 🌐 Public
openfda drug-label food-recall 🌐 Public
12306 stations trains train price me passengers orders 🔐 Browser
suno generate status list download 🔐 Browser
weread-official search shelf book notes review readdata discover list-apis 🌐 Public
qwen new ask send read status history detail image 🔐 Browser
deepseek new ask send read status history detail usage 🔐 Browser
yahoo search 🔐 Browser
1point3acres hot latest forums forum thread digest search user notifications 🌐 Public
brave search 🔐 Browser
duckduckgo search suggest 🔐 Browser
cnki search 🔐 Browser
flomo memos 🔐 Browser
jianyu search detail 🔐 Browser
taobao search detail reviews cart add-cart 🔐 Browser
minimax music 🔑 MiniMax API

Guide Getting Started (`docs/guide/getting-started.md`)

Getting Started

Make any website your CLI.
Zero risk · Reuse Chrome login · AI-powered discovery · Browser automation



OpenCLI turns any website into a command-line interface — Bilibili, Zhihu, 小红书, Twitter/X, Reddit, YouTube, and many more — powered by browser session reuse and AI-native discovery.

OpenCLI is a general-purpose browser automation CLI and an agent-browser alternative. Browse unfamiliar sites without adapters; use adapters for reusable site commands. See the migration guide.

Highlights

  • Browser Automation — browser gives AI agents direct browser control: click, type/fill, extract, screenshot — fully scriptable.
  • Website → CLI — Turn any website into a deterministic CLI: 100+ site surfaces are already registered, or author your own with the opencli-adapter-author skill.
  • Account-safe — Reuses Chrome's logged-in state; your credentials never leave the browser.
  • AI Agent ready — opencli browser * primitives (open / network / state / eval) and adapter init|check|test drive the adapter-authoring loop.
  • No built-in LLM dependency — Commands run without LLM inference; an AI agent orchestrating actions still has its own model costs.
  • Deterministic adapters — Site commands provide structured output schemas. Pipeable, scriptable, CI-friendly.

Quick Start

Install via npm

bash
npm install @jackwener/opencli

Browse without a site adapter

Set up Browser Bridge, then run:

bash
opencli doctor
opencli browser --session work open https://example.com
opencli browser --session work state
opencli browser --session work extract
opencli browser --session work close

Install the opencli-browser skill so your AI agent can use the same browser primitives:

bash
npx skills add jackwener/opencli --skill opencli-browser

Basic Usage

bash
opencli list                              # See all commands
opencli hackernews top --limit 5          # Public API, no browser
opencli bilibili hot --limit 5            # Browser command
opencli zhihu hot -f json                 # JSON output

Output Formats

All built-in commands support --format / -f:

bash
opencli bilibili hot -f table   # Rich terminal table
opencli bilibili hot -f json    # JSON (pipe to jq or LLMs)
opencli bilibili hot -f yaml    # YAML (human-readable)
opencli bilibili hot -f md      # Markdown
opencli bilibili hot -f csv     # CSV
opencli bilibili hot -v         # Verbose: show pipeline debug

Tab Completion

OpenCLI supports intelligent tab completion to speed up command input:

bash
# Add shell completion to your startup config
echo 'eval "$(opencli completion zsh)"' >> ~/.zshrc              # Zsh
echo 'eval "$(opencli completion bash)"' >> ~/.bashrc            # Bash
echo 'opencli completion fish | source' >> ~/.config/fish/config.fish  # Fish

# Restart your shell, then press Tab to complete:
opencli [Tab]          # Complete site names (bilibili, zhihu, twitter...)
opencli bilibili [Tab] # Complete commands (hot, search, me, download...)

The completion includes:

  • All available sites and adapters
  • Built-in commands (list, validate, verify, browser, doctor, plugin...)
  • Command aliases
  • Real-time updates as you add new adapters

Next Steps


Zh Index (`docs/zh/index.md`)


layout: home
hero:
name: OpenCLI
text: 让任何网站成为你的 CLI
tagline: General-purpose browser automation · 复用 Chrome 登录态 · 可复用站点命令
actions:
- theme: brand
text: 快速开始
link: /zh/guide/getting-started
- theme: alt
text: 替代 agent-browser
link: /zh/guide/agent-browser-alternative
- theme: alt
text: 在 GitHub 查看
link: https://github.com/jackwener/opencli

features:

  • icon: 🌐
    title: 浏览器自动化
    details: AI Agent 直接导航、点击、填表、提取和截图。操作网页无需 site adapter。
  • icon: 🔐
    title: 账号安全
    details: 复用 Chrome 登录态,凭证永远不会离开浏览器 — 无 token,无密码泄露。
  • icon: 🤖
    title: AI Agent 就绪
    details: Browser 原语加上适配器编写 skill,让 AI Agent 可以稳定完成侦察、提取、验证和适配器落地。
  • icon: 💰
    title: 无内置 LLM 依赖
    details: 命令本身不调用 LLM。由 AI Agent 决定操作步骤时,仍有 Agent 自身的 model costs。
  • icon: 🔁
    title: Adapter 确定性输出
    details: 相同命令,相同输出结构,每次一致。可管道、可脚本、CI 友好。


Zh Adapters Index (`docs/zh/adapters/index.md`)

所有适配器

运行 opencli list 查看完整命令列表。

详细文档请参考 英文版本。


Zh Guide Getting Started (`docs/zh/guide/getting-started.md`)

快速开始

让任何网站成为你的 CLI。
零风险 · 复用 Chrome 登录态 · AI 驱动发现 · 浏览器自动化

OpenCLI 将任何网站变成命令行界面 — Bilibili、知乎、小红书、Twitter/X、Reddit、YouTube 等 — 基于浏览器会话复用和 AI 原生发现。

OpenCLI 是 general-purpose browser automation CLI,可以作为 agent-browser 的替代工具。操作陌生网站无需 adapter;adapters 用于可复用的站点命令。参见 迁移指南。

安装

bash
npm install @jackwener/opencli

直接操作网页(无需 adapter)

先完成 Browser Bridge 设置,然后运行:

bash
opencli doctor
opencli browser --session work open https://example.com
opencli browser --session work state
opencli browser --session work extract
opencli browser --session work close

安装 opencli-browser skill,让 AI Agent 使用同一组 browser primitives:

bash
npx skills add jackwener/opencli --skill opencli-browser

基本使用

bash
opencli list                              # 查看所有命令
opencli hackernews top --limit 5          # 公开 API,无需浏览器
opencli bilibili hot --limit 5            # 浏览器命令
opencli zhihu hot -f json                 # JSON 输出

输出格式

所有命令支持 --format / -f:

bash
opencli bilibili hot -f table   # 默认:终端表格
opencli bilibili hot -f json    # JSON
opencli bilibili hot -f yaml    # YAML
opencli bilibili hot -f md      # Markdown
opencli bilibili hot -f csv     # CSV

终端自动补全

OpenCLI 支持智能的 Tab 自动补全,加快命令输入:

bash
# 把自动补全加入 shell 启动配置
echo 'eval "$(opencli completion zsh)"' >> ~/.zshrc              # Zsh
echo 'eval "$(opencli completion bash)"' >> ~/.bashrc            # Bash
echo 'opencli completion fish | source' >> ~/.config/fish/config.fish  # Fish

# 重启 shell 后,按 Tab 键补全:
opencli [Tab]          # 补全站点名称(bilibili、zhihu、twitter...)
opencli bilibili [Tab] # 补全命令(hot、search、me、download...)

补全功能包含:

  • 所有可用的站点和适配器
  • 内置命令(list、validate、verify、browser、doctor、plugin、adapter...)
  • 命令别名
  • 新增适配器时的实时更新

下一步


Comparison (`docs/comparison.md`)


title: OpenCLI Browser Automation Comparison

Comparison Guide

OpenCLI combines general-purpose browser automation with reusable site adapters. This guide evaluates where opencli excels, where it's a viable option, and where other tools are a better fit.

Looking for an agent-browser alternative? OpenCLI supports the general-purpose browser loop without site adapters. See OpenCLI vs agent-browser for a workflow comparison and command migration guide.

At a Glance

Tool Approach Best for
opencli General-purpose browser primitives + reusable site adapters AI agent browsing, deterministic site commands
Browser-Use LLM-driven browser control General-purpose AI browser automation
Crawl4AI Async web crawler Large-scale data crawling
Firecrawl Scraping API / self-hosted Clean markdown extraction, managed or self-hosted infrastructure
agent-browser Browser primitive CLI Token-efficient AI agent browsing
Stagehand AI browser framework Developer-friendly browser automation
Skyvern Visual AI automation Cross-site generalized workflows

Scenario Comparison

1. Scheduled Batch Data Extraction

"I want to pull trending posts from Bilibili/Reddit/HackerNews every hour into my pipeline."

Tool Fit Notes
opencli Best One command, structured JSON output, zero runtime cost. Runs in cron/CI without tokens or API keys.
Crawl4AI Good Strong for large-scale crawling, but requires writing extraction logic per site.
Firecrawl Viable Managed service with clean output, but costs scale with volume.
Browser-Use / Stagehand Poor LLM inference on every run is slow, expensive, and non-deterministic for repeated tasks.

Why opencli wins here: A command like opencli bilibili hot -f json returns the same structured schema every time, costs nothing to run, and finishes in seconds. For recurring data extraction from known sites, pre-built adapters beat LLM-driven approaches on cost, speed, and reliability.

2. AI Agent Site Operations

"My AI agent needs to search Twitter, read Reddit threads, or post to Xiaohongshu."

Tool Fit Notes
opencli Best Structured JSON output, fast deterministic execution, hundreds of commands ready to use.
agent-browser Good Browser primitives for agent-driven workflows; the caller orchestrates actions.
Browser-Use Viable General-purpose, but each operation costs tokens and takes 10-60s.
Stagehand Viable Good DX, but same LLM-per-action cost model.

Why opencli wins here: When your agent needs twitter search "AI news" -f json, a deterministic command that returns in seconds is strictly better than an LLM clicking through a webpage. The agent saves tokens for reasoning, not navigation.

3. Authenticated Operations (Login-Required Sites)

"I need to access my bookmarks, post content, or interact with sites that require login."

Tool Fit Notes
opencli Best Reuses your Chrome login session via Browser Bridge. No credentials stored or transmitted.
Browser-Use Viable Can use browser profiles, but credential management is manual.
Firecrawl Poor Cloud service cannot access your authenticated sessions.
Crawl4AI Poor Requires manual cookie/session injection.

Why opencli wins here: The Browser Bridge extension reuses your existing Chrome login state in real-time. You log in once in Chrome, and opencli commands work immediately. No OAuth setup, no API keys, no credential files.

4. General Web Browsing & Exploration

"I need to explore an unknown website, fill forms, or navigate complex multi-step flows."

Tool Fit Notes
Browser-Use Best LLM-driven, handles arbitrary websites and flows.
Stagehand Best Clean API for act(), extract(), observe() on any page.
agent-browser Good Token-efficient primitives for AI agents.
Skyvern Good Visual AI that generalizes across sites.
opencli Good General-purpose opencli browser primitives let agents navigate, click, fill forms, extract content, and inspect sites without adapters.

opencli supports this directly. An AI agent can use the opencli-browser skill and opencli browser primitives to explore unknown websites and carry out multi-step tasks through your logged-in browser. No pre-built adapter is required. For recurring workflows, an adapter packages those operations into a reusable, deterministic command.

Key Trade-offs

opencli's Strengths

  • General-purpose browser automation — Agents can operate websites through opencli browser primitives without writing or installing a site adapter.
  • No built-in LLM dependency — Adapter commands and browser primitives run without LLM inference. An AI agent driving the browser still incurs its own model costs.
  • Deterministic adapter output — Adapter commands provide structured schemas. Pipeable, scriptable, CI-friendly.
  • Speed — Adapter commands return in seconds, not minutes.
  • Broad platform coverage — 100+ registered site surfaces spanning global platforms (Reddit, HackerNews, Twitter, YouTube) and Chinese platforms (Bilibili, Zhihu, Xiaohongshu, Douban, Weibo) with adapters that understand local anti-bot patterns.
  • Easy to extend — Drop a .js adapter into the clis/ folder for auto-registration. Contributing a new site adapter is straightforward.

opencli's Limitations

  • Ready-made command coverage varies — Site-specific commands require adapters, but general browser automation does not. Use opencli browser on sites without adapters, and add an adapter when a workflow needs a reusable command.
  • Adapter maintenance — When a website updates its DOM or API, the corresponding adapter may need updating. The community maintains these, but breakage is possible.
  • Browser workflows need orchestration — For tasks without adapters, a script or AI agent must choose actions and handle page state using the browser primitives. General-purpose access does not make every workflow a single deterministic command.

Choosing a Workflow

Use opencli's adapters for ready-made commands and its general-purpose browser primitives for exploration or tasks without adapters:

text
Has adapter?  ──yes──▶  opencli <site> <command> (deterministic)
     │
     no
     │
     ▼
Explore site / run task with opencli browser (script or AI agent)
     │
     ▼
Recurring?    ──yes──▶  Package the workflow as an opencli adapter

Further Reading


Advanced Android Chrome (`docs/advanced/android-chrome.md`)

Using OpenCLI with Android Chrome

OpenCLI can control Chrome on a connected Android device via ADB port forwarding and CDPBridge — no extra tools or custom builds required. The same adapters that run on desktop Chrome work identically on Android, reusing whatever cookies are already in the mobile browser.


How It Works

Android Chrome supports remote debugging via CDP. The device exposes a local Unix socket that ADB can forward to a TCP port on your machine. OpenCLI's CDPBridge then connects to that port exactly as it would to any other CDP endpoint.

text
OpenCLI (CDPBridge)
    │  WebSocket (CDP)
    ▼
localhost:9222                ← ADB forward
    │  adb forward
    ▼
Android device
  chrome_devtools_remote      ← Chrome's Unix debug socket

No Chrome extension, no daemon process — just a direct CDP WebSocket connection.


Prerequisites

On the Android device:

  1. Settings → About Phone → tap Build Number 7 times to enable Developer Options
  2. Settings → Developer Options → enable USB Debugging
  3. In Chrome for Android, open chrome://flags, search for DevTools remote debugging, and enable it (Chrome 119+). On older versions this is on by default when USB debugging is active.

On your machine:


Step-by-Step Setup

1. Connect the device

bash
adb devices

Expected output:

text
List of devices attached
R5CT443TRDM    device

If the device shows as unauthorized, check for a "Allow USB Debugging?" prompt on the phone and tap Allow.

2. Forward the CDP port

bash
adb forward tcp:9222 localabstract:chrome_devtools_remote

3. Verify the connection

bash
curl http://localhost:9222/json

A successful response lists the open tabs:

json
[
  {
    "id": "3941",
    "title": "Hacker News",
    "type": "page",
    "url": "https://news.ycombinator.com",
    "webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/3941"
  }
]

4. Run any OpenCLI command

bash
export OPENCLI_CDP_ENDPOINT=http://localhost:9222
opencli hackernews top --limit 5

Targeting a Specific Tab

When multiple tabs are open, CDPBridge picks the best one automatically using a scoring algorithm (prefer type=page, real URLs over about:blank, etc.). To override this, set OPENCLI_CDP_TARGET to a substring of the tab's title or URL:

bash
OPENCLI_CDP_TARGET="twitter" opencli twitter trending

You can also connect directly to a specific tab's WebSocket URL (from /json):

bash
OPENCLI_CDP_ENDPOINT=ws://localhost:9222/devtools/page/3941 opencli ...

Using Login-Required Adapters

Adapters that use the cookie strategy (most social/content sites) need you to be logged in on the Android device. The cookies are already in Android Chrome — OpenCLI reads them automatically over CDP.

To check whether an adapter requires login:

bash
opencli zhihu hot --help
# Strategy: cookie | Browser: yes | Domain: www.zhihu.com

If you see Strategy: cookie, log into the site on the phone first, then run the command.


Teardown

Remove the port forward when done:

bash
adb forward --remove tcp:9222
# or remove all forwards:
adb forward --remove-all

Differences from Desktop Chrome

Feature Desktop Chrome (BrowserBridge) Android Chrome (CDPBridge)
Chrome extension required Yes No
Daemon process Yes (auto-started) No
Multi-tab management Full (tabs, selectTab) Not supported
Cookie session Desktop browser's cookies Android browser's cookies
Touch events N/A Not needed (CDP uses DOM events)
Concurrent devices N/A Use different local ports per device

Multiple Devices

To connect to more than one Android device simultaneously, assign each a different local port:

bash
# Device 1
adb -s <device1-serial> forward tcp:9222 localabstract:chrome_devtools_remote

# Device 2
adb -s <device2-serial> forward tcp:9223 localabstract:chrome_devtools_remote

# Run commands targeting each device
OPENCLI_CDP_ENDPOINT=http://localhost:9222 opencli twitter trending
OPENCLI_CDP_ENDPOINT=http://localhost:9223 opencli twitter trending

Troubleshooting

adb devices shows nothing

  • Check USB cable (data cable, not charge-only)
  • Revoke USB debugging authorizations on the device and re-approve

curl http://localhost:9222/json returns empty array []

  • Chrome for Android is not open, or has no visible tabs — open a tab and retry
  • Remote debugging flag in chrome://flags may be disabled

curl http://localhost:9222/json returns connection refused

  • Port forward may have dropped (happens after device screen lock on some ROMs) — re-run adb forward

Adapter returns (no data) despite a working connection

  • The site's API requires authentication: log into the site in Android Chrome first
  • Confirm with --verbose to see which pipeline step returns 0 items

Advanced Cdp (`docs/advanced/cdp.md`)

Connecting OpenCLI via CDP (Remote/Headless Servers)

If you cannot use the opencli Browser Bridge extension (e.g., in a remote headless server environment without a UI), OpenCLI provides an alternative: connecting directly to Chrome via CDP (Chrome DevTools Protocol).

Because CDP binds to localhost by default for security reasons, accessing it from a remote server requires an additional networking tunnel.

This guide is broken down into three phases:

  1. Preparation: Start Chrome with CDP enabled locally.
  2. Network Tunnels: Expose that CDP port to your remote server using either SSH Tunnels or Reverse Proxies.
  3. Execution: Run OpenCLI on your server.

Phase 1: Preparation (Local Machine)

First, you need to start a Chrome browser on your local machine with remote debugging enabled.

macOS:

bash
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --remote-debugging-port=9222 \
  --user-data-dir="$HOME/chrome-debug-profile" \
  --remote-allow-origins="*"

Linux:

bash
google-chrome \
  --remote-debugging-port=9222 \
  --user-data-dir="$HOME/chrome-debug-profile" \
  --remote-allow-origins="*"

Windows:

cmd
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
  --remote-debugging-port=9222 ^
  --user-data-dir="%USERPROFILE%\chrome-debug-profile" ^
  --remote-allow-origins="*"

Note: The --remote-allow-origins="*" flag is often required for modern Chrome versions to accept cross-origin CDP WebSocket connections (e.g. from reverse proxies like ngrok).

Once this browser instance opens, log into the target websites you want to use (e.g., bilibili.com, zhihu.com) so that the session contains the correct cookies.


Phase 2: Remote Access Methods

Once CDP is running locally on port 9222, you must securely expose this port to your remote server. Choose one of the two methods below depending on your network conditions.

If your local machine has SSH access to the remote server, this is the most secure and straightforward method.

Run this command on your Local Machine to forward the remote server's port 9222 back to your local port 9222:

bash
ssh -R 9222:localhost:9222 your-server-user@your-server-ip

Leave this SSH session running in the background.

Method B: Reverse Proxy (ngrok / frp / socat)

If you cannot establish a direct SSH connection (e.g., due to NAT or firewalls), you can use an intranet penetration tool like ngrok.

Run this command on your Local Machine to expose your local port 9222 to the public internet securely via ngrok:

bash
ngrok http 9222

This will print a forwarding URL, such as https://abcdef.ngrok.app. Copy this URL.


Phase 3: Execution (Remote Server)

Now switch to your Remote Server where OpenCLI is installed.

Depending on the network tunnel method you chose in Phase 2, set the OPENCLI_CDP_ENDPOINT environment variable and run your commands.

If you used Method A (SSH Tunnel):

bash
export OPENCLI_CDP_ENDPOINT="http://localhost:9222"
opencli doctor                    # Verify connection
opencli bilibili hot --limit 5    # Test a command

If you used Method B (Reverse Proxy like ngrok):

bash
# Use the URL you copied from ngrok earlier
export OPENCLI_CDP_ENDPOINT="https://abcdef.ngrok.app"
opencli doctor                    # Verify connection
opencli bilibili hot --limit 5    # Test a command

Tip: If you provide a standard HTTP/HTTPS CDP endpoint, OpenCLI requests the /json target list and picks the most likely inspectable page target automatically. If multiple page targets exist, you can further narrow selection with OPENCLI_CDP_TARGET (for example example.com or localhost:3000).

Tip: Set OPENCLI_CDP_INIT_SCRIPT to a readable regular JavaScript file to run it on every new document of the connected page (registered after the built-in stealth script). The file is validated before connecting; directories and named pipes are rejected. Useful when the CDP peer keeps state per connection, so the page must be prepared on OpenCLI's own connection.

If you plan to use this setup frequently, you can persist the environment variable by adding the export line to your ~/.bashrc or ~/.zshrc on the server.


Advanced Download (`docs/advanced/download.md`)

Download Support

OpenCLI supports downloading images, videos, and articles from supported platforms.

Supported Platforms

Platform Content Types Notes
xiaohongshu Images, Videos Downloads all media from a note
bilibili Videos Requires yt-dlp installed
twitter Images, Videos Downloads from user media tab or single tweet
douban Images Downloads poster / still image lists from movie subjects
xiaoyuzhou Audio, Transcript Downloads episode audio and transcript JSON/text with local credentials
zhihu Articles (Markdown) Exports articles with optional image download
weixin Articles (Markdown) Exports WeChat Official Account articles
midjourney Images, Raw/Social Video, GIF Validates file signatures; requires a logged-in browser

Prerequisites

For video downloads from streaming platforms, install yt-dlp:

bash
# Install yt-dlp
pip install yt-dlp
# or
brew install yt-dlp

Usage Examples

text
/* Detailed source-code truncated for AI context efficiency. */

opencli xiaoyuzhou download and transcript require local Xiaoyuzhou credentials in ~/.opencli/xiaoyuzhou.json.

Pipeline Step

The download step can be used in pipeline adapters:

::: v-pre

yaml
pipeline:
  - fetch: https://api.example.com/media
  - download:
      url: ${{ item.imageUrl }}
      dir: ./downloads
      filename: ${{ item.title | sanitize }}.jpg
      concurrency: 5
      skip_existing: true

:::


Advanced Rate Limiter Plugin (`docs/advanced/rate-limiter-plugin.md`)

Rate Limiter Plugin

An optional plugin that adds a random sleep between browser-based commands to reduce the risk of platform rate-limiting or bot detection.

Install

bash
opencli plugin install github:jackwener/opencli-plugin-rate-limiter

Or copy the example below into ~/.opencli/plugins/rate-limiter/ to use it locally without installing from GitHub.

What it does

After every command targeting a browser platform (xiaohongshu, weibo, bilibili, douyin, tiktok, …), the plugin sleeps for a random duration — 5–30 seconds by default — before returning control to the caller.

Configuration

Variable Default Description
OPENCLI_RATE_MIN 5 Minimum sleep in seconds
OPENCLI_RATE_MAX 30 Maximum sleep in seconds
OPENCLI_NO_RATE — Set to 1 to disable entirely (local dev)
bash
# Shorter delays for light scraping
OPENCLI_RATE_MIN=3 OPENCLI_RATE_MAX=10 opencli xiaohongshu search "AI眼镜"

# Skip delays when iterating locally
OPENCLI_NO_RATE=1 opencli bilibili comments BV1WtAGzYEBm

Local installation (without GitHub)

  1. Create the plugin directory:

    bash
    mkdir -p ~/.opencli/plugins/rate-limiter
  2. Create ~/.opencli/plugins/rate-limiter/package.json:

    json
    { "type": "module" }
  3. Create ~/.opencli/plugins/rate-limiter/index.js:

    js
    import { onAfterExecute } from '@jackwener/opencli/registry'
    
    const BROWSER_DOMAINS = [
      'xiaohongshu', 'weibo', 'bilibili', 'douyin', 'tiktok',
      'instagram', 'twitter', 'youtube', 'zhihu', 'douban',
      'jike', 'weixin', 'xiaoyuzhou',
    ]
    
    onAfterExecute(async (ctx) => {
      if (process.env.OPENCLI_NO_RATE === '1') return
    
      const site = ctx.command?.split('/')?.[0] ?? ''
      if (!BROWSER_DOMAINS.includes(site)) return
    
      const min = Number(process.env.OPENCLI_RATE_MIN ?? 5)
      const max = Number(process.env.OPENCLI_RATE_MAX ?? 30)
      const ms = Math.floor(Math.random() * (max - min + 1) + min) * 1000
    
      process.stderr.write(`[rate-limiter] ${site}: sleeping ${(ms / 1000).toFixed(0)}s\n`)
      await new Promise(r => setTimeout(r, ms))
    })
  4. Verify it loaded:

    bash
    OPENCLI_NO_RATE=1 opencli xiaohongshu search "test" 2>&1 | grep rate-limiter
    # → (no output — plugin loaded but rate limit skipped)
    
    opencli xiaohongshu search "test" 2>&1 | grep rate-limiter
    # → [rate-limiter] xiaohongshu: sleeping 12s

Writing your own plugin

Plugins are plain JS/TS files in ~/.opencli/plugins/<name>/. A plugin file must export a hook registration call that matches the pattern onStartup(, onBeforeExecute(, or onAfterExecute( — opencli's discovery engine uses this pattern to identify hook files vs. command files.

js
// ~/.opencli/plugins/my-plugin/index.js
import { onAfterExecute } from '@jackwener/opencli/registry'

onAfterExecute(async (ctx) => {
  // ctx.command — e.g. "bilibili/comments"
  // ctx.args    — coerced command arguments
  // ctx.error   — set if the command threw
  console.error(`[my-plugin] finished: ${ctx.command}`)
})

See hooks.ts for the full HookContext type.

Browser command hooks

Browser page actions, session bind/unbind, and native Chrome commands emit the
same before/after lifecycle hooks as site commands. Names include browser/open,
browser/bind, and browser/chrome/call. ctx.args includes named positional
arguments (for example, ctx.args.url for browser open) and inherited options
such as session and profile. The before hook is awaited before connection or
browser work begins.

The after hook receives the same context, a completion timestamp, and the last
emitted result. Reported command failures populate ctx.error, including errors
handled by the command's output layer. Streaming commands emit the after hook
when they finish, with their last result. Hook exceptions remain warnings and do
not stop commands; these hooks support observation and cooperative pacing, not
a security policy that can veto execution.


Advanced Remote Chrome (`docs/advanced/remote-chrome.md`)

Remote Chrome

Run OpenCLI on a server or headless environment by connecting to a remote Chrome instance.

Use Cases

  • Running CLI commands on a remote server
  • CI/CD automation with headed browser
  • Shared team browser sessions

Setup

1. Start Chrome on the Remote Machine

bash
# On the remote machine (or your Mac)
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --remote-debugging-port=9222

2. SSH Tunnel (If Needed)

If the remote Chrome is on a different machine, create an SSH tunnel:

bash
# On your local machine or server
ssh -L 9222:127.0.0.1:9222 user@remote-host

::: warning
Use 127.0.0.1 instead of localhost in the SSH command to avoid IPv6 resolution issues that can cause timeouts.
:::

3. Configure OpenCLI

bash
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"

4. Verify

bash
# Test the connection
curl http://127.0.0.1:9222/json/version

# Run a diagnostic
opencli doctor

CI/CD Integration

For CI/CD environments, use a real Chrome instance with xvfb:

::: v-pre

yaml
steps:
  - uses: browser-actions/setup-chrome@latest
    id: setup-chrome
  - run: |
      xvfb-run --auto-servernum \
        ${{ steps.setup-chrome.outputs.chrome-path }} \
        --remote-debugging-port=9222 &

:::


Conventions Convention Audit (`docs/conventions/convention-audit.md`)

Convention Audit

opencli convention-audit scans adapter metadata plus source files for common
agent-native convention violations.

The command is intentionally report-first. It gives agents a shared fact base
before starting a sweep PR; --strict can be used later by CI gates.

Usage

bash
opencli convention-audit
opencli convention-audit --site twitter
opencli convention-audit twitter/search
opencli convention-audit --site pixiv -f yaml
opencli convention-audit --strict

Formats:

  • table prints a grouped human-readable report.
  • yaml is the recommended agent-facing format.
  • json is available for stricter machine consumers.

Rules

The first version reports these categories:

  • silent-column-drop: source rows emit top-level keys that are not present in columns.
  • camelCase-in-columns: output columns should use stable snake_case keys.
  • missing-access-metadata: every adapter command must declare access: 'read' | 'write'.
  • silent-clamp: Math.min(...limit...) can silently change user input instead of throwing ArgumentError.
  • silent-empty-fallback: return [] can hide fetch/parse failures from agents.
  • silent-sentinel: ?? 'unknown' / || 'N/A' style fallbacks can turn missing data into fake data.
  • write-without-delete-pair: write commands such as like, save, follow, create, or post should have an undo/delete counterpart when the site supports one.

The scanners are heuristic. Treat reports as prioritized review input by
default, then turn a specific rule into a strict CI gate only after the current
violations and exemptions are understood.

CI Gates

npm run check:silent-column-drop enforces the silent-column-drop rule in
baseline mode. The baseline file is
scripts/silent-column-drop-baseline.json.

npm run check:typed-error-lint enforces the silent failure rules in baseline
mode:

  • silent-clamp
  • silent-empty-fallback
  • silent-sentinel

The baseline file is scripts/typed-error-lint-baseline.json.

Each gate fails only on new violations beyond its baseline. This lets the repo
adopt the invariant immediately while existing findings are cleaned up in
separate sweep PRs.

When a sweep fixes existing silent-column-drop entries, update the baseline:

bash
npm run build
node scripts/check-silent-column-drop.mjs --update-baseline

When a sweep fixes existing typed-error findings, update the baseline:

bash
npm run build
node scripts/check-typed-error-lint.mjs --update-baseline

Conventions Listing Detail Id Pairing (`docs/conventions/listing-detail-id-pairing.md`)

Listing↔detail ID pairing (advisory)

Status: advisory convention, not a CI gate. Use as guidance when
designing listing columns; an audit script (npm run advise:listing-id-pairing)
can surface candidate listings for human review.

When a site exposes both a listing-class command (search / hot /
recent / top / feed / ...) and a detail-class command (read /
paper / article / job / view / ...), it's usually nicer for agents
if the listing rows include an id-shaped column whose value can be passed
directly into the detail command.

Without that, the agent has to either re-search by title or scrape a URL
out of band to follow up on a listing row.

Soft convention

If <site> has both a listing command and a detail command, prefer
giving each listing row a column whose value round-trips into the
detail command's positional argument.

That column is whatever the detail command expects:

Site Listing Detail Round-trip column
hackernews top / best / ask / jobs / show / new read id
hupu hot / search detail <tid> tid
lobsters hot / active / newest / tag read id (Lobsters short_id value)
arxiv search / recent paper id
stackoverflow hot / search / bounties / unanswered read id
openreview search / venue paper / reviews <forum> id
devto top / tag / user read id
bilibili hot video bvid
reddit hot read id
bluesky user thread uri
1688 search item offer_id
tieba search read id
jike feed / search / user post id
weibo feed / search post id

Why this matters

The agent never has eyes on a webpage. It sees the listing rows as a
plain table of strings. If the listing emits [rank, title, author, votes]
and the detail command needs an id, the agent has three bad options:

  1. Re-search by title — fragile, may hit a different post for ambiguous
    titles, costs an extra round-trip plus quota.
  2. Parse the URL — assumes URL shape stays stable and is regex-able,
    often breaks across A/B buckets or after a site redesign.
  3. Hand-craft a search — pure guess; agents trained to do this leak
    the failure mode silently downstream.

Surfacing the id in the listing collapses all three into a single,
unambiguous column.

Why this is advisory, not a gate

Whether a listing should pair with a detail is a case-by-case product/UX
call. Many legitimate listings genuinely don't pair:

  • Topic-string listings (twitter trending, weibo hot) — rows are
    search keywords, not addressable entities.
  • Profile-attribute listings (reddit user, lesswrong user,
    weibo user) — rows are [field, value] pairs of one profile.
  • UI-only sessions (browser quick find surfaces)
    — page ids aren't extractable from the rendered DOM.
  • Comment / reply listings — sub-resources of a parent thread; the
    detail command fetches the parent, not the comment.

A hard CI gate forced authors to either add an artificial id column or
file an exemption with a reason — both of which were higher cognitive cost
than the silent-loss bugs the rule actually catches. See PR #1311 thread
for the broader "anti-pattern vs case-by-case" filter.

What counts as an "id-shaped column"

The advisory script (scripts/check-listing-id-pairing.mjs) considers any
of these column names a valid round-trip handle:

  • Exact id / short_id
  • Anything ending in _id or Id (e.g. offer_id, paperId)
  • Domain-specific ids: jk (indeed), tid (thread id), bvid / aid
    (bilibili), sku (retail product SKU), asin (amazon), isbn, doi,
    slug
  • username / handle (only when the detail command keys off the user
    rather than a post)
  • url — only when the detail command's positional argument explicitly
    accepts a URL (for example read , article , or help
    text such as Post ID or full URL). URL is not a valid substitute when
    the detail command only says an id comes "from URL"; callers would still
    need to parse the URL out of band.
  • uri — for sites whose canonical handle is a URI scheme (e.g.
    Bluesky's at://did:.../app.bsky.feed.post/...).

If the natural id for your site is a different shape, add the pattern to
ID_COLUMN_PATTERNS in the script.

How to add an id column to a listing

  1. Find the source field. Most listing endpoints already include the
    id in their raw response — they're just dropped before the row is
    shaped. Check func's mapper before adding new fetch logic.

  2. Pick the column position. Convention is [rank, id, ...rest, url]
    so identifiers stay near the front and the URL stays last.

  3. Update the docs. The site's docs/adapters/browser/<site>.md
    should list the new column under "Listing columns" and call out that
    it round-trips into the detail command.

  4. Optional: run the advisory script to confirm the manifest reflects
    the new column.

    bash
    npm run advise:listing-id-pairing

Advisory script usage

bash
# Print a report of listings that don't currently carry an id-shaped column.
# Always exits 0 — does not fail CI.
npm run advise:listing-id-pairing

The script reads cli-manifest.json, so always rebuild the manifest
(npx tsx src/build-manifest.ts) after touching adapter columns.

  • docs/developer/ts-adapter.md — adapter
    authoring conventions, including the required access: 'read' | 'write'
    metadata.
  • "Output design" reference inside the bundled
    opencli-adapter-author skill — column naming, ordering, and id-first
    conventions.

Design Browser Agent Runtime (`docs/design/browser-agent-runtime.md`)

Browser Agent Runtime

OpenCLI browser should become reliable for unknown SaaS workflows without
becoming a Playwright clone. The target is an agent-native runtime:

  • compact observation that gives an agent the right refs in one call,
  • refs that survive common React re-render/stale-node cases,
  • real browser input events for user-like interactions,
  • a small command surface that reduces calls only when the abstraction is
    proven.

This design was triggered by a customer report: Mercury expense category
dropdowns worked with agent-browser + Claude Code, but OpenCLI often failed
to select the category.

Source Findings

We compared OpenCLI against vercel-labs/agent-browser at source level, not
only from documentation.

What agent-browser Actually Does

The reliable dropdown behavior is not from a full Playwright actionability
pipeline or a magic custom-select command.

  • cli/src/native/interaction.rs: click resolves the target center and sends
    CDP Input.dispatchMouseEvent as mouseMoved, mousePressed,
    mouseReleased. It does not run Playwright's full visible/stable/enabled/
    receives-events pipeline.
  • cli/src/native/interaction.rs: select_option only handles native
    <select> by mutating selected options and dispatching change.
  • cli/src/native/snapshot.rs: snapshots come from
    Accessibility.getFullAXTree, not a DOM walk. Refs carry accessibility
    role/name and backend node id.
  • cli/src/native/element.rs: ref resolution first tries the cached
    backendDOMNodeId; if stale, it re-queries the AX tree by role/name/nth.
    This is the important stale-ref recovery mechanism.
  • cli/src/native/snapshot.rs and cli/src/native/actions.rs: iframe refs
    carry frame context, including dedicated sessions for cross-origin iframes
    when CDP exposes them.
  • cli/src/native/actions.rs: semantic locators such as getbyrole are
    simple JS queries that mark an element with data-agent-browser-located,
    then delegate to the same action path.
  • skill-data/core/SKILL.md: the intended agent loop remains
    snapshot -> click/fill/type by @ref -> snapshot again.

Implication: for Mercury-style custom dropdowns, the minimum necessary fix is
real CDP input plus better refs/observation. A one-shot choose command is a
later optimization, not the root cause fix.

Current OpenCLI Gaps

  • src/browser/base-page.ts and src/browser/target-resolver.ts: generic
    browser click currently resolves an element and calls DOM el.click()
    first. CDP native click is only a fallback when JS click fails. Radix/MUI/
    shadcn controls often open/select on pointerdown, mousedown, mouseup,
    or pointerup, so el.click() can report success while the UI did not
    change.
  • src/browser/dom-snapshot.ts: OpenCLI observation is DOM-based. It emits
    useful compact refs, but refs do not have AX role/name/nth fallback semantics
    and are weaker across re-rendered portals.
  • OpenCLI already has the right low-level plumbing: IPage.cdp,
    nativeClick, nativeType, nativeKeyPress, setFileInput, and extension
    CDP passthrough including Accessibility.getFullAXTree.
  • Extension CDP passthrough already allows Input.dispatchMouseEvent,
    Accessibility.getFullAXTree, and DOM.getBoxModel. It does not currently
    allow DOM.describeNode; AX subtree/iframe work must add that allowlist entry
    before depending on it.
  • OpenCLI exposes fewer general browser primitives than agent-browser:
    hover, focus, check, uncheck, dblclick, drag, upload, and
    wait download are not a consistent first-class CLI surface.
  • browser find is currently CSS-oriented; role/name/label/text locators are
    not first-class for agents.

Product Position

OpenCLI has two browser jobs:

  1. deterministic adapters for known sites,
  2. a reliable browser toolbelt for unknown pages and adapter authors.

Borrow from Playwright only where it improves reliability:

  • real pointer/mouse/keyboard/file input events,
  • selected actionability checks when they prevent silent failures,
  • strict locator ambiguity for write actions,
  • typed failure reasons.

Do not copy:

  • Playwright's test runner, assertion DSL, trace viewer, route/HAR surface, or
    one-to-one API list.

Borrow from agent-browser:

  • AX-tree observation,
  • compact refs as the default agent selector,
  • role/name stale-ref re-resolution,
  • iframe-aware refs,
  • annotated screenshots mapped to refs,
  • a simple snapshot/action loop.

Do not copy blindly:

  • broad command sprawl,
  • natural-language act as the primary runtime,
  • route/mock/HAR as near-term browser CLI surface,
  • claims that a custom dropdown should be solved by magic if the source system
    itself still uses snapshot/click/snapshot/click.

Design Principles

  • Prefer one reliable primitive over three brittle workarounds.
  • Reduce agent calls by improving observation first. A better snapshot can
    avoid many follow-up help/find calls without inventing high-level commands
    prematurely.
  • Keep actions transparent. A failed action should return a branchable reason,
    not a generic "click failed".
  • Add command surface only when it maps to a distinct browser task and reduces
    real agent calls.
  • Keep adapter compatibility explicit. Any change to default click/type/fill
    behavior must run full adapter tests. Escape hatches are emergency plan B, not
    a reason to merge known regressions.

Architecture

Native Input Backend

Normalize native input through a small internal backend over existing IPage
capabilities:

ts
interface NativeInputBackend {
  click(point: Point, opts?: ClickOptions): Promise<void>;
  dblclick(point: Point): Promise<void>;
  hover(point: Point): Promise<void>;
  key(key: string, modifiers?: string[]): Promise<void>;
  insertText(text: string): Promise<void>;
  setFiles(selector: string, files: string[]): Promise<void>;
}

The Browser Bridge and direct CDP implementation can both use:

  • Input.dispatchMouseEvent,
  • Input.dispatchKeyEvent,
  • Input.insertText,
  • DOM.setFileInputFiles.

This is the P0 fix for Mercury dropdowns: CDP mouse primary for click, with
DOM el.click() only as fallback.

This does not change browser select. Native <select> remains a separate
operation that sets selected options and dispatches change, matching both
OpenCLI's current behavior and agent-browser's select_option behavior.

AX Observation And Refs

Add an AX-backed observation path alongside the current DOM snapshot.

Ref identity should include enough data for re-resolution:

ts
type BrowserRef = {
  ref: string;
  backendNodeId?: number;
  role: string;
  name: string;
  nth?: number;
  frame?: {
    frameId?: string;
    sessionId?: string;
    url?: string;
  };
  bbox?: { x: number; y: number; width: number; height: number };
};

Resolution order:

  1. cached backendNodeId,
  2. AX re-query by role/name/nth in the same frame,
  3. existing CSS/DOM resolver fallback when the target is not a ref.

The first rollout should be additive:

  • keep current browser state output stable,
  • Phase 0: add an internal or opt-in AX prototype; do not change the default
    browser state text output,
  • Phase 1 decision point: either promote AX to default observation or keep it
    opt-in,
  • decision criteria: fixture pass rate, stale-ref recovery rate, manual SaaS
    results, adapter compatibility, and snapshot token size versus the current DOM
    snapshot.

Frame Routing

Refs from iframes need frame context so commands can act without manual frame
switching in common cases.

The route should mirror agent-browser's model:

  • same-origin iframe: parent session plus frameId params where CDP supports
    them,
  • cross-origin iframe: dedicated attached target session when available,
  • if unsupported: typed frame_unreachable with the iframe ref/name/url.

Do not add a global "switch frame" burden to the normal agent path unless the
target cannot be routed automatically.

Actionability Helper

Do not start with full Playwright actionability. Implement a small helper that
prevents known silent failures:

  1. resolve target/ref,
  2. scroll into view when CDP supports it,
  3. measure a non-zero bounding box,
  4. dispatch native input.

Boundary by phase:

  • MVP: scroll into view plus non-zero bounding box only.
  • Phase 1: add visible/enabled/not-editable checks if the target action needs
    them and compatibility remains clean.
  • Phase 2: add stability and receives-events checks only if fixtures or manual
    SaaS cases show real failures.

Each added wait/check has compatibility and latency cost.

Typed statuses:

ts
type ActionStatus =
  | 'ready'
  | 'not_found'
  | 'stale_ref_recovered'
  | 'stale_ref_unresolved'
  | 'zero_rect'
  | 'not_visible'
  | 'disabled'
  | 'not_editable'
  | 'frame_unreachable'
  | 'native_backend_unavailable';

Semantic Locators

Add semantic locator support after AX refs are in place:

bash
opencli browser --session research click --role button --name "Submit"
opencli browser --session research fill --label "Email" "[email protected]"
opencli browser --session research get text --testid invoice-total

For write operations, ambiguous locators must fail with candidates. They should
not silently choose the first match.

Command Surface

Keep the surface smaller than agent-browser and Playwright.

Near-term primitives:

bash
opencli browser --session research click <target>
opencli browser --session research dblclick <target>
opencli browser --session research hover <target>
opencli browser --session research focus <target>
opencli browser --session research check <target>
opencli browser --session research uncheck <target>
opencli browser --session research upload <target> <file...>
opencli browser --session research drag <source> <target>
opencli browser --session research wait download [pattern]

Keep browser select native <select> only. It should clearly return
not_a_select when used on custom controls.

Defer browser choose <target> <option> until after the MVP proves the
snapshot/ref/action loop on Mercury-like fixtures. If added later, it should be
a thin deterministic helper for common combobox/listbox/menu patterns, not a
general AI act command.

Backward Compatibility

Area Risk Policy
browser click Native CDP input triggers pointer/mouse handlers that DOM el.click() skipped. This is intended, but can expose sites that depended on synthetic click. Make CDP primary with JS fallback. Run full adapter tests; all new failures are blockers unless proven unrelated. Keep an internal env escape hatch for one release only as emergency rollback support.
browser type CDP input can differ from DOM mutation for rich editors. Keep existing output shape and verification. Prefer native type where already available.
browser fill Fill must remain exact replacement, not append typing. Preserve exact-set semantics; native input only after clearing/focus preparation.
browser select Native select behavior is already established. Do not overload for custom dropdowns. CDP-primary click does not affect browser select; it keeps the JS option setter/change-event path.
Ref format Agents and docs depend on compact refs. Add metadata internally first; avoid breaking text output.
Extension support Older extensions may lack a CDP command. Detect unsupported backend and return typed diagnostic or fallback.
Adapter code 770+ commands may rely on current page helpers. Run targeted browser/unit tests plus full adapter tests before changing defaults.

Milestones

Phase 0: Mercury Reliability MVP

Documented in docs/design/mercury-fix-mvp.md.

Scope:

  • CDP mouse primary for browser click,
  • Radix/shadcn/MUI-style fixture coverage,
  • AX snapshot/ref-map prototype with role/name/nth re-resolution,
  • native type/fill normalization where existing behavior is already close.

Out of scope for Phase 0:

  • iframe/frame-aware action routing,
  • full actionability,
  • browser choose.

Exit:

  • Mercury-like custom select can be completed with
    snapshot -> click trigger -> snapshot -> click option -> verify.
  • No silent "clicked true but no UI event chain" failure remains for fixture
    dropdowns.
  • Existing adapter tests do not regress.
  • Quantitative gates from docs/design/mercury-fix-mvp.md pass.

Phase 1: Ref And Observation Upgrade

Scope:

  • decide AX default versus opt-in based on Phase 0 metrics,
  • AX-backed browser state or browser snapshot option,
  • ref cache that stores backend node id, role/name/nth, frame context,
  • iframe-aware action routing,
  • annotated screenshot with the same ref ids and sidecar metadata.

Status after implementation:

  • same-origin iframe AX refs route through Accessibility.getFullAXTree
    frameId params,
  • cross-origin iframe AX routing is best-effort. Real Chrome extension smoke
    verified that chrome.debugger may not expose attachable OOPIF iframe
    targets to extensions even after Target.setDiscoverTargets,
    Target.getTargets, and Target.setAutoAttach,
  • unsupported frames degrade by omission or typed action failure rather than
    requiring global manual frame switching.

Implementation note: Phase 1 also includes a DOM-ref visual slice via
browser screenshot --annotate. It refreshes current DOM refs and overlays
visible [N] labels on the captured image. AX-side visual labels and richer
sidecar metadata remain follow-up work.

Exit:

  • Agent can act on iframe refs without manual frame selection in common cases.
  • Stale refs from simple React re-renders recover by role/name/nth.
  • Snapshot output remains compact enough for normal agent context.

Phase 2: Browser Toolbelt

Scope:

  • hover, focus, dblclick, check, uncheck, upload, drag, and
    wait download (implemented),
  • semantic locator options for role/name, label, text, testid,
  • structured ambiguity errors for write locators.

Implementation note: semantic locators cover browser find, browser click,
browser get text|value|attributes, input actions (type, fill, select),
and Phase 2 action primitives (hover, focus, dblclick, check,
uncheck, upload). drag uses prefixed endpoint locators (--from-role /
--to-role, etc.) so source and target cannot be confused. Placeholder is
folded into accessible-name matching for --name; a dedicated --placeholder
flag can be added only if real usage shows the distinction matters.

Exit:

  • A representative form with text, checkbox/radio, file upload, custom select,
    and submit can be completed without eval.
  • Agents can usually avoid inventing CSS selectors.

Phase 3: High-Level Deterministic Helpers

Only after Phase 0/1 metrics justify it:

  • browser choose for common custom select/combobox/listbox/menu controls,
  • optional browser form inspect and browser form fill <json> for structured
    forms,
  • failure artifact bundle: screenshot, refs, target diagnostics, console/
    network summary, and suggested next command.

Do not add a free-form natural-language act as the primary interface.

Success Metrics

Track both reliability and call count.

Mercury-like custom select:

  • current OpenCLI baseline: often fails because click is DOM el.click();
  • Phase 0 target: reliable 4-step snapshot/action loop, with fixture pass rate
    at least N-1/N after recording baseline;
  • Phase 3 target, only if warranted: deterministic 1-step choose after
    target discovery.

Stale-ref recovery:

  • Phase 0 AX prototype target: at least 9/10 repeated React re-render fixture
    runs recover through role/name/nth.

Compatibility:

  • Any PR changing default click/type/fill behavior must run full adapter tests.
    New failures are merge blockers unless proven unrelated to the PR.

Fixture matrix:

  • Radix Select,
  • shadcn Select,
  • Material UI Select/Autocomplete,
  • native <select>,
  • checkbox/radio label retarget,
  • file upload,
  • same-origin iframe form,
  • cross-origin iframe where CDP target attach is available.

Manual SaaS matrix:

Site / app Scenario Controls
Mercury expense category custom select, portal
Brex expense category / memo custom select, text input
Ramp reimbursement category custom select
Stripe Dashboard filters combobox, menu
Linear issue fields combobox
Notion property select custom select, portal
Airtable field select custom select, grid
Workday form dropdown custom select, iframe risk
Concur expense form custom select, upload
GitHub labels combobox, portal

Manual matrix is not a CI gate at first. It is the calibration set for deciding
whether OpenCLI is approaching agent-browser reliability.

Execution process:

  • Phase 0 completion: @opencli-质量官 runs Mercury, Brex, and Linear when access
    is available.
  • On each form page, collect opencli browser --session research state --compare-sources so the AX
    default decision has DOM-vs-AX metrics: refs, frame sections, approximate
    tokens, elapsed time, and per-source errors.
  • Pass means the relevant category/field can be selected and the form state can
    be saved or committed.
  • Failures do not block the already-shipped MVP unless they expose a regression,
    but they become Phase 1 backlog with exact command sequence and failure
    reason.

Test Strategy

Phase 0:

  • unit tests for CDP-primary click fallback behavior,
  • local fixture that records pointer/mouse/click event order,
  • component fixtures for Radix/shadcn/MUI-style controls,
  • stale-ref fixture that re-renders an option after snapshot and verifies
    AX re-resolution,
  • direct CDP and Browser Bridge paths where practical.

Regression gates:

bash
npm run build
npm run typecheck
npm test -- --run src/browser src/cli.test.ts
npm run check:typed-error-lint
npm run check:silent-column-drop

Before changing default action behavior, also run the adapter suite on main and
on the branch and compare failures.

Documentation

Update after Phase 0:

  • skills/opencli-browser/SKILL.md: recommend snapshot/click/snapshot/click for
    custom dropdowns until choose exists.
  • Browser command help: explain that select is native <select> only.
  • Troubleshooting: explain zero_rect, not_visible, disabled,
    frame_unreachable, stale_ref_unresolved, and native_backend_unavailable.
  • Comparison guide: OpenCLI's goal is not "Playwright in CLI form"; it is an
    adapter-first CLI with reliable agent browser primitives.

Open Questions

  • Should the CDP click escape hatch be public (--mode js) or env-only?
    Prefer env-only unless a real adapter regression needs user control.
  • Should AX snapshot replace DOM snapshot by default or exist as
    --source ax first? Prefer opt-in/prototype first, then promote after
    fixture and manual SaaS validation.
  • How much actionability is enough? Start with scroll/rect/visible/enabled.
    Add stability/receives-events only with measured failures.
  • Does browser choose materially reduce successful Mercury workflows after
    AX refs land? If not, do not add it.

Design Mercury Fix Mvp (`docs/design/mercury-fix-mvp.md`)

Mercury Dropdown MVP

This is the short-term implementation slice for the Mercury expense category
failure. It is intentionally smaller than the full browser-agent-runtime
roadmap.

Problem

Mercury-style category controls are usually custom React dropdowns. The trigger
and option are not native <select> elements. Libraries such as Radix UI,
Material UI, and shadcn commonly open or commit selection on pointer/mouse down
or up events.

OpenCLI's generic browser click currently calls DOM el.click() first. That
only dispatches a click event, so OpenCLI can return success while the dropdown
never opened or the option never committed.

agent-browser succeeds in this class mainly because its click path sends real
CDP mouse events. It still uses the normal loop:

bash
snapshot
click trigger
snapshot
click option
snapshot or get value

It does not have a general one-shot custom-dropdown choose command.

MVP Scope

0. Extension CDP Capability Check

The MVP depends on Chrome debugger CDP passthrough. Unlike agent-browser,
OpenCLI usually reaches Chrome through the extension, so command availability
must be explicit.

Current status:

CDP command Extension status MVP action
Input.dispatchMouseEvent Allowed in extension/src/background.ts CDP passthrough and already used by nativeClick. No extension change for PR 1.
Accessibility.getFullAXTree Allowed in CDP passthrough. No extension change for AX fetch.
DOM.getBoxModel Allowed in CDP passthrough. No extension change for CDP point measurement.
DOM.describeNode Not currently in the CDP passthrough allowlist. Add to allowlist before AX iframe/subtree work.

Therefore PR 1 can ship without extension changes. PR 2 must either avoid
DOM.describeNode or include the small extension allowlist addition in the same
PR. If AX re-resolution needs DOM.resolveNode, that command must be added and
tested at the same time rather than assumed.

1. CDP Mouse Primary

Change generic browser click to:

  1. resolve target,
  2. scroll into view and measure a non-zero target box,
  3. send CDP Input.dispatchMouseEvent sequence:
    mouseMoved -> mousePressed -> mouseReleased,
  4. fall back to DOM el.click() only when native click is unavailable or the
    target has no usable point.

Required output behavior:

  • keep existing success shape,
  • add diagnostics only as additive fields if needed,
  • never report success from JS click before trying CDP when CDP is available.

This applies only to click-like actions: browser click and later
browser dblclick. It does not change browser select; native <select>
continues to use the existing JS option setter/change-event path.

2. Real Component Fixture

Add a local browser fixture that records event order and selected value.

Minimum cases:

  • Radix/shadcn-like select:
    • trigger opens on pointerdown,
    • option selects on pointerup or mousedown,
    • menu is rendered in a portal.
  • Material UI-like autocomplete:
    • combobox input opens popup,
    • option list is outside the trigger subtree.
  • Native <select> remains covered by existing browser select.

Pass condition:

  • Before PR 1, run and record baseline pass rate. At least one custom fixture
    case must fail on the DOM el.click() path.
  • After PR 1, custom fixture pass rate must be at least N-1/N, where N is
    the number of custom dropdown cases in the fixture.
  • OpenCLI verifies the selected text/value changed.

3. AX Snapshot Prototype

Add an AX-backed snapshot/ref-map prototype behind a non-breaking option or
internal test helper.

Required data per ref:

ts
type BrowserRef = {
  ref: string;
  backendNodeId?: number;
  role: string;
  name: string;
  nth?: number;
  frame?: { frameId?: string; sessionId?: string; url?: string };
};

Required behavior:

  • build refs from Accessibility.getFullAXTree,
  • use backendDOMNodeId as the fast path for action resolution,
  • if that id is stale, re-query the AX tree by role/name/nth,
  • keep current DOM snapshot text output stable until the AX path is proven.

This is the part that should learn most directly from agent-browser.

Success metric:

  • stale-ref recovery fixture must pass at least 9/10 repeated React re-render
    runs by resolving through AX role/name/nth.

4. Native Type/Fill Normalization

Review existing nativeType and fillText paths and make them consistent with
the native-input backend:

  • focus through CDP when possible,
  • use Input.insertText for printable text,
  • keep fill exact-replacement semantics,
  • keep existing verification as the authority for fill success.

Do not expand this into a full actionability rewrite in the MVP.

Non-Goals

  • No full Playwright actionability pipeline.
  • No broad Playwright API clone.
  • No general natural-language act.
  • No one-shot browser choose in this MVP.
  • No route/HAR/mock/trace-viewer surface.

browser choose can be considered after this MVP if measurements show that the
snapshot/click/snapshot/click loop is reliable but still too expensive for
agents.

PR Breakdown

PR 0: Extension Allowlist For AX Prototype

Only needed if PR 2 uses commands that are not already allowed.

  • add DOM.describeNode to CDP passthrough allowlist,
  • add DOM.resolveNode only if the implementation needs it,
  • add extension tests that blocked commands remain blocked and allowed AX/DOM
    commands pass.

PR 1: CDP-Primary Click

  • flip generic click to CDP-first,
  • keep JS fallback,
  • add event-order fixture tests,
  • run browser/unit gates and full adapter tests,
  • list every new adapter failure compared with main and fix them before merge.

This corresponds to the immediate Mercury reliability fix.

PR 2: AX Ref Prototype

  • add AX tree fetch through existing page.cdp,
  • create internal BrowserRef map,
  • implement cached backend id resolution plus role/name/nth fallback,
  • add stale React re-render fixture.

Keep this additive. Do not replace browser state default in the same PR.

Frame-aware routing is not part of the MVP. It moves to Phase 1 because the
Mercury exit criteria do not require iframe support.

Status after implementation:

  • PR 1 shipped CDP-primary click and component fixtures.
  • PR 2 shipped opt-in browser state --source ax, backend-node ref clicks, and
    stale role/name/nth recovery.
  • Phase 1 same-origin iframe refs shipped for AX snapshots; cross-origin
    session routing remains deferred.
  • Phase 1 metrics shipped as browser state --compare-sources so AX default
    promotion can be decided from measured DOM-vs-AX data.
  • Phase 1 visual refs shipped as browser screenshot --annotate, giving agents
    a screenshot whose visible labels map back to normal DOM [N] refs.

Phase 1 Follow-Up

  • carry same-origin frameId and cross-origin session id when available,

  • route click/fill/type by ref frame context,

  • return typed frame_unreachable when not possible,

  • add iframe fixture.

  • decide whether AX becomes default observation or an explicit --source ax,

  • update skills/opencli-browser/SKILL.md,

  • add troubleshooting docs and fixture examples,

  • record manual Mercury or Mercury-equivalent validation.

Compatibility Plan

Change Compatibility risk Mitigation
CDP click primary Event order changes from synthetic click to real mouse sequence. This is desired for dropdowns. PR 1 must run full adapter tests; all new failures must be listed and fixed before merge. Keep OPENCLI_BROWSER_CLICK=js as emergency plan B for one release, not as a substitute for fixing tests.
AX refs Ref internals change; text output should not. Add AX map internally first; preserve visible state format.
Stale-ref recovery A stale ref may now resolve to a new node with same role/name/nth. Only use fallback for refs, not arbitrary CSS selectors; include diagnostic field when recovery happens.
Frame routing Actions may reach iframe elements that previously failed. Phase 1 only. Add typed errors for unsupported frames instead of silent fallback.
Native select Risk of accidental behavior change if "click-like" is interpreted broadly. Out of scope for PR 1. browser select keeps JS option setter/change-event behavior.

Exit Criteria

  • A custom dropdown fixture that depends on pointer/mouse events passes through
    browser click.
  • A portal-rendered option can be selected with the normal
    snapshot/click/snapshot/click loop.
  • A stale React-ref fixture recovers through AX role/name/nth.
  • Existing browser tests and adapter tests pass.
  • Documentation tells agents the correct current recipe and does not promise
    choose until it exists.

Quantitative gates:

  • Custom dropdown fixtures: record baseline before PR 1, then pass at least
    N-1/N custom cases after PR 1.
  • Stale-ref recovery: pass at least 9/10 repeated re-render runs after PR 2.
  • Adapter compatibility: zero unexplained new full-adapter-test failures before
    a default behavior PR merges.

Manual SaaS check:

  • After Phase 0, @opencli-质量官 runs Mercury, Brex, and Linear manually when
    credentials/access are available.
  • Pass means the workflow can select the relevant category/field and save or
    commit the form state.
  • For each site, also run opencli browser --session research state --compare-sources on the form
    page and record sources.dom.refs, sources.ax.refs, frame_sections,
    approx_tokens, elapsed_ms, and any per-source error.
  • Failure does not block MVP retroactively, but each failure must be recorded as
    a Phase 1 backlog item with observed command sequence and failure reason.

Validation Commands

bash
npm run build
npm run typecheck
npm test -- --run src/browser src/cli.test.ts
npm run check:typed-error-lint
npm run check:silent-column-drop

Before merging a default behavior change:

bash
npm test -- --run

If full tests are too slow in the review loop, run full adapter tests at least
once before merge and report any difference from main.


Developer Ai Workflow (`docs/developer/ai-workflow.md`)

Building adapters with an agent

OpenCLI supplies composable tools and observable results. The agent chooses its
implementation from the task, available site behavior and existing adapters.

Discover capabilities

sh
opencli list search --site example
opencli example search --help -f json

list returns compact capabilities with total and optional nextOffset.
Default command results use {ok:true,data:...}; failures use
{ok:false,error:{code,message,hint?,...}} and a nonzero exit code. Logs go to stderr.

Inspect a site

sh
opencli browser open https://example.com --session research
opencli browser state --diagnostics --session research
opencli browser network --static --session research
opencli browser network --detail RequestKey --session research

Page facts, captured requests and AST candidates inform implementation choices.
Static candidates are unexecuted evidence; the agent decides what to investigate.
browser chrome describe exposes native tab, group and window management without
a page session. Use doctor to diagnose connectivity when needed.

Implement and exercise

sh
opencli adapter init example/search
opencli adapter check example/search
opencli adapter test example/search --args '{"query":"hello"}'

Write a normal JS file. cli({...}), func(args) and func(page,args) remain the
adapter contract. Return business data; the CLI adds the JSON envelope.
check validates definitions; test executes the real command and optionally
compares a fixture. Write adapters have real effects when tested.

There is no draft store, promotion step, required strategy note or site-memory gate.
Use focused tests and real execution to cover core behavior, error paths and
business semantics. Optional traces and fixtures help investigate failures.

See opencli-adapter-author
and opencli-browser
for the tool contracts and references.


Developer Architecture (`docs/developer/architecture.md`)

Architecture

OpenCLI is a command surface that sits on top of four major subsystems:

  1. command discovery and registry
  2. execution and formatting
  3. browser / daemon / CDP connectivity
  4. adapter and plugin integration

Runtime Shape

text
opencli CLI
  ├─ command discovery / registry
  ├─ execution / output
  ├─ browser runtime
  │   ├─ Browser Bridge extension
  │   ├─ local daemon
  │   └─ direct CDP path
  ├─ adapter loading
  │   ├─ built-in site adapters
  │   ├─ generated adapters
  │   └─ pipeline-backed adapters
  └─ plugin loading

Core Modules

CLI Surface

  • src/main.ts — process entrypoint
  • src/cli.ts — top-level command tree and built-in command groups
  • src/completion.ts / src/completion-fast.ts — shell completion

Discovery, Registry, Execution

  • src/discovery.ts — discovers built-in adapters, generated adapters, plugins, and manifests
  • src/registry.ts — central command registry
  • src/registry-api.ts — adapter-facing registration helpers
  • src/execution.ts — argument validation, lazy loading, and command execution
  • src/commanderAdapter.ts — bridges registry metadata into Commander subcommands
  • src/output.ts — table, json, yaml, md, csv formatting
  • src/serialization.ts — registry and manifest serialization helpers

Browser and Runtime

  • src/runtime.ts — shared command runtime and target resolution
  • src/daemon.ts — lifecycle and bridge behavior for the local daemon
  • src/doctor.ts — browser bridge diagnostics
  • src/observation/ — trace artifacts, redaction, and structured runtime evidence
  • src/interceptor.ts — interception helpers for browser-backed strategies
  • src/browser/ — Browser Bridge connection and browser-side primitives

Pipeline Engine

  • src/pipeline/executor.ts — pipeline execution
  • src/pipeline/template.ts — template expansion
  • src/pipeline/transform.ts — transform helpers
  • src/pipeline/steps/ — concrete steps such as:
    • fetch
    • download
    • browser
    • intercept
    • tap
    • transform

Adapter and Extension Surfaces

  • clis/ — built-in site adapters
  • src/plugin.ts / src/plugin-manifest.ts / src/plugin-scaffold.ts — plugin install, metadata, scaffold

Command Sources

OpenCLI merges commands from multiple places into one registry:

Source Location Examples
Built-in adapters clis/ twitter, bilibili, reddit, chatgpt
Generated / local adapters ~/.opencli/clis/ user-authored adapters
Plugins ~/.opencli/plugins/ community-contributed commands

The user sees one unified command tree through opencli list.

Connectivity Modes

Browser Bridge mode

Primary path for browser-backed commands:

text
opencli process
  ↔ local daemon
  ↔ Browser Bridge extension
  ↔ logged-in Chrome / Chromium

This path is used for:

  • cookie-backed websites
  • browser automation primitives
  • interactive browser verification

Direct CDP mode

Used when OpenCLI talks directly to a Chrome debugging endpoint through OPENCLI_CDP_ENDPOINT.

Typical uses:

  • remote Chrome
  • headless Chrome

Authentication / Access Strategies

OpenCLI currently uses these access strategies:

Strategy Purpose
public direct fetch with no login
cookie reuse browser session cookies
intercept capture the app's own network responses
ui DOM / accessibility driven interaction

The key distinction is operational:

  • public favors direct network access
  • cookie, intercept, ui depend on a live browser surface

High-Risk Change Zones

Changes in these files usually affect broad command behavior:

  • src/cli.ts
  • src/commanderAdapter.ts
  • src/discovery.ts
  • src/execution.ts
  • src/runtime.ts
  • src/daemon.ts
  • src/plugin.ts
  • src/pipeline/**

These areas deserve targeted tests first, then broader validation when the change crosses module boundaries.

Mental Model

The simplest accurate model is:

  1. OpenCLI discovers command definitions.
  2. It registers them into one command registry.
  3. It resolves each invocation through execution + runtime.
  4. It reaches the target through one of:
    • network fetch
    • Browser Bridge
    • direct CDP
  5. It formats the result into a stable output surface.

That is the architecture to preserve when refactoring.


Developer Contributing (`docs/developer/contributing.md`)

Contributing

Thanks for your interest in contributing to OpenCLI.

Quick Start

bash
# 1. Fork & clone
git clone [email protected]:<your-username>/opencli.git
cd opencli

# 2. Install dependencies
npm install

# 3. Build
npm run build

# 4. Run a few checks
npx tsc --noEmit
npm run build

# 5. Link globally (optional, for testing `opencli` command)
npm link

Adding a New Site Adapter

This is the most common type of contribution. All adapters use TypeScript with the cli() API.

Before you start:

  • Prefer positional args for the command's primary subject (search <query>, topic , download ). Reserve named flags for optional modifiers such as --limit, --sort, --lang, and --output.
  • Normalize expected adapter failures to CliError subclasses instead of raw Error whenever possible. Prefer AuthRequiredError, EmptyResultError, CommandExecutionError, TimeoutError, and ArgumentError so the top-level CLI can render better messages and hints.
  • If you add a new adapter or make a command newly discoverable, update the matching doc page and the user-facing indexes that expose it.

Create the Adapter

Built-in adapters are authored in JavaScript. Create a file like clis/<site>/<command>.js:

javascript
import { cli, Strategy } from '@jackwener/opencli/registry';
import { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';

cli({
  site: 'mysite',
  name: 'search',
  description: 'Search MySite',
  access: 'read', // 'read' | 'write'
  example: 'opencli mysite search <query> -f yaml',
  domain: 'www.mysite.com',
  strategy: Strategy.COOKIE,
  args: [
    { name: 'query', positional: true, required: true, help: 'Search query' },
    { name: 'limit', type: 'int', default: 10, help: 'Max results' },
  ],
  columns: ['title', 'url', 'date'],

  func: async (page, kwargs) => {
    const { query, limit = 10 } = kwargs;
    // ... browser automation logic
    if (!Array.isArray(data)) throw new CommandExecutionError('MySite returned an unexpected response');
    if (!data.length) throw new EmptyResultError('mysite search', 'Try a different keyword');
    return data.slice(0, Number(limit)).map((item) => ({
      title: item.title,
      url: item.url,
      date: item.created_at,
    }));
  },
});

TypeScript adapters are also supported — see TypeScript Adapter.

Validate Your Adapter

bash
opencli <site> <command> --limit 3 -f json   # Test your command
opencli <site> <command> -v    # Verbose mode for debugging

Code Style

  • TypeScript strict mode — avoid any where possible.
  • ES Modules — use .js extensions in imports (TypeScript output).
  • Naming: kebab-case for files, camelCase for variables/functions, PascalCase for types/classes.
  • No default exports — use named exports.
  • Errors — throw CliError subclasses for expected adapter failures; avoid raw Error for normal adapter control flow.

Commit Convention

We use Conventional Commits:

text
feat(twitter): add thread command
fix(browser): handle CDP timeout gracefully
docs: update CONTRIBUTING.md
test(reddit): add e2e test for save command
chore: bump vitest to v4

Submitting a Pull Request

  1. Create a feature branch: git checkout -b feat/mysite-trending
  2. Make your changes and add tests when relevant
  3. Run the smallest check set that matches your change:
    bash
    npx tsc --noEmit           # Type check
    npm run build              # Ensure dist stays healthy
    npx vitest run clis/<site>/<command>.test.js   # Your adapter's tests
    npm test                   # Broader local gate when shared runtime changes justify it
  4. Commit using conventional commit format
  5. Push and open a PR

If your PR adds a new adapter or changes user-facing commands, also verify:

  • Adapter docs exist under docs/adapters/
  • docs/adapters/index.md is updated for new adapters
  • VitePress sidebar includes the new doc page
  • README.md / README.zh-CN.md stay aligned when command discoverability changes

Developer Documentation Audit 2026 05 (`docs/developer/documentation-audit-2026-05.md`)

Documentation Audit — 2026-05

This document reviews the current long-form docs, README surfaces, and developer guides in opencli. It focuses on stale facts, internal contradictions, and documentation structure that now causes drift.

Scope

  • README.md
  • README.zh-CN.md
  • docs/
  • skills/ references that are linked from user-facing docs

Executive View

The docs are usable, but they are drifting in four visible ways:

  1. Hard-coded counts and feature claims are stale.
  2. Developer docs describe an older architecture and older test layout.
  3. English and Chinese docs are no longer updated with the same rigor.
  4. Some pages still describe deleted concepts or old workflows.

The highest-value work is:

  1. Fix the stale facts in README*, docs/index.md, docs/zh/index.md, and docs/guide/getting-started.md.
  2. Rewrite docs/developer/testing.md and docs/developer/architecture.md against current main.
  3. Make English and Chinese entry docs derive from the same source-of-truth checklist.
  4. Stop writing command/adapters counts by hand unless they are generated.

Priority 0 — Clearly stale or incorrect

1. Adapter / site counts are stale across multiple entry points

Affected files:

  • README.md
  • README.zh-CN.md
  • docs/guide/getting-started.md
  • docs/comparison.md

Current problems:

  • README.md and README.zh-CN.md still say 90+ adapters.
  • docs/guide/getting-started.md still says 87+ pre-built adapters.
  • docs/comparison.md still says 87+ sites.

Current reality:

  • node dist/src/main.js list --format json | jq 'map(.site) | unique | length' returns 106.

Why this matters:

  • These are the first pages people read.
  • The mismatch is easy to notice and weakens trust in the rest of the docs.
  • These values will keep drifting if we maintain them manually.

Recommended fix:

  • Replace all hard-coded counts with one of:
    • 100+
    • 100+ sites
    • over 100 registered sites
  • Best option: generate this number into docs at release time or avoid explicit counts entirely.

2. `docs/developer/testing.md` is materially out of date

Affected file:

  • docs/developer/testing.md

Current problems:

  • It says adapter tests live in clis/**/*.test.{ts,js}.
  • The file examples name adapter tests such as:
    • clis/zhihu/download.test.ts
    • clis/twitter/timeline.test.ts
    • clis/reddit/read.test.ts
    • clis/bilibili/dynamic.test.ts
  • Those files do not exist.
  • It says E2E coverage is 5 files.
  • Current reality is 11 E2E files.
  • It presents npm test as the main local gate, while current team rule is to prefer the smallest sufficient test set instead of default full-suite runs.

Current reality from the repo:

  • find src -name '*.test.ts' | wc -l → 60
  • find clis -iregex '.*\\.test\\.(ts|js)$' | wc -l → 0
  • find tests/e2e -name '*.test.ts' | wc -l → 11
  • find tests/smoke -name '*.test.ts' | wc -l → 1

Why this matters:

  • This page is the main developer testing contract.
  • A new contributor following it will get the wrong mental model of the test layout.
  • It encourages a heavier default test habit than the team currently wants.

Recommended fix:

  • Rewrite the page from current files, not from remembered structure.
  • Separate:
    • fast local checks
    • targeted validation
    • full CI coverage
  • Remove nonexistent adapter test examples.
  • Add a short rule:
    • local default = smallest sufficient validation
    • full-suite = broader refactor, shared runtime changes, or CI

3. `docs/developer/architecture.md` describes an older system shape

Affected file:

  • docs/developer/architecture.md

Current problems:

  • It refers to src/browser.ts, but that file does not exist.
  • The directory structure block says src/clis/, but adapters live at top-level clis/.
  • The architecture diagram is too simplified for the current system and omits important pieces such as:
    • daemon.ts
    • plugin.ts
    • update check / diagnostics / runtime detection paths
  • It says “3-tier authentication strategy” but lists 5 strategies.

Why this matters:

  • This is the page people read to understand the project.
  • Once architecture docs are stale, all deeper docs become harder to trust.

Recommended fix:

  • Rewrite this page around current modules:
    • command discovery and registry
    • execution
    • browser / daemon bridge
    • plugin system
    • direct browser CDP path
    • pipeline engine
  • Replace the static tree with a curated module map that matches current filenames.
  • Change “3-tier” to a neutral label like authentication strategies.

4. Home pages still mention deleted concepts

Affected files:

  • docs/index.md
  • docs/zh/index.md

Current problems:

  • Both home pages say:
    • explore
    • synthesize
    • cascade
  • docs/developer/ai-workflow.md explicitly says those commands do not exist and that the skill drives the loop.

Why this matters:

  • The home page is currently teaching a product vocabulary that the actual CLI does not have.
  • This creates immediate confusion for users who go from docs to terminal.

Recommended fix:

  • Replace those phrases with current concepts:
    • browser primitives
    • adapter-authoring skill
    • verify loop
  • Keep the homepage aligned with docs/developer/ai-workflow.md.

5. Chinese getting-started page lists a deleted built-in command

Affected file:

  • docs/zh/guide/getting-started.md

Current problem:

  • It says built-in commands include list、explore、validate...
  • explore is not a current built-in command.

Why this matters:

  • This is a hard user-facing error.

Recommended fix:

  • Replace the example list with current built-ins such as:
    • list
    • validate
    • verify
    • browser
    • doctor
    • plugin
    • adapter

Priority 1 — Inconsistent or incomplete

6. Installation pages are inconsistent about runtime support and update flow

Affected files:

  • README.md
  • README.zh-CN.md
  • docs/guide/installation.md
  • docs/zh/guide/installation.md

Current problems:

  • README.md says Node >= 21 or Bun >= 1.0.
  • docs/guide/installation.md and docs/zh/guide/installation.md only mention Node.
  • README.md documents skill refresh on update.
  • docs/zh/guide/installation.md only documents package update and omits skills refresh.

Why this matters:

  • Entry docs should agree on install prerequisites and upgrade procedure.

Recommended fix:

  • Pick one official runtime support statement and reuse it everywhere.
  • If Bun is supported, add it consistently to guide pages.
  • Mirror the post-update skill refresh guidance in the install/update guides.

7. README and docs still use top-level tables and examples that will drift by hand

Affected files:

  • README.md
  • README.zh-CN.md

Current problems:

  • The “Built-in Commands” section is manually curated and already partially selective.
  • The surrounding copy still frames it like a broad current snapshot.

Why this matters:

  • Manual command snapshots go stale quickly in a repo with active adapter growth.

Recommended fix:

  • Reframe the section as:
    • “Representative built-in commands”
    • “Sample sites”
  • Keep opencli list and docs/adapters/index.md as the full registry surface.

8. `docs/comparison.md` contains stale scale claims

Affected file:

  • docs/comparison.md

Current problem:

  • It still says 87+ sites.

Why this matters:

  • Comparison pages shape market positioning.
  • Stale numbers make the project look less maintained than it is.

Recommended fix:

  • Remove exact numbers from comparison copy unless they are generated.

Priority 2 — Structural drift risks

9. English and Chinese docs are drifting independently

Most visible examples:

  • docs/index.md and docs/zh/index.md both kept the deleted explore / synthesize / cascade language.
  • docs/zh/guide/getting-started.md contains a stale built-in command example that should have been caught by parity review.
  • README.md and README.zh-CN.md both carry the same stale adapter count.

Why this keeps happening:

  • We have mirrored content with no explicit parity checklist.
  • Updates land in one place and rely on memory for the rest.

Recommended fix:

  • Introduce a small doc parity checklist for any change that touches:
    • README.md
    • README.zh-CN.md
    • docs/index.md
    • docs/zh/index.md
    • docs/guide/*
    • docs/zh/guide/*
  • Add one PR checklist item:
    • “Did this change require an English/Chinese mirror update?”

10. Core product pages mix generated facts with narrative copy

Examples:

  • command counts
  • site counts
  • test counts
  • lists of built-in commands

Why this matters:

  • Numbers and command inventories drift faster than narrative guidance.

Recommended fix:

  • For fast-changing facts:
    • generate them
    • or generalize them
  • Reserve hand-written docs for:
    • mental models
    • workflows
    • constraints
    • trade-offs

Suggested rewrite order

Pass 1 — Fix trust-breaking errors

  1. README.md
  2. README.zh-CN.md
  3. docs/index.md
  4. docs/zh/index.md
  5. docs/guide/getting-started.md
  6. docs/zh/guide/getting-started.md
  7. docs/comparison.md

Pass 2 — Rebuild the technical source-of-truth pages

  1. docs/developer/testing.md
  2. docs/developer/architecture.md
  3. docs/guide/installation.md
  4. docs/zh/guide/installation.md

Pass 3 — Prevent the next round of drift

  1. Add a docs parity checklist to PR workflow.
  2. Remove exact counts from hand-written copy unless generated.
  3. Decide which pages are authoritative for:
    • install
    • browser bridge
    • testing
    • architecture
    • AI workflow

Concrete edits I would make next

Small fast edits

  • Replace all 87+ / 90+ claims with 100+.
  • Remove explore / synthesize / cascade from both home pages.
  • Remove explore from docs/zh/guide/getting-started.md.
  • Align install docs on Node/Bun support and skill refresh.

Medium rewrites

  • Rewrite docs/developer/testing.md from current filesystem state.
  • Rewrite docs/developer/architecture.md from current module boundaries.

Process fix

  • Add a lightweight “doc drift” checklist to PRs that touch command surface, runtime support, testing strategy, or adapter discovery.

Bottom line

The docs do not need a ground-up rewrite. They need a focused trust repair pass on entry pages, then a source-of-truth rebuild for testing and architecture, then a small process change so counts and mirrored pages stop drifting.


Developer Testing (`docs/developer/testing.md`)

Testing Guide

测试配置以 vitest.config.ts 和 package.json 为准;不要维护容易过期的测试数量清单。

测试职责

Project 位置 负责验证
unit src/**/*.test.ts 核心逻辑、参数、输出、runtime 与错误分类
extension extension/src/**/*.test.ts 使用 mocked Chrome APIs 的 extension 行为
adapter clis/**/*.test.{ts,js} 站点解析、数据归一化、站点特有错误与 command wiring
e2e-fixed-port tests/e2e/browser-tabs.test.ts、daemon-transport.test.ts 真实 daemon 与模拟 extension 的协议;串行运行
e2e tests/e2e/ 中配置启用的文件 默认只跑离线 CLI、管理命令与 auth contract;真实站点和 GitHub plugin 测试需显式启用
smoke tests/smoke/ 公开 API 与命令注册健康检查,无需 Chrome

本地验证

先跑改动对应的测试;共享逻辑或跨模块改动再扩大范围。

bash
npm ci
npm run build

# 默认:unit + extension + adapter,不调用真实站点 E2E
npm test

# 目标文件
npx vitest run --project adapter clis/ctrip/auth.test.js

# 真实 CLI + 隔离的站点 fixture,无需登录或 Chrome
npx vitest run --project e2e tests/e2e/auth-contract.test.ts tests/e2e/management.test.ts

# 离线 CLI 与 daemon contract(固定端口测试会重启 daemon)
npm run test:e2e

# 少量严格的真实公开 API 检查
npx vitest run --project smoke

# 所有默认启用的 projects,包含公开 API smoke
npm run test:all

npm run build 已包含 TypeScript 检查。只需要类型反馈时可单独运行 npm run typecheck。
E2E 运行构建后的 CLI,修改源码后先重新 build。
e2e-fixed-port 使用固定端口,运行前确认不会与正在使用的 daemon 冲突。

如何避免重复测试

  • 共享 helper 的完整边界矩阵放在 helper 所在层;各 command 保留必要 wiring 验证。
  • Adapter test 覆盖站点 response shape 和解析边界;E2E 保留代表性的成功、typed error、exit code 与跨层连接验证,不复制整套解析矩阵。
  • CLI 输出格式入口统一放在 tests/e2e/management.test.ts;具体格式渲染逻辑放在 src/output.test.ts。
  • 不逐 command 抄录 columns、strategy、默认值做静态断言;manifest 一致性、全量 validate 与 column lint 统一负责声明检查。站点测试应调用行为;特有的 session/navigation contract 仍可保留。
  • 相同 test body 如果调用不同 command,并不自动构成重复。
  • 不添加“非零退出时只要有文字就通过”的 auth test:未知命令和程序崩溃也能满足这种断言。应检查具体错误类型、状态或输出内容。
  • 不为了验证 auth 自动执行创建、删除、发布或付费操作;使用隔离 fixture 验证这些分支。

浏览器与真实站点

browser-public.test.ts 等真实站点测试依赖网络、站点状态和可用的 Browser Bridge。
部分测试允许站点限制导致的空数据,因此不能把这些通过结果视为完整登录流程已验证。
Auth 的确定性 CLI contract 在 auth-contract.test.ts,站点特有判断在 adapter tests。

可选测试通过环境变量启用:

bash
# 手动运行真实站点、文章下载与 GitHub plugin 测试
OPENCLI_E2E=1 npm run test:e2e

# 真实 Chrome + extension contract
OPENCLI_AX_E2E=1 npx vitest run --project e2e tests/e2e/browser-ax-chrome.test.ts

# 站点槽位池(OPENCLI_SITE_SLOTS):真实 daemon + extension + 隔离浏览器,本地 fixture;需先停掉占用 19825 的 daemon。
# 品牌版 Google Chrome 会忽略 --load-extension,需用 CHROME_PATH 指向 Chromium / Chrome for Testing
# 本地有界面时窗口可能被其他窗口遮挡、被系统标记为 hidden,渲染断言会不稳定,建议加 OPENCLI_E2E_HEADLESS=1
OPENCLI_E2E_HEADLESS=1 CHROME_PATH=/path/to/chrome-for-testing OPENCLI_AX_E2E=1 npx vitest run --project e2e tests/e2e/site-slots-chrome.test.ts

真实登录问题还应使用已登录浏览器,手动执行对应的只读命令验证。

CI 分工

Workflow / job 频率 覆盖
CI / build PR、main/dev push、每周、手动 Linux build、lint、manifest 与全部离线 CLI E2E;每周/手动再跑三 OS build
CI / unit-test 同上 Linux 两个 shard 跑完整 unit + extension + adapter;每周/手动额外跑 macOS/Windows core tests
CI / bun-test 每周、手动 Bun runtime compatibility
CI / smoke-test 每周、手动 四个公开 API family 的代表性 endpoint;非零退出即失败
E2E Headed Chrome 匹配路径的 main/dev push、release tag、每日、手动 三 OS 的 CLI tab/daemon contract;Linux 真实 extension,不重复整套站点 E2E

Bun compatibility 不再作为每次 PR 的 gate;相关 runtime 改动应在本地额外运行 npm run test:bun。
CI 的精确触发条件与命令以 .github/workflows/ 为准。

跨平台 core/build 回归改由每周或手动检查,可能比每次 push 更晚发现。真实站点宽覆盖改为 opt-in;默认 CI 不证明所有网站当前可用。


Developer Ts Adapter (`docs/developer/ts-adapter.md`)

TypeScript Adapter Guide

Use TypeScript adapters when you need browser-side logic, multi-step flows, DOM manipulation, or complex data extraction that goes beyond simple API fetching.

Basic Structure

typescript
import { cli, Strategy } from '@jackwener/opencli/registry';
import { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';

cli({
  site: 'mysite',
  name: 'search',
  description: 'Search MySite',
  access: 'read', // 'read' | 'write'
  example: 'opencli mysite search <query> -f yaml',
  domain: 'www.mysite.com',
  strategy: Strategy.COOKIE,      // PUBLIC | COOKIE | INTERCEPT | UI
  args: [
    { name: 'query', required: true, help: 'Search query' },
    { name: 'limit', type: 'int', default: 10, help: 'Max results' },
  ],
  columns: ['title', 'url', 'date'],

  func: async (page, kwargs) => {
    const { query, limit = 10 } = kwargs;

    // Navigate and extract data
    await page.goto('https://www.mysite.com');

    const data = await page.evaluate(async (q: string) => {
      const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`, {
        credentials: 'include',
      });
      return (await res.json()).results;
    }, String(query));

    if (!Array.isArray(data)) throw new CommandExecutionError('MySite returned an unexpected response');
    if (!data.length) throw new EmptyResultError('mysite search', 'Try a different keyword');

    return data.slice(0, Number(limit)).map((item: any) => ({
      title: item.title,
      url: item.url,
      date: item.created_at,
    }));
  },
});

Pipeline JSON Requests

The fetch pipeline step can send JSON request bodies from Node or the browser
session. Define a body alongside an explicit HTTP method:

typescript
pipeline: [
  {
    fetch: {
      url: 'https://example.com/graphql',
      method: 'POST',
      body: {
        query: 'query Search($term: String!, $limit: Int!) { search(term: $term, limit: $limit) { id title } }',
        variables: {
          term: '${{ args.query }}',
          limit: '${{ args.limit }}',
        },
      },
    },
  },
  { select: 'data.search' },
]

Body templates support nested objects and arrays. A full expression keeps its
value type, so numbers, booleans, arrays, objects and null remain JSON values.
Use body: '${{ data }}' to send the previous step's complete result. Strings
inside values returned by expressions are treated as data, without another
template evaluation pass.

Bodies are JSON-encoded exactly once, including scalar strings. The step adds
Content-Type: application/json unless a content-type header is already present
(case-insensitive). It preserves explicit headers. GET and HEAD requests cannot
have a body; an omitted body sends no payload. A body that resolves to undefined
or cannot be JSON-serialized fails before any request is sent. Raw text, form data
and file uploads are not supported by this JSON request option.

Per-item Requests

Set forEach: true to issue one request per element of the preceding step's
array, including when every request uses the same URL:

typescript
pipeline: [
  { fetch: 'https://example.com/catalog' },
  { select: 'entries' },
  {
    fetch: {
      url: 'https://example.com/graphql',
      method: 'POST',
      forEach: true,
      concurrency: 3,
      params: { language: '${{ args.language }}' },
      headers: { 'X-Request-Index': '${{ index }}' },
      body: {
        query: 'query Detail($id: ID!) { entry(id: $id) { id title } }',
        variables: { id: '${{ item.id }}' },
      },
    },
  },
]

URLs, query parameters, headers and bodies all receive the same per-item context:
item is the current element, index is zero-based, data is the complete input
array, and args contains command arguments. forEach: true requires an array;
an empty array produces [] without making requests. Use forEach: false to
force a single request, for example to send an entire array as one JSON body.
When omitted, existing implicit per-item URL fetching continues to apply.

Concurrency defaults to 5 and must be a positive integer. Results retain input
order even if requests finish out of order. Batch HTTP or network failures occupy
their result slot as { error: '...' }; successful requests are not repeated.
Body serialization completes before sending begins, so an undefined or
unserializable body fails the whole batch before any requests are issued.
Browser batches run in one evaluation and include the browser's credentials.

Access Metadata

Every adapter must declare access: 'read' | 'write'.

  • Use read when the command only retrieves data from the target product or account.
  • Use write when the command changes remote product/account state, such as sending messages, publishing, liking, following, buying, deleting, creating remote assets, or starting paid/credit-consuming generation.
  • download and export commands are read when they only read remote data and write local files; local filesystem writes are a separate permission dimension.

Adapters may also declare example to override the canonical invocation shown in agent-facing help. Prefer YAML examples, e.g. opencli mysite search <query> -f yaml.

Listing↔Detail ID Pairing (advisory)

If your site exposes both a listing-class command (search / hot / top /
recent / ...) and a detail-class command (read / paper / article /
post / view / ...), it's usually nicer for agents if listing rows surface
an id-shaped column that round-trips into the detail command's positional
arg. Without that, an agent can't follow up on a row without re-searching by
title or scraping a URL out of band.

This is a soft convention, not a CI gate. Many legitimate listings
genuinely don't pair (topic-string trending, profile-attribute rows,
UI-only sessions). Use judgment per command, not a checklist.

Run npm run advise:listing-id-pairing to see candidate listings without an
id column. See Listing↔Detail ID Pairing
for context, the full pattern table, and how to add an id to a listing.

Strategy Types

Strategy Constant Use Case
Public Strategy.PUBLIC No auth needed
Cookie Strategy.COOKIE Browser session cookies
Intercept Strategy.INTERCEPT Capture browser requests/responses
UI Strategy.UI Drive authenticated browser UI

Browser Session Reuse

Browser-backed commands are one-shot by default: each execution gets a fresh
tab lease and releases it when the command returns. For interactive sites where
successive commands should continue in the same page, opt into a persistent site
session:

typescript
cli({
  site: 'mysite',
  name: 'ask',
  strategy: Strategy.COOKIE,
  siteSession: 'persistent',
  // ...
});

siteSession: 'persistent' makes commands for the same site share a stable
adapter site tab and keeps that tab open until it is explicitly closed. Users
can override the adapter default with --site-session ephemeral or force
persistence with --site-session persistent.

A persistent site tab is shared, so concurrent persistent commands for one site
can navigate each other's page. Users who batch a site can instead pool it with
OPENCLI_SITE_SLOTS (for example xiaohongshu:1:1500-3000): each command run
borrows one of poolSize persistent slot sessions (site:<site>#<n>, one warm
tab each) for its whole duration, reads included, and waits in a daemon-side
queue when every slot is busy. A command's --timeout covers the queue wait and
the run together; without one, the wait alone is capped at 60s. The optional interval spaces slot grants start-to-start, so the
pace applies per command run rather than per navigation. A waiting command that
exits leaves the queue. When a holder stops sending commands for longer than the
session-lease TTL, its slot can go to the next waiting run. Commands from expired
or released runs are rejected until they acquire a slot again. Adapters need no changes to be pooled.

All adapter tabs share one automation window, and only its active tab renders.
A pooled run brings its slot tab to the front when it starts, but another
command opening a tab during the run (or a second slot of the same site) puts it
in the background, where rAF and IntersectionObserver-driven lazy loading stall.
Keep poolSize at 1 for render-dependent commands.
Slot pools require Browser Bridge; direct CDP callers can opt out with
--site-session ephemeral. Pool sizes are limited to 1–32 and intervals/wait
budgets to 2,147,483,647 ms. Concurrent callers must use the same policy while a
pool has active runs or waiters. A policy can change after the pool is idle.
Manual slot-session commands are rejected while a run holds that slot; runs
must acquire their own slot and cannot reuse a run identity in another pool.

The `page` Object

The page parameter provides browser interaction methods:

  • page.goto(url) — Navigate to a URL
  • page.evaluate(fn, ...args) — Execute a serializable function in the page context. Pass Node-side values through JSON-serializable args; the function cannot close over local variables.
  • page.evaluate(script) — Execute a raw JavaScript string in the page context. Prefer function form for new adapter code.
  • page.waitForSelector(selector) — Wait for an element
  • page.click(selector) — Click an element
  • page.type(selector, text) — Type text into an input

The `kwargs` Object

Contains parsed CLI arguments as key-value pairs. Always destructure with defaults:

typescript
const { query, limit = 10, format = 'json' } = kwargs;

For most search/read/detail commands, the main subject should be positional (opencli mysite search "rust", opencli mysite article 123) instead of a named flag such as --query or --id. Keep named flags for optional modifiers.

Error Handling

Prefer throwing CliError subclasses from src/errors.ts for expected adapter failures:

  • AuthRequiredError for missing login / cookies
  • EmptyResultError for empty but valid responses
  • CommandExecutionError for unexpected API or browser failures
  • TimeoutError for site timeouts
  • ArgumentError for invalid user input

Avoid raw Error for normal adapter control flow. This keeps top-level CLI output consistent and preserves hints for users.

AI-Assisted Development

Use the opencli-adapter-author skill plus the opencli browser * primitives to scaffold and verify adapters end-to-end:

bash
# Recon on the target site
opencli browser --session research open https://example.com
opencli browser --session research network
opencli browser --session research state

# Scaffold + verify
opencli adapter init mysite/trending
opencli adapter test mysite/trending

See AI Workflow for the full loop and the adapter-author skill for the step-by-step runbook.


Developer Yaml Adapter (`docs/developer/yaml-adapter.md`)

YAML Adapter Guide (Deprecated)

YAML adapters are no longer supported. All adapters now use TypeScript with the cli() API from @jackwener/opencli/registry.

See Contributing Guide for how to write TypeScript adapters using the pipeline API or func().


Development Auth Audit 2026 10 (`docs/development/auth-audit-2026-10.md`)

Authentication audit — October 2026

Base: 77af6bc4 (OpenCLI 1.8.8). The audit covers all 70 auth.js / whoami.js entry files, shared registration, CLI status/refresh aggregation, Browser Bridge cookie transport, direct CDP cookie scope, command discovery, and dependency advisories. The complete unit, extension and adapter suites were run before and after the changes. This is a source and regression audit; it is not a claim that every website was tested with a live account.

Confirmed defects addressed

Layer Defect Verification
Ctrip login_uid was required before any account check; stale cookies also counted as an account Current homepage's getMemberSummaryInfo request inspected; anonymous and signed-in browser probes; fixture CLI tests for absent legacy cookies, stale cookies, API outages and schema changes
Ctrip identity Successful current responses may redact uid and userName Live response verified against the homepage membership label; missing identity fields remain empty instead of triggering login
Shared auth Null/empty/invalid identity responses could become logged_in: true; adapter metadata could override the site; unknown quick checks became false Contract tests for invalid responses, explicit logout and unknown signals
CLI status Full probes ignored explicit negative results; lazy import errors could abort the entire batch Negative/invalid response tests and mixed working/broken adapter tests
CLI refresh Unknown checks were classified as logout; explicit profiles shared a throttle Tri-state checks and independent profile throttle tests
Browser Bridge Malformed cookie replies silently became empty cookie jars Transport response validation tests
Direct CDP Domain cookie reads were limited to the current page; domain filtering differed from Chrome Storage-wide reads, parent/subdomain and URL/path tests; Storage.getCookies verified in Chrome
Gemini / Gmail / NotebookLM Cookie gates, locale-specific account selectors and an incorrectly escaped Gmail regex Actual browser probe JS evaluated against English and simplified/traditional Chinese DOM fixtures; signed-in Gemini live probe
Google apps / ChatGPT Login polling could navigate away from OAuth forms or wait forever for a legacy cookie Polling tests keep the login form open and complete on return without cookie preconditions
Claude A successful authenticated organizations response still required an analytics cookie Authenticated response with no analytics cookies
DeepSeek / HF / Gitee / Jimeng / Quark Polling swallowed API/transport failures as “waiting for login” HTTP 503 during polling remains a command error
12306 / Xiaohongshu Service failures could be reported as login failures HTTP 503 and malformed-response tests
Reddit Loading the login module could replace the rich whoami command Import-order regression test; existing output preserved
Production dependencies undici 7.29.0 was affected by published advisories Upgrade to 7.29.1; npm audit --omit=dev reports zero vulnerabilities

Auth result contract

  • A full probe must return a verified account or throw a typed error. AUTH_REQUIRED means a positive login-required signal; network failures, unexpected responses and unsupported DOM layouts are command errors.
  • A quick probe is optional and may return unknown. Ctrip, ChatGPT and the three Google adapters no longer infer a valid session from cookie names. Use opencli auth status --site ctrip --full or opencli ctrip whoami for verification.
  • Missing display names or redacted IDs do not invalidate an account established by the authoritative probe.
  • Login polling must preserve the user's login surface and keep infrastructure errors separate from pending authentication.

Reproduction and checks

sh
npm run build
npm test
npx vitest run --project e2e tests/e2e/auth-contract.test.ts
npm run typecheck
npm run check:typed-error-lint
npm run check:silent-column-drop
npm audit --omit=dev

The CLI fixture test starts an isolated CDP server on a random port, evaluates the actual adapter JavaScript against fixture responses, and invokes the built CLI in child processes. It checks output, error codes and full/quick status behavior without requiring accounts or modifying the user's daemon.

Live Ctrip and Gemini probes used the existing browser connection with the repository's actual adapter functions. The separate v1.8.8 CLI Browser Bridge extension was disconnected, so live browser checks and CLI transport checks were performed separately. No cookies or tokens are stored in fixtures or this report.

Remaining verification limits

Other adapters still have site-specific cookie/DOM assumptions. In particular, cookie-only identities (1688/JD), cookie preconditions in other API-backed adapters, and DOM absence or challenge pages interpreted as logout require individual live fixtures before changing their contracts. The audit found these as risk patterns, not confirmed current failures on those accounts. Blanket removal or guessing replacement endpoints would not establish correctness.

Several development-tool dependency advisories remain in the Vite/VitePress/Vue toolchain; the production dependency tree is clear. The existing static-lint baselines also remain (they are not evidence of a clean repository).

Entry-file inventory

The following inventory records the reviewed entrypoints, not live-site certification.

  • clis/12306/auth.js
  • clis/1688/auth.js
  • clis/1point3acres/auth.js
  • clis/amazon/auth.js
  • clis/band/auth.js
  • clis/bilibili/auth.js
  • clis/boss/auth.js
  • clis/chaoxing/auth.js
  • clis/chatgpt/auth.js
  • clis/claude/auth.js
  • clis/coupang/auth.js
  • clis/ctrip/auth.js
  • clis/deepseek/auth.js
  • clis/dianping/auth.js
  • clis/douban/auth.js
  • clis/doubao/auth.js
  • clis/douyin/auth.js
  • clis/dribbble/auth.js
  • clis/facebook/auth.js
  • clis/flomo/auth.js
  • clis/gemini/auth.js
  • clis/gitee/auth.js
  • clis/github/auth.js
  • clis/gmail/auth.js
  • clis/grok/auth.js
  • clis/hf/auth.js
  • clis/hupu/auth.js
  • clis/instagram/auth.js
  • clis/jd/auth.js
  • clis/jianyu/auth.js
  • clis/jike/auth.js
  • clis/jimeng/auth.js
  • clis/ke/auth.js
  • clis/kimi/auth.js
  • clis/linkedin/auth.js
  • clis/linkedin-learning/auth.js
  • clis/linux-do/auth.js
  • clis/maimai/auth.js
  • clis/manus/auth.js
  • clis/midjourney/whoami.js
  • clis/notebooklm/auth.js
  • clis/nowcoder/auth.js
  • clis/pixiv/auth.js
  • clis/powerchina/auth.js
  • clis/quark/auth.js
  • clis/qwen/auth.js
  • clis/reddit/auth.js
  • clis/reddit/whoami.js
  • clis/rednote/auth.js
  • clis/reuters/auth.js
  • clis/slock/whoami.js
  • clis/suno/auth.js
  • clis/taobao/auth.js
  • clis/tiktok/auth.js
  • clis/toutiao/auth.js
  • clis/twitter/auth.js
  • clis/upwork/auth.js
  • clis/v2ex/auth.js
  • clis/wechat-channels/auth.js
  • clis/weibo/auth.js
  • clis/weread/auth.js
  • clis/xianyu/auth.js
  • clis/xiaoe/auth.js
  • clis/xiaohongshu/auth.js
  • clis/xiaoyuzhou/auth.js
  • clis/xueqiu/auth.js
  • clis/youtube/auth.js
  • clis/yuanbao/auth.js
  • clis/zhihu/auth.js
  • clis/zsxq/auth.js

Guide Agent Browser Alternative (`docs/guide/agent-browser-alternative.md`)


title: OpenCLI vs agent-browser — Browser Automation and Migration

OpenCLI vs agent-browser

OpenCLI is a general-purpose browser automation CLI and an alternative to agent-browser for AI agent browsing. Use opencli browser to navigate websites, inspect page state, click, fill forms, extract content, and take screenshots. A site does not need a pre-built adapter.

OpenCLI also provides reusable site commands. These extend its browser capabilities; the adapter catalog is not the boundary of what an agent can browse.

Can OpenCLI replace agent-browser?

Yes, for workflows built around the observe → act → observe browser loop. An agent can operate an unfamiliar website directly through OpenCLI, including multi-step navigation and form entry. It does not have to generate an adapter first.

The CLI syntax, element references, session lifecycle, and output formats differ. Migrate the actions in your workflow and verify the result; existing agent-browser scripts are not command-line compatible. If a workflow depends on a specialized flag or runtime feature, check that requirement individually rather than assuming complete feature parity.

Two ways to operate a website

Need OpenCLI interface Site adapter required?
Explore an unfamiliar site or complete a one-off browser task opencli browser <session> <command> No
Navigate, inspect, click, fill, extract, or screenshot opencli browser primitives No
Run a ready-made site command with a structured schema opencli <site> <command> Yes
Reuse a recurring workflow as a command Author a site adapter Only for packaging the workflow

Both browser primitives and adapter commands execute without built-in LLM inference. An AI agent choosing browser actions still has its own model usage. Adapter commands can reduce the number of actions the agent needs to plan.

Start browsing without an adapter

Install OpenCLI and the Browser Bridge extension, then check the connection:

bash
npm install @jackwener/opencli
opencli doctor
npx skills add jackwener/opencli --skill opencli-browser

Run the browser loop with a named session:

bash
opencli browser --session work open https://example.com
opencli browser --session work state
opencli browser --session work extract
opencli browser --session work screenshot /tmp/opencli-example.png
opencli browser --session work close

Reuse work across commands to preserve the session. state returns interactive elements with numeric references. On a page with an interactive element, use a reference from the latest state:

bash
opencli browser --session work click 12
opencli browser --session work state

12 is an illustrative reference, not a fixed element on example.com. Inspect state again after navigation or page changes. close releases the session's tab lease; do not assume it has the same lifecycle semantics as another tool's browser shutdown.

Command migration reference

The agent-browser examples below follow its upstream README. Element references are specific to each tool's current page snapshot.

Task agent-browser OpenCLI
Navigate agent-browser open https://example.com opencli browser --session work open https://example.com
Inspect interactive elements agent-browser snapshot opencli browser --session work state
Click an observed element agent-browser click @e2 opencli browser --session work click 2
Fill an input agent-browser fill "#email" "[email protected]" opencli browser --session work fill "#email" "[email protected]"
Press a key agent-browser press Enter opencli browser --session work keys Enter
Read page content agent-browser get text body opencli browser --session work extract
Take a screenshot agent-browser screenshot page.png opencli browser --session work screenshot page.png
Run page JavaScript agent-browser eval "document.title" opencli browser --session work eval "document.title"
End the session agent-browser close opencli browser --session work close

Use opencli browser --help and opencli browser work <command> --help for current options. Do not copy @e2 into OpenCLI or assume reference 2 identifies the same element in both tools.

When are adapters useful?

If an agent needs a site's trending posts every day, opencli bilibili hot -f json can replace repeated browser exploration with one structured command. If the site has no adapter, the agent can still browse it immediately. Add an adapter when the workflow benefits from a reusable interface.

See Getting Started, the broader tool comparison, and Extending OpenCLI.


Guide Browser Bridge (`docs/guide/browser-bridge.md`)

Browser Bridge Setup

⚠️ Important: Browser commands reuse your Chrome login session. You must be logged into the target website in Chrome before running commands.

OpenCLI connects to your browser through a lightweight Browser Bridge Chrome Extension + micro-daemon (zero config, auto-start).

Extension Installation

Install OpenCLI from the Chrome Web Store.

Method 2: Download Pre-built Release

  1. Go to the GitHub Releases page and download the latest opencli-extension-v{version}.zip.
  2. Unzip the file and open chrome://extensions, enable Developer mode (top-right toggle).
  3. Click Load unpacked and select the unzipped folder.

Method 3: Load Unpacked Source (For Developers)

  1. Open chrome://extensions and enable Developer mode.
  2. Click Load unpacked and select the extension/ directory from the repository.

Verification

That's it! The daemon auto-starts when you run any browser command. No tokens, no manual configuration.

bash
opencli doctor            # Check extension + daemon connectivity

Tab Targeting

Browser commands require an explicit --session <name> option. Use the same session name for a multi-step flow, and use different names to isolate parallel work.

bash
opencli browser --session baidu open https://www.baidu.com/
opencli browser --session baidu tab list
opencli browser --session baidu tab new https://www.baidu.com/
opencli browser --session baidu eval --tab <targetId> 'document.title'
opencli browser --session baidu tab select <targetId>
opencli browser --session baidu get title
opencli browser --session baidu tab close <targetId>

Key rules:

  • opencli browser --session <session> open and opencli browser --session <session> tab new [url] return a targetId.
  • opencli browser --session <session> tab list prints the targetId values of tabs that already exist.
  • --tab <targetId> routes a single browser command to that specific tab.
  • tab new creates a new tab but does not change the default browser target.
  • tab select <targetId> makes that tab the default target for later untargeted opencli browser ... commands.
  • tab close <targetId> removes the tab; if it was the current default target, the stored default is cleared.

Session Lifecycle

Use a stable session name when you want multiple opencli browser commands to keep operating on the same page:

bash
opencli browser --session my-session open https://example.com
opencli browser --session my-session state
opencli browser --session my-session extract "main"

Owned browser sessions use an interactive tab lease with a 10-minute idle timeout. Release it explicitly when done:

bash
opencli browser --session my-session close

Use opencli browser --session <session> bind when you want to attach OpenCLI to a Chrome tab you already opened manually. Bound sessions do not have the owned-session idle close timer; they stay attached until unbind, tab close, window close, or daemon restart. For owned sessions, use --window foreground to watch OpenCLI work in a visible automation window, or --window background to keep that automation window out of the way.

The OpenCLI Browser and OpenCLI Adapter tab groups are extension-managed automation containers; avoid putting your own long-lived tabs in them or renaming them.

Native Chrome management

Use Chrome APIs to manage ordinary browser tabs, groups and windows:

bash
opencli browser chrome describe
opencli browser chrome describe tabs.group
opencli browser chrome call tabs.query '[{}]'
opencli browser chrome call tabs.group '[{"tabIds":[123,456]}]'
opencli browser chrome call tabGroups.update '[789,{"title":"Research","color":"blue"}]'
opencli browser chrome call tabs.ungroup '[[123,456]]'

Replace the example IDs with numeric Chrome IDs returned by the native queries, not the targetId strings used by page commands. Arguments are a JSON array of positional arguments. The success envelope contains native Chrome values in data; methods returning nothing return null.

describe lists the supported browser-management methods. For a method it returns its signature, availability, current permissions and official reference URL. These commands use the selected --profile and do not attach a page. Native-created tabs and windows persist after the CLI exits. Mutations affecting an active OpenCLI session or its managed group return managed_resource_conflict.

API discovery

bash
opencli browser --session research open https://example.com
opencli browser --session research network --static
# Follow a returned request key to inspect its captured response:
opencli browser --session research network --detail '<key>'

network summarizes captured API requests; --static also parses loaded JavaScript with an AST scanner. Each candidate includes method, URL, parameter names and evidence (network, static, or network+static). Script locations and request keys link back to the evidence. Unresolved expressions appear as EXPR; they are not guessed into observed routes.

Static candidates are not executed. The agent decides which endpoints to investigate, writes a normal JS adapter, and runs it with the existing CLI. There is no draft store or activation workflow.

Limits are explicit: up to 20 document scripts, 2 MiB per script, a 2 MiB combined inline-script budget, and a 10-second timeout per external script. External scripts are fetched through Node without browser credentials. Imports, workers, alias/data-flow resolution and scripts not present in the current document are not crawled. The report includes parse/fetch errors, omitted scripts and analysisComplete for this bounded scan; it does not claim complete site coverage. A drained network buffer falls back to the session cache, with networkSource and networkSavedAt identifying cached evidence.

Real-browser regression test

After building the CLI and extension, use Chrome for Testing or Chromium:

bash
OPENCLI_P0_E2E=1 CHROME_PATH=/path/to/chrome npx vitest run tests/e2e/browser-p0-chrome.test.ts

The test uses a temporary Chrome profile and an installation copy with a separate port. It covers native group operations, discovery/cache, and the existing Node/browser JS adapter contracts.

How It Works

text
┌─────────────┐     WebSocket      ┌──────────────┐     Chrome API     ┌─────────┐
│  opencli    │ ◄──────────────► │  micro-daemon │ ◄──────────────► │  Chrome  │
│  (Node.js)  │    localhost:19825  │  (auto-start) │    Extension       │ Browser  │
└─────────────┘                    └──────────────┘                    └─────────┘

The daemon manages the WebSocket connection between your CLI commands and the Chrome extension. The extension executes JavaScript in the context of web pages, with access to the logged-in session.

Daemon Lifecycle

The daemon auto-starts on first browser command and stays alive persistently.

bash
opencli daemon stop      # Graceful shutdown

The daemon is persistent — it stays alive until you explicitly stop it (opencli daemon stop) or uninstall the package.

Running OpenCLI from a remote machine

If you need to run opencli on a remote server (CI runner, agent host) but keep the browser session on your local machine, see Remote Orchestration. It walks through the SSH reverse-tunnel pattern so the daemon never leaves localhost.

Native input and hidden pages

Native click, key, hover, double-click and drag actions require the target page
to report document.visibilityState === 'visible'. If Chrome reports a hidden
page (for example a background tab or a minimized/occluded window), OpenCLI
returns COMMAND_EXEC before dispatching native input. Visibility-check failures
also stop the action. Select the intended tab and restore/uncover its window,
then retry. OpenCLI does not automatically focus the window or replay a blocked
native action through synthetic DOM events. Visibility is a precondition, not a
verification that the application completed the requested action.


Guide Exit Codes (`docs/guide/exit-codes.md`)

Exit Codes

opencli follows Unix sysexits.h conventions so it integrates naturally with shell pipelines and CI scripts.

Code Meaning When
0 Success Command completed normally
1 Generic error Unexpected / unclassified failure
2 Usage error Bad arguments or unknown command
66 Empty result No data returned (EX_NOINPUT)
69 Service unavailable Browser Bridge not connected (EX_UNAVAILABLE)
75 Temporary failure Command timed out — retry (EX_TEMPFAIL)
77 Auth required Not logged in to target site (EX_NOPERM)
78 Config error Missing credentials or bad config (EX_CONFIG)
130 Interrupted Ctrl-C / SIGINT

Example: branch on exit code

bash
opencli spotify status || echo "exit $?"   # 69 if browser not running

opencli twitter timeline 2>/dev/null
[ $? -eq 77 ] && opencli twitter login      # auto-auth if not logged in

Guide Extending Opencli (`docs/guide/extending-opencli.md`)

Extending OpenCLI

OpenCLI has four extension paths. Pick the path based on where you want the source code to live and how you want commands to be shared.

Goal Use Source location Command surface
Build a personal website command in your own Git repo Local plugin Your project directory, symlinked into ~/.opencli/plugins/ opencli <command>
Quickly draft a private adapter on this machine User adapter ~/.opencli/clis/<site>/<command>.js opencli <site> <command>
Edit an official adapter locally Adapter override ~/.opencli/clis/<site>/ opencli <site> <command>
Publish or install third-party commands Plugin Git repo, installed into ~/.opencli/plugins/ opencli <command>

Personal commands in your own Git repo

Use a local plugin when you want the code to stay in a normal project directory and be managed by Git.

bash
opencli plugin create my-cnn
cd my-cnn
git init
opencli plugin install file://$(pwd)
opencli my-cnn hello

plugin install file://... creates a symlink under ~/.opencli/plugins/. Your source files stay in your project directory, so edits and commits happen there.

This is the recommended path for custom commands you own long-term.

Private adapters in `~/.opencli/clis`

Use a user adapter when you want the fastest local adapter loop and do not need a separate project directory.

bash
opencli adapter init cnn/top
# edit ~/.opencli/clis/cnn/top.js
opencli adapter test cnn/top
opencli cnn top

User adapters are loaded from:

text
~/.opencli/clis/<site>/<command>.js

This path is convenient for quick local automation. For code you want to version, review, or share, prefer a plugin.

If the command takes required positional args and no fixture exists yet, seed the first verify run explicitly:

bash
opencli adapter test instagram/collection-create --write-fixture --args opencli-verify
opencli adapter test example/detail --write-fixture --args '["https://example.com/item/1", "--limit", 3]'

--args is only used when the fixture has no args. Once the fixture is written, opencli adapter test reads args from ~/.opencli/sites/<site>/verify/<command>.json.

browser verify also enforces row shape before fixture checks: each row should
stay compact (at most 12 top-level keys), avoid nesting deeper than one level,
and keep id-shaped fields such as id / user_id at the top level.

Local overrides for official adapters

Use adapter eject when you want to customize an existing official adapter.

bash
opencli adapter eject twitter
# edit ~/.opencli/clis/twitter/*.js
opencli adapter reset twitter

Files in ~/.opencli/clis/<site>/<command>.js override packaged adapters with the same site/command on this machine. opencli adapter test <site>/<command> also runs the local override, so a passing local verify does not prove that the packaged adapter was changed.

The packaged cli-manifest.json only describes bundled adapters. User adapters are discovered at runtime and do not need manifest entries.

After copying a local fix into the repository for a PR, remove the local copy or run opencli adapter reset <site> after merge. Otherwise the local file keeps shadowing future package updates. opencli doctor warns when it detects this shadowing.

Plugins for sharing commands

Plugins are third-party command packages. They can be installed from GitHub, any git-cloneable URL, or a local directory.

bash
opencli plugin install github:user/opencli-plugin-my-tool
opencli plugin install https://github.com/user/opencli-plugin-my-tool
opencli plugin install file:///absolute/path/to/plugin
opencli plugin list
opencli plugin update --all
opencli plugin uninstall my-tool

Each plugin directory is scanned for .ts and .js command files. TypeScript plugins are transpiled during install.

See Plugins for manifest fields, TypeScript examples, update behavior, and monorepo publishing.

Multiple custom sites in one repo

For a Git-hosted plugin collection, declare sub-plugins in opencli-plugin.json and install from GitHub:

json
{
  "plugins": {
    "cnn": { "path": "packages/cnn" },
    "reuters": { "path": "packages/reuters" }
  }
}
bash
opencli plugin install github:user/opencli-plugins
opencli plugin install github:user/opencli-plugins/cnn

For local development, install each sub-plugin directory directly:

bash
opencli plugin install file:///absolute/path/opencli-plugins/packages/cnn
opencli plugin install file:///absolute/path/opencli-plugins/packages/reuters

Local file:// installs expect the target directory itself to be a valid plugin with command files. For a monorepo root, push it to GitHub and install it with the GitHub monorepo flow.


Guide Installation (`docs/guide/installation.md`)

Installation

Requirements

  • Node.js: >= 21.0.0, or Bun >= 1.0
  • Chrome running and logged into the target site (for browser commands)
bash
npm install @jackwener/opencli

Install the Browser Bridge Extension

For browser commands, install OpenCLI from the Chrome Web Store (recommended). See Browser Bridge setup for manual installation and verification.

Install from Source

bash
git clone [email protected]:jackwener/opencli.git
cd opencli
npm install
npm run build
npm link      # Link binary globally
opencli list  # Now you can use it anywhere!

Update

bash
npm install @jackwener/opencli@latest

# If you use the packaged OpenCLI skills, refresh them too
npx skills add jackwener/opencli

Or refresh only the skills you actually use:

bash
npx skills add jackwener/opencli --skill opencli-adapter-author
npx skills add jackwener/opencli --skill opencli-autofix
npx skills add jackwener/opencli --skill opencli-browser
npx skills add jackwener/opencli --skill opencli-usage
npx skills add jackwener/opencli --skill smart-search

Verify Installation

bash
opencli --version   # Check version
opencli list        # List all commands
opencli doctor      # Diagnose connectivity

Guide Plugins (`docs/guide/plugins.md`)

Plugins

OpenCLI supports community-contributed plugins. Install third-party adapters from GitHub, and they're automatically discovered alongside built-in commands.

Quick Start

bash
# Install a plugin
opencli plugin install github:ByteYue/opencli-plugin-github-trending

# List installed plugins
opencli plugin list

# Update one plugin
opencli plugin update github-trending

# Update all installed plugins
opencli plugin update --all

# Use the plugin (it's just a regular command)
opencli github-trending repos --limit 10

# Remove a plugin
opencli plugin uninstall github-trending

How Plugins Work

Plugins live in ~/.opencli/plugins/<name>/. Each subdirectory is scanned at startup for .ts or .js command files — the same formats used by built-in adapters.

Supported Source Formats

bash
# GitHub shorthand
opencli plugin install github:user/repo
opencli plugin install github:user/repo/subplugin   # install specific sub-plugin from monorepo
opencli plugin install https://github.com/user/repo

# Any git-cloneable URL
opencli plugin install https://gitlab.example.com/team/repo.git
opencli plugin install ssh://[email protected]/team/repo.git
opencli plugin install [email protected]:team/repo.git

# Local plugin (for development)
opencli plugin install file:///path/to/plugin
opencli plugin install /path/to/plugin

The repo name prefix opencli-plugin- is automatically stripped for the local directory name. For example, opencli-plugin-hot-digest becomes hot-digest.

Plugin Manifest (`opencli-plugin.json`)

Plugins can include an opencli-plugin.json manifest file at the repo root to declare metadata:

json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "opencli": ">=1.0.0",
  "description": "My awesome plugin"
}
Field Description
name Plugin name (overrides repo-derived name)
version Semantic version
opencli Required opencli version range (e.g. >=1.0.0, ^1.2.0)
description Human-readable description
plugins Monorepo sub-plugin declarations (see below)

The manifest is optional — plugins without one continue to work exactly as before.

Monorepo Plugins

A single repository can contain multiple plugins by declaring a plugins field in opencli-plugin.json:

json
{
  "version": "1.0.0",
  "opencli": ">=1.0.0",
  "description": "My plugin collection",
  "plugins": {
    "polymarket": {
      "path": "packages/polymarket",
      "description": "Prediction market analysis",
      "version": "1.2.0"
    },
    "defi": {
      "path": "packages/defi",
      "description": "DeFi protocol data",
      "version": "0.8.0",
      "opencli": ">=1.2.0"
    },
    "experimental": {
      "path": "packages/experimental",
      "disabled": true
    }
  }
}

Installing

bash
# Install ALL enabled sub-plugins from a monorepo
opencli plugin install github:user/opencli-plugins

# Install a SPECIFIC sub-plugin
opencli plugin install github:user/opencli-plugins/polymarket

How It Works

  • The monorepo is cloned once to ~/.opencli/monorepos/<repo>/
  • Each sub-plugin gets a symlink in ~/.opencli/plugins/<name>/ pointing to its subdirectory
  • Command discovery works transparently — symlinks are scanned just like regular directories
  • Disabled sub-plugins (with "disabled": true) are skipped during install
  • Sub-plugins can specify their own opencli compatibility range

Updating

Updating any sub-plugin from a monorepo pulls the entire repo and refreshes all sub-plugins:

bash
opencli plugin update polymarket   # updates the monorepo, refreshes all

Uninstalling

bash
opencli plugin uninstall polymarket   # removes just this sub-plugin's symlink

When the last sub-plugin from a monorepo is uninstalled, the monorepo clone is automatically cleaned up.

Version Tracking

OpenCLI records installed plugin versions in ~/.opencli/plugins.lock.json. Each entry stores the plugin source, current git commit hash, install time, and last update time. opencli plugin list shows the short commit hash when version metadata is available.

Creating a Plugin

Creating a TypeScript Plugin

text
my-plugin/
├── package.json
├── my-command.ts
└── README.md

package.json:

json
{
  "name": "opencli-plugin-my-plugin",
  "version": "0.1.0",
  "type": "module",
  "peerDependencies": {
    "@jackwener/opencli": ">=1.0.0"
  }
}

my-command.ts:

typescript
import { cli, Strategy } from '@jackwener/opencli/registry';

cli({
  site: 'my-plugin',
  name: 'my-command',
  description: 'My custom command',
  access: 'read', // 'read' | 'write'
  example: 'opencli my-plugin my-command -f yaml',
  strategy: Strategy.PUBLIC,
  browser: false,
  args: [
    { name: 'limit', type: 'int', default: 10, help: 'Number of items' },
  ],
  columns: ['title', 'score'],
  func: async (kwargs) => {
    const res = await fetch('https://api.example.com/data');
    const data = await res.json();
    return data.items.slice(0, kwargs.limit).map((item: any, i: number) => ({
      title: item.title,
      score: item.score,
    }));
  },
});

TS Plugin Install Lifecycle

When you run opencli plugin install, TS plugins are automatically set up:

  1. Clone — git clone --depth 1 from GitHub
  2. npm install — Resolves regular dependencies
  3. Host symlink — Links the running @jackwener/opencli into the plugin's node_modules/ so import from '@jackwener/opencli/registry' always resolves against the host
  4. Transpile — Compiles .ts → .js via esbuild (production node cannot load .ts directly)

On startup, if both my-command.ts and my-command.js exist, the .js version is loaded to avoid duplicate registration.

Example Plugins

Repo Type Description
opencli-plugin-albato JS Albato automation workflow management: scenario inspection, start/pause, failure diagnosis, and retry
opencli-plugin-amap JS AutoNavi / 高德地图 spot & route extraction, coordinate decoders (GCJ-02 & WGS-84), and SSR search
opencli-plugin-github-trending TS GitHub Trending repositories
opencli-plugin-goofish JS Goofish / 闲鱼 buyer orders, favorites, IM chat, profile, item search, and fulfillment stats
opencli-plugin-hot-digest TS Multi-platform trending aggregator (zhihu, weibo, bilibili, v2ex, stackoverflow, reddit, linux-do)
opencli-plugin-juejin TS 稀土掘金 (Juejin) hot articles, categories, and article feed
opencli-plugin-rubysec TS RubySec advisory archive and advisory article reader
opencli-plugin-taobao JS Taobao buyer chat history, order history, bought shops, favorites, and keyword-based chat summaries
opencli-plugin-x-article-publisher JS Publish Markdown with local images as X long-form Articles via OpenCLI and xPoster

Community adapter bundles

Albato, Goofish and Taobao currently keep their command files under clis/<site> without a monorepo manifest. Installing the repository root with github:vecyang1/opencli-plugin-<site> fails structure validation. Clone the repository and install its command directory instead; keep the clone because local installs link to it:

bash
git clone https://github.com/vecyang1/opencli-plugin-taobao.git
opencli plugin install ./opencli-plugin-taobao/clis/taobao

For Albato or Goofish, substitute albato or goofish in both paths. Those two repositories require Node.js 22.5 or later. Follow each repository's README for its additional tools and setup. These are community-maintained adapters; the listing describes their commands, not a guarantee of historical-data completeness.

Troubleshooting

Command not found after install

Restart opencli (or open a new terminal) — plugins are discovered at startup.

TS plugin import errors

If you see Cannot find module '@jackwener/opencli/registry', the host symlink may be broken. Reinstall the plugin:

bash
opencli plugin uninstall my-plugin
opencli plugin install github:user/opencli-plugin-my-plugin

Guide Remote Orchestration (`docs/guide/remote-orchestration.md`)

Remote Orchestration

Run an OpenCLI command from a remote machine (a CI runner, an agent server, a sandbox) while the browser session stays on your local laptop. The remote command sees localhost:19825 like usual; behind the scenes, traffic is tunneled back to the daemon and Chrome on your machine.

When you need this

  • An autonomous agent (OpenClaw, a CI job, a server-side script) needs to drive a logged-in browser session, but only your local Chrome has the cookies.
  • Target sites do IP-based throttling or risk control — you want web traffic to leave from your home network, not from the agent's data center.
  • The remote machine has no display and no Chrome installed.

What not to do (and why)

The first instinct is "let the extension connect to a remote daemon" — type a public host into the popup, expose port 19825 with frp, done. Don't. The daemon's WebSocket protocol has no built-in authentication. Anything that can reach the port can:

  • Read cookies for every site you're logged into
  • Execute arbitrary JavaScript in any of your tabs
  • Take screenshots, send arbitrary HTTP requests, dump page content

Treat the daemon port the way you'd treat your unlocked desktop: never put it on a network you don't fully trust. Native "extension talks to remote daemon" support was proposed in #636 and deferred until daemon authentication exists.

The pattern: reverse-tunnel a localhost daemon

Keep Chrome, the extension, and the daemon all on your local machine. Use a reverse port forward so the remote process can reach your daemon by connecting to its own localhost:19825. The daemon itself never leaves localhost.

text
┌─ Local ─────────────────────────────────┐    ┌─ Remote ──────────┐
│  Chrome ↔ Extension ↔ Daemon (127.0.0.1) │ ←┐ │  opencli-cli      │
└──────────────────────────────────────────┘  │ │  (talks to        │
                                              │ │   localhost:19825)│
                       reverse tunnel ────────┘ └───────────────────┘
                       (SSH -R / frpc / VPN)

The remote opencli process needs no flags, no env vars, no extension changes — it connects to its own loopback, which the tunnel forwards to your laptop.

From your local machine, SSH to the remote with -R to expose your local daemon to the remote's loopback:

bash
ssh -R 19825:127.0.0.1:19825 user@remote-server

While that session is open, anything on the remote connecting to localhost:19825 is forwarded back to your local daemon. The remote-side workflow is unchanged:

bash
# On the remote server
opencli twitter feed
opencli browser --session research open https://example.com

::: tip
Use 127.0.0.1 (not localhost) on the -R clause to avoid IPv6 resolution stalls.
:::

For long-lived agent runs, use autossh so the tunnel reconnects automatically:

bash
autossh -M 0 -N -R 19825:127.0.0.1:19825 user@remote-server

Or as a systemd unit / launchd plist on the local side.

Why this is safe

  • The daemon stays bound to 127.0.0.1 on your machine.
  • The tunnel rides on SSH's authenticated transport — no new auth surface.
  • If the SSH session drops, the tunnel drops; the remote opencli simply fails to connect rather than reaching some stale endpoint.

Option B — frp reverse TCP proxy

If SSH from your local machine to the remote isn't an option (NAT, firewalls), use frp to expose the local daemon through a public relay. This is more complex than SSH and has more failure modes — prefer Option A unless you have a hard reason not to.

  1. Run frps on a public relay you control.

  2. Run frpc on your local machine, exposing daemon port 19825:

    toml
    # ~/frpc.toml on your local machine
    serverAddr = "<public-relay-ip>"
    serverPort = 7000
    auth.method = "token"
    auth.token  = "<long-random-token>"
    
    [[proxies]]
    name = "opencli-daemon"
    type = "tcp"
    localIP = "127.0.0.1"
    localPort = 19825
    remotePort = 19825
  3. On the remote server, run a second frpc that maps the relay's exposed port back to the remote's localhost:19825 (a stcp visitor or a plain tcp client+visitor pair). This way opencli on the remote keeps talking to its own loopback.

::: warning

  • Always set a strong auth.token on frps and frpc. Without it, anyone who learns the relay address has full control of your browser.
  • Bind the relay's exposed port to a private interface or restrict it with iptables / security groups. A daemon port on the public internet is the same risk as the rejected #636 design.
  • If you find yourself debugging frp auth, revisit Option A — it's cheaper and safer.
    :::

Verification

After setting up the tunnel, confirm the remote sees the daemon:

bash
# On the remote server
curl -sf http://127.0.0.1:19825/ping && echo "daemon reachable"
opencli doctor

opencli doctor from the remote should report the same extension version your local Chrome is running.

Caveats

  • Local Chrome must be running for the duration of the remote command. Closing Chrome closes the extension's WebSocket; remote opencli calls will fail with a "no daemon" error until Chrome is reopened.
  • Tunnel latency adds to every call. Each browser command crosses the tunnel twice; expect 50–200ms overhead per call on a typical SSH link, more on transcontinental links.
  • One tunnel per local daemon. If you start multiple SSH sessions all forwarding 19825, only the first wins; the rest log a "remote port already in use" warning.

Guide Troubleshooting (`docs/guide/troubleshooting.md`)

Troubleshooting

Common Issues

"Extension not connected"

  • Ensure the opencli Browser Bridge extension is installed and enabled in chrome://extensions.
  • Run opencli doctor to diagnose connectivity.

Empty data or 'Unauthorized' error

  • Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page.
  • Some sites have geographic restrictions (e.g., Bilibili, Zhihu from outside China).

Browser command opens the page but still cannot read context

  • A healthy Browser Bridge connection does not guarantee that the current page target exposes the data your adapter expects.
  • Some browser adapters are sensitive to the active host or page context.
  • Example: opencli 1688 item may fail with did not expose product context if the target is too broad.
  • Retry on a real item page, refresh the page in Chrome, and if needed narrow the target, for example:
bash
OPENCLI_CDP_TARGET=detail.1688.com opencli 1688 item 841141931191 -f json

Node API errors

  • Make sure you are using Node.js >= 20. Run node --version to verify.

Daemon issues

bash
# View extension logs
curl localhost:19825/logs

# Stop the daemon
opencli daemon stop

# Full diagnostics
opencli doctor

The daemon is persistent and stays alive until explicitly stopped (opencli daemon stop) or the package is uninstalled.

When the CLI detects a stale daemon (version mismatch after npm install @jackwener/opencli@latest), it first asks the daemon to shut down via /shutdown, then falls back to SIGKILL if the daemon does not release the port within 3 seconds. Manual opencli daemon stop is only needed if SIGKILL itself is rejected (cross-user owner / cross-machine PID file).

Build errors

bash
# Clean rebuild
rm -rf dist/
npm run build

# Type check
npx tsc --noEmit

Getting Help

  • GitHub Issues — Bug reports and feature requests
  • Run opencli doctor for comprehensive diagnostics

Zh Comparison (`docs/zh/comparison.md`)


title: OpenCLI browser automation 对比

OpenCLI browser automation 对比

OpenCLI 支持 general-purpose browser automation,可以作为 agent-browser 的替代工具。 没有预置 adapter 的网站,也能通过 opencli browser 直接导航、检查页面、点击、填表、提取和截图。

如果你正在迁移现有 workflow,请先看 OpenCLI vs agent-browser 与命令迁移。更多工具的对比见 English comparison。

按任务选择使用方式

任务 OpenCLI 的使用方式
探索陌生网站、完成多步 browser workflow 使用 opencli browser <session> <command>,无需 adapter
让 AI Agent 操作已登录网页 安装 opencli-browser skill,通过 Browser Bridge 复用 Chrome 登录态
定时获取站点内容、重复运行固定流程 调用现成 adapter commands,获取结构化输出
把探索过的流程变成可复用命令 编写 site adapter

OpenCLI 和 agent-browser 都能提供 Agent 使用的 browser primitives。OpenCLI 还提供现成站点命令,将重复任务封装为一次结构化调用。两者的命令语法、element references、session lifecycle 和输出格式不同,迁移时需要逐项验证。

实际限制

  • 现成站点命令的覆盖范围取决于 adapters,但 browser automation 不受 adapter 列表限制。
  • 网站 DOM 或 API 变化时,adapter 可能需要维护。
  • 通用 browser workflow 仍需要 script 或 AI Agent 决定操作步骤、观察页面状态并处理错误。
  • OpenCLI 命令本身不依赖 LLM inference;负责规划操作的 AI Agent 仍有自身的 model costs。

开始使用


Adapters Browser 12306 (`docs/adapters/browser/12306.md`)

12306 (中国铁路 China Railway)

Mode: 🌐 Public (stations, trains, train, price) · 🖥️ Browser + Cookie (me, passengers, orders)
Domain: kyfw.12306.cn

Read-only adapter against the 12306 (China Railway) site. Anonymous queries
hit the public ticket-search endpoints; authenticated queries reuse the
user's existing browser login state. No CAPTCHA / slider / SMS / anti-abuse
bypass is performed, no credentials are stored, and no booking / payment /
ticket-sniping is implemented.

Commands

Command Mode Description
opencli 12306 stations Public Search the station bundle by Chinese name, telecode, full pinyin, or short alias
opencli 12306 trains Public Trains between two stations on a given date with per-seat-class availability
opencli 12306 train Public Stop list (arrive / depart / stopover time) for one train segment
opencli 12306 price Public Ticket prices by seat class for one train segment + date
opencli 12306 me Browser (cookie) Logged-in account summary (sensitive fields masked by default)
opencli 12306 passengers Browser (cookie) Saved passenger list (sensitive fields masked by default)
opencli 12306 orders Browser (cookie) In-progress orders (not yet ridden / refunded / completed)

Usage Examples

bash
# Search stations
opencli 12306 stations 上海 --limit 5
opencli 12306 stations beijing
opencli 12306 stations AOH        # by telecode

# List trains between two stations
opencli 12306 trains 北京 上海 --date 2026-05-22 --limit 20
opencli 12306 trains BJP AOH --date 2026-05-22

# Show stops for one train
opencli 12306 train 24000000G10L --from 北京南 --to 上海虹桥 --date 2026-05-22

# Ticket prices by seat class
opencli 12306 price 24000000G10L --from 北京南 --to 上海虹桥 --date 2026-05-22

# Authenticated commands (require login on kyfw.12306.cn first)
opencli 12306 me
opencli 12306 me --include-sensitive
opencli 12306 passengers --limit 10
opencli 12306 orders
opencli 12306 orders --include-sensitive

# JSON output
opencli 12306 trains 北京 上海 --date 2026-05-22 -f json

Station Resolution

The <from> and <to> arguments on trains, train, and price accept
any of the following forms; lookup is anchored against the public
station_name.js bundle 12306 ships:

  • Chinese name (上海虹桥)
  • Telecode (AOH, 3-4 uppercase letters, the wire format used in
    12306's own API)
  • Full pinyin (shanghaihongqiao, case-insensitive)
  • Short alias / abbr (shhq)

Anything else raises ArgumentError with a hint pointing to the accepted
forms. Match order is exact-name first, so 北京 does not accidentally
resolve to 北京北 by substring.

Columns

`stations`

Column Notes
name Chinese station name
code 3-4 letter telecode (use in API URLs)
pinyin Full pinyin
abbr Short alias
city Chinese city name

`trains`

Column Notes
code Public train code (G1, D301, ...)
from_station / to_station Chinese station names
from_code / to_code Telecodes
start_time / arrive_time / duration HH:MM format
available true when 12306 shows 预订 status
business_seat / first_seat / second_seat Availability for 商务座 / 一等座 / 二等座 (有 / 无 / number string)
soft_sleeper / hard_sleeper / hard_seat / no_seat Same shape for 软卧 / 硬卧 / 硬座 / 无座
train_no Internal id used by train and price commands

`train`

Column Notes
station_no 1-based stop index within this train's route
station_name Chinese name
arrive_time / start_time / stopover_time Empty string for the origin (no arrive) and destination (no stopover)

`price`

Column Notes
seat_code 12306 seat letter (A9 商务座, M 一等座, O 二等座, WZ 无座, A1 硬座, A3 硬卧, A4 软卧, F 动卧, P 特等座)
seat_name Localised Chinese label
price Decimal string (CNY)
currency Always CNY

Rows are sorted by descending price. 12306 double-encodes some prices as
bare numeric keys (e.g. "9": "21580" mirroring "A9": "¥2158.0" in
no-decimal form); the bare-numeric duplicates are filtered out so each
seat class appears exactly once.

`me`

Column Notes
username 12306 login name (loginUserDTO.user_name)
real_name Masked by default; --include-sensitive to opt in
email Local-part masked by default
mobile 12306 already masks server-side (xxx****xxxx) and the adapter preserves that
birth_date Year only by default
sex, country, user_type 男 / 女, ISO-3, e.g. 成人
member, active Boolean flags

`passengers`

Column Notes
name Masked by default to <surname>*<...>
sex 男 / 女
born_year Year only by default
id_type e.g. 居民身份证
id_no 12306 masks server-side; the adapter never decodes
mobile Same as me
passenger_type 成人, 儿童, 学生, 残军
country ISO-3

`orders`

Column Notes
order_id 12306 sequence_no
order_date Order placement timestamp
train_code Public train code
from_station / to_station Chinese names
departure Departure timestamp
passengers Comma-separated passenger names from the order; masked by default, --include-sensitive to opt in
status 12306 ticket / order status name
amount Total price (CNY)

Login

The three authenticated commands (me, passengers, orders) require a
logged-in 12306 session in the same Chrome instance that OpenCLI's bridge
talks to. Sign in once at https://kyfw.12306.cn; the adapter then reads
the resulting tk / JSESSIONID cookies on subsequent runs.

Login is detected via document.cookie rather than
page.getCookies({url}), because 12306 sets the auth cookies with
Path=/otn and CDP Network.getCookies filters by URL path - a bare
https://kyfw.12306.cn URL filter would otherwise hide them. If tk or
JSESSIONID is missing, the adapter raises AuthRequiredError.

Privacy

Authenticated commands mask sensitive fields by default:

  • Email: local part is <first>***<last>@<domain>
  • Mobile: 12306's own mask is preserved (the adapter never tries to
    decode it)
  • Real name / passenger/order passenger name: Chinese names are masked to
    <first-char>*<last-char> (or <first-char>* for two-character names)
  • Birth date: year only

Pass --include-sensitive on me, passengers, or orders to opt back into
the unmasked fields the user is entitled to see on their own account. The
12306-side ID number mask is server-side and is never decoded.

Limit Validation

All --limit arguments use a strict validator that throws ArgumentError
on non-integer / out-of-range input rather than silently clamping. The
caps are:

  • stations: 1-50 (default 20)
  • trains: 1-100 (default 50)
  • passengers: 1-50 (default 20)

Endpoint Notes

  • /otn/leftTicket/init is hit first to mint anonymous session cookies
    (JSESSIONID, route, BIGipServerotn).
  • 12306 rotates the train-query endpoint name (queryO, queryZ,
    queryA, queryG, ...) every few weeks. The adapter walks a list of
    known names; when the server responds with
    {c_url: "leftTicket/queryX"} it captures the suggested name and
    retries.
  • The |-separated train wire record includes a base64 booking-handshake
    secret token at position 0. This adapter parses but does not surface
    that field (a unit test asserts it cannot leak via the row shape).

Non-Goals

  • No ticket sniping
  • No order submission / payment
  • No CAPTCHA / slider / SMS / anti-abuse bypass
  • No password storage
  • No order history beyond the in-progress slice (left as a follow-up)

Adapters Browser 1688 (`docs/adapters/browser/1688.md`)

1688

Mode: 🔐 Browser · Domain: 1688.com

Commands

Command Description
opencli 1688 search "<query>" --limit <n> Search public product candidates with price, MOQ, seller link, and visible badges
opencli 1688 item Read a public product detail page with price tiers, MOQ, delivery text, and seller basics
opencli 1688 assets Extract product media assets visible on the item page (main images, SKU images, detail images, videos)
opencli 1688 download Batch download product media assets visible on the item page
opencli 1688 store Read a public supplier/store page with company info, years on platform, categories, and visible service signals

Usage Examples

bash
# Search products
opencli 1688 search "桌面置物架 宿舍 收纳" --limit 10

# JSON output
opencli 1688 search "桌面置物架 宿舍 收纳" --limit 10 -f json

# Read an item by offer id
opencli 1688 item 841141931191 -f json

# Read an item by URL
opencli 1688 item https://detail.1688.com/offer/841141931191.html -f json

# List downloadable media assets
opencli 1688 assets 841141931191 -f json

# Batch download page-visible images/videos
opencli 1688 download 841141931191 --output ./1688-downloads

# Read a supplier store
opencli 1688 store https://shop52908bfw19166.1688.com/ -f json

# Read a supplier by member id
opencli 1688 store b2b-22154705262941f196 -f json

Prerequisites

Notes

  • This adapter only returns or downloads fields and media visible on public pages. It does not send inquiries, place orders, or access seller back office data.
  • assets / download currently prioritize page state and rendered DOM. They may not perfectly match every file exposed by the official 1688 extension workflow.
  • Prefer stable identifiers such as offer_id, member_id, and shop_id for follow-up workflows.
  • search --limit defaults to 20 and is capped at 100.
  • search deduplicates with key priority: offer_id first, then canonical item_url.
  • item can be more sensitive to the active browser target than search or store.

Troubleshooting

  • If opencli 1688 item reports did not expose product context, first make sure the open page is a real detail.1688.com item page.
  • If the browser target is too broad, retry with OPENCLI_CDP_TARGET=detail.1688.com.
  • If you hit a slider or verification page, refresh the real page in Chrome and retry.

Adapters Browser 1point3acres (`docs/adapters/browser/1point3acres.md`)

1point3acres (一亩三分地)

Browse and search 1point3acres — a Discuz!-based BBS popular for North American job, immigration, and grad-school discussions. Public listings work without auth; search and notifications require an active browser session.

Mode: 🌐 Public + 🔐 Cookie · Domain: www.1point3acres.com

Commands

Command Description Auth
opencli 1point3acres hot Today's hot threads (by heat) Public
opencli 1point3acres latest Newest threads (by post time, desc) Public
opencli 1point3acres digest Editor-picked / featured threads Public
opencli 1point3acres forums List all forums (fid + name) Public
opencli 1point3acres forum <fid> List threads in a specific forum Public
opencli 1point3acres thread <tid> Thread detail + replies Public
opencli 1point3acres user <who> User profile (group / points / 大米 / posts) Public
opencli 1point3acres search <query> Full-text search Cookie
opencli 1point3acres notifications Site notifications (replies / mentions / reviews) Cookie

Usage Examples

bash
# Today's hot threads
opencli 1point3acres hot --limit 10

# Newest posts in the overseas-job-referral forum (fid=198)
opencli 1point3acres forum 198 --limit 20

# Read a thread (tid comes from any listing's `tid` column)
opencli 1point3acres thread 1158360 --limit 10

# Lookup a user (numeric → uid, otherwise username)
opencli 1point3acres user 12345
opencli 1point3acres user some-username

# Filter the forum list by keyword
opencli 1point3acres forums --filter 面经

# Search the site (requires login)
opencli 1point3acres search "OPT extension" --limit 10

# Notifications (requires login)
opencli 1point3acres notifications --kind mypost --limit 20

Common Forum IDs

145 (海外面经) · 198 (海外职位内推) · 27 (研究生申请) · 28 (博士申请) · 82 (NIW / EB-1A 移民).
Use opencli 1point3acres forums to see the full list.

Output Columns

Command Columns
hot / latest / digest / forum rank, tid, title, forum, author, replies, views, lastReplyTime, url
thread floor, pid, author, postTime, content, url
user uid, username, group, credits, rice, posts, threads, digests, registerTime, lastAccess, profileUrl
forums fid, name, url
search rank, tid, title, forum, author, replies, views, postTime, url
notifications index, from, summary, time, threadUrl

Prerequisites

  • No browser required for public commands (hot / latest / digest / forums / forum / thread / user)
  • For search and notifications:

Notes

  • The site serves GBK-encoded HTML; the adapter decodes to UTF-8 internally
  • tid (thread id) is the canonical handle that pipes a listing row into thread for the full content
  • Public endpoints serve rendered HTML, so heavy bot traffic may hit Discuz challenge / login gates — fall back to a logged-in session if hot / latest start returning empty rows
  • Listing --limit values are validated upfront and rejected with ArgumentError if non-positive or above 50 (the page yields ~50 rows max) — no silent clamp
  • thread --page, thread --limit, thread --contentLimit, and notifications --limit also reject invalid values explicitly instead of silently flooring them

whoami verifies the current-user panel on the Discuz-native /bbs/home.php?mod=space page, without changing the saved forum UI preference. Missing cookies or an explicit login wall report AUTH_REQUIRED; a page without recognizable self identity reports COMMAND_EXEC instead of guessing from other users’ avatars.


Adapters Browser 36kr (`docs/adapters/browser/36kr.md`)

36kr (36氪)

Mode: 🌐 Public / 🔐 Browser · Domain: 36kr.com

Commands

Command Description
opencli 36kr hot 36氪热榜 — trending articles
opencli 36kr news Latest tech/startup news from 36kr
opencli 36kr search <query> Search 36kr articles
opencli 36kr article Read full article content

Usage Examples

bash
# Trending articles
opencli 36kr hot --limit 10

# Hot by type
opencli 36kr hot --type renqi --limit 10
opencli 36kr hot --type zonghe --limit 10

# Latest news
opencli 36kr news --limit 20

# Search articles
opencli 36kr search "AI" --limit 10
opencli 36kr search "OpenAI" --limit 5

# Read full article (by ID or URL)
opencli 36kr article 3000000123456
opencli 36kr article https://36kr.com/p/3000000123456

# JSON output
opencli 36kr hot -f json

Notes

  • news uses the public RSS feed and works without Browser Bridge.
  • hot, search, and article use Browser Bridge and are best run with Chrome open.
  • hot --type accepts catalog, renqi, zonghe, and shoucang.

Prerequisites

  • news: No browser required — uses public RSS feed
  • hot, search, article: Chrome running with Browser Bridge extension installed

Adapters Browser 51job (`docs/adapters/browser/51job.md`)

51job

Mode: 🔐 Browser · Domains: we.51job.com, jobs.51job.com

Commands

Command Description
opencli 51job search <keyword> Keyword search with city / salary / experience / degree / company filters
opencli 51job hot Recommended jobs feed for a city
opencli 51job detail <jobId> Full job detail page by jobId
opencli 51job company <encCoId> Company profile plus active jobs by encrypted company ID

Usage Examples

bash
# Search Beijing Python jobs
opencli 51job search python --area 北京 --limit 5

# Recommended jobs in Shanghai
opencli 51job hot --area 上海 --limit 5

# Detail by jobId from search/hot output
opencli 51job detail 171699769

# Company jobs by encCoId from search output
opencli 51job company MjYxMjgxMA== --limit 3

# JSON output for agent workflows
opencli 51job search Golang --area 杭州 -f json

Notes

  • search and hot run behind Aliyun WAF. The adapter uses a real browser session and browser-context fetch for the JSON API on we.51job.com.
  • detail and company read SSR HTML pages on jobs.51job.com.
  • area accepts a known city name or a 6-digit city code. Unknown non-empty values fail fast.
  • company returns the full companyIntro text. It does not silently truncate content.

Adapters Browser Aibase (`docs/adapters/browser/aibase.md`)

AIbase

Mode: 🌐 Public · Domain: aibase.com

Commands

Command Description
opencli aibase news AIbase daily AI industry news

Usage Examples

bash
# Latest AIbase daily news
opencli aibase news --limit 20

# JSON output
opencli aibase news --limit 10 -f json

Notes

  • Returns rank, title, and stable article url.
  • Invalid --limit values fail fast instead of being silently clamped.

Adapters Browser Amazon (`docs/adapters/browser/amazon.md`)

Amazon

Mode: 🔐 Browser · Domain: amazon.com

Commands

Command Description
opencli amazon bestsellers [] Read Amazon Best Sellers pages for ranked candidate discovery
opencli amazon search "<query>" Read Amazon search results for coarse filtering
opencli amazon product <asin-or-url> Read a product page with title, price, rating, breadcrumbs, and bullets
opencli amazon offer <asin-or-url> Read seller / fulfillment / buy-box facts from the product page
opencli amazon discussion <asin-or-url> Read review summary and sample customer reviews
opencli amazon movers-shakers [] Amazon Movers & Shakers pages for short-term growth signals
opencli amazon new-releases [] Amazon New Releases pages for early momentum discovery

Usage Examples

bash
# Root Best Sellers page
opencli amazon bestsellers https://www.amazon.com/Best-Sellers/zgbs --limit 10 -f json

# Category-specific Best Sellers page
opencli amazon bestsellers "<category-best-sellers-url>" --limit 50 -f json

# Search products
opencli amazon search "desk shelf organizer" --limit 20 -f json

# Validate one product
opencli amazon product B0FJS72893 -f json

# Validate seller / offer facts
opencli amazon offer B0FJS72893 -f json

# Read review summary + samples
opencli amazon discussion B0FJS72893 --limit 5 -f json

Prerequisites

Notes

  • This adapter only returns fields visible on public Amazon pages.
  • bestsellers, movers-shakers, new-releases, and search are for candidate discovery; product, offer, and discussion are the validation surfaces.
  • offer is the right surface for sold_by, ships_from, and Amazon-retail exclusion.
  • discussion may return review data even when Q&A is absent. Missing Q&A is a normal outcome, not an error.
  • A product or review URL from a sibling marketplace (amazon.co.uk, amazon.de, amazon.com.au, …) is read on that marketplace, and the emitted URLs stay on it. A bare ASIN still defaults to amazon.com.

Troubleshooting

  • If Amazon shows a robot-check page, clear it in Chrome and retry.
  • If CDP is attached to the wrong tab, retry with OPENCLI_CDP_TARGET=amazon.com.
  • Avoid running multiple Amazon browser commands in parallel against the same shared Chrome target.

Adapters Browser Apple Podcasts (`docs/adapters/browser/apple-podcasts.md`)

Apple Podcasts

Mode: 🌐 Public · Domain: podcasts.apple.com

Commands

Command Description
opencli apple-podcasts search
opencli apple-podcasts episodes
opencli apple-podcasts top

Usage Examples

bash
# Quick start
opencli apple-podcasts search --limit 5

# JSON output
opencli apple-podcasts search -f json

# Verbose mode
opencli apple-podcasts search -v

Prerequisites

  • No browser required — uses public API

Adapters Browser Archive (`docs/adapters/browser/archive.md`)

Internet Archive

Mode: 🌐 Public · Domain: archive.org

Commands

Command Description
opencli archive search <query> Search Internet Archive items across books, movies, audio, software, and web
opencli archive item Fetch metadata for a single Internet Archive item by identifier
opencli archive wayback Look up the closest Wayback Machine snapshot for a URL
opencli archive snapshots List Wayback Machine snapshots over time for a URL via the CDX API

Usage Examples

bash
# Full-text search across all mediatypes (default sort by downloads)
opencli archive search "machine learning" --limit 10

# Restrict to a mediatype
opencli archive search "newton principia" --mediatype texts --limit 5
opencli archive search "moon landing" --mediatype movies --sort date --limit 5

# Single item metadata
opencli archive item open-syllabus
opencli archive item FinalFantasy2_356

# Closest Wayback snapshot, optionally near a date
opencli archive wayback wikipedia.org
opencli archive wayback wikipedia.org --timestamp 2015

# Wayback CDX history for a URL
opencli archive snapshots wikipedia.org --limit 20
opencli archive snapshots wikipedia.org --from 2010 --to 2015 --limit 50

# JSON output
opencli archive search "machine learning" -f json

`search` Options

Option Description
query (positional) Full-text query (matches title, description, creator, subject)
--mediatype texts / movies / audio / software / image / web / data / collection
--sort downloads (default) / date / addeddate / week / title
--limit Max items (1-100, default: 20)

Returns rows with rank, identifier, title, creator, date, mediatype, downloads, url. The identifier round-trips into opencli archive item .

`item` Options

Option Description
identifier (positional) Archive item identifier (letters, digits, ".", "_", "-")

Returns one row with identifier, title, creator, date, mediatype, collection, description, file_count, url.

`wayback` Options

Option Description
url (positional) URL to look up (with or without scheme)
--timestamp Target timestamp (YYYY[MM[DD[hh[mm[ss]]]]] or ISO date). Defaults to most recent snapshot

Returns one row with original_url, requested_timestamp, snapshot_timestamp, snapshot_url, status. The snapshot_url round-trips into a regular browser fetch.

`snapshots` Options

Option Description
url (positional) URL to look up (with or without scheme)
--from Earliest digit-only timestamp
--to Latest digit-only timestamp
--limit Max snapshots (1-1000, default: 20)

Returns rows with timestamp, snapshot_url, status, mimetype, original_url. Each snapshot_url is a direct Wayback Machine permalink. The CDX endpoint is served over HTTP only; the HTTPS endpoint returns 503 in practice.

Prerequisites

  • No browser required; uses public archive.org APIs (Advanced Search, Metadata, Wayback Available, CDX).

Adapters Browser Arxiv (`docs/adapters/browser/arxiv.md`)

arXiv

Mode: 🌐 Public · Domain: arxiv.org

Commands

Command Description
opencli arxiv search <query> Search arXiv papers
opencli arxiv paper Get arXiv paper details by ID
opencli arxiv recent <category> List recent submissions in a category
opencli arxiv author <name> List papers by a given author (newest first)

Usage Examples

bash
# Search for papers
opencli arxiv search "transformer attention" --limit 10

# Get full paper details (full abstract, all authors, primary/all categories, pdf url)
opencli arxiv paper 1706.03762

# Newest papers in a category, sorted by submitted date desc
opencli arxiv recent cs.CL --limit 10
opencli arxiv recent math.PR --limit 5

# Newest papers by an author (best-effort fuzzy match — try alternate spellings if empty)
opencli arxiv author "Yoshua Bengio" --limit 20
opencli arxiv author "Y Bengio" --limit 5

# JSON output
opencli arxiv search "LLM" -f json

Output Columns

Command Columns
paper id, title, authors, published, updated, primary_category, categories, abstract, comment, pdf, url
search id, title, authors, published, primary_category, url
recent id, title, authors, published, primary_category, url
author id, title, authors, published, primary_category, url

paper returns the full abstract and full author list. search/recent are list-style outputs that omit the abstract for readability — pipe an id into paper for the full record.

Common Categories

cs.AI, cs.CL, cs.LG, cs.CV, cs.RO, stat.ML, math.PR, math.ST, q-bio.NC, econ.TH, physics.comp-ph. Full list: https://arxiv.org/category_taxonomy.

Prerequisites

  • No browser required — uses public arXiv API

Adapters Browser Autohome (`docs/adapters/browser/autohome.md`)

汽车之家 Autohome

Mode: 🌐 Public · Domain: autohome.com.cn

No login, no cookies, no signature. Reads two fully server-rendered sources:
the brand catalog (grade/carhtml/.html) and the 口碑 page
(k.autohome.com.cn/<seriesId>, whose __NEXT_DATA__ carries the aggregate
rating).

Commands

Command Description
opencli autohome brand <品牌> A brand's car series + 厂商指导价 (guide price)
opencli autohome score <series_id> 口碑 rating: overall + per-dimension + 故障率PPH + competitors

score takes a series_id from brand (the series_id column) or a
https://k.autohome.com.cn/ URL.

Usage Examples

bash
# A brand's whole lineup with guide prices
opencli autohome brand 宝马
opencli autohome brand 比亚迪 --limit 80
opencli autohome brand 理想

# Owner-rating summary for a series
opencli autohome score 6548        # 宝马X5

# JSON output
opencli autohome brand 丰田 -f json

Output Columns

Command Columns
brand series_id, name, price, url
score field, value (series_id, name, brand, level, guide_price, overall, 各维度评分…, pph_每百车故障, review_users, competitors, url)

Notes & Limits

  • Search is by brand, not free text. Autohome's keyword-search and the
    per-trim config JSON are app-signature gated; the brand catalog is the
    login-free entry point, so you search by brand (e.g. 宝马 / 比亚迪 / 理想) and
    drill into a series from there. For free-text model search, use
    dongchedi search.
  • brand accepts known Chinese brand names (mapped to the catalog's pinyin
    initial) or a single A-Z catalog letter. Unknown brands raise a clear error
    rather than guessing.
  • score is the aggregate rating only. The per-review owner-text list loads
    from a separate signed XHR and is intentionally not scraped (use
    dongchedi koubei for owner review bodies).
  • Full per-trim config (参数配置) is not offered — Autohome's config page
    obfuscates values with a rotating CSS font glyph map, which can't be read
    reliably from plain HTTP; faking partial specs would be worse than omitting
    them. Use dongchedi specs for a config overview.

Prerequisites

None — public site, no authentication required.


Adapters Browser Baidu Scholar (`docs/adapters/browser/baidu-scholar.md`)

Baidu Scholar

Mode: 🌐 Public · Domain: xueshu.baidu.com

Commands

Command Description
opencli baidu-scholar search <query> Search Baidu Scholar papers by keyword

Usage Examples

bash
opencli baidu-scholar search "大语言模型"
opencli baidu-scholar search "检索增强生成" --limit 5

Notes

  • Runs in browser mode against public search results
  • Baidu may occasionally present verification or anti-bot pages

Adapters Browser Band (`docs/adapters/browser/band.md`)

Band

Mode: 🔐 Browser · Domain: www.band.us

Read posts, comments, and notifications from Band, a private community platform. Authentication uses your logged-in Chrome session (cookie-based).

Commands

Command Description
opencli band bands List all Bands you belong to
opencli band posts List posts from a Band
opencli band post Export full post content including nested comments
opencli band mentions Show notifications where you were @mentioned

Usage Examples

bash
# List all your bands (get band_no from here)
opencli band bands

# List recent posts in a band
opencli band posts 12345678 --limit 10

# Export a post with comments
opencli band post 12345678 987654321

# Export post body only (skip comments)
opencli band post 12345678 987654321 --comments false

# Export post and download attached photos
opencli band post 12345678 987654321 --output ./band-photos

# Show recent @mention notifications
opencli band mentions --limit 20

# Show only unread mentions
opencli band mentions --unread true

# Show all notification types
opencli band mentions --filter all

`band mentions` filter options

Filter Description
mentioned Only notifications where you were @mentioned (default)
all All notifications
post Post-related notifications
comment Comment-related notifications

Prerequisites

Notes

  • band_no is the numeric ID in the Band URL: band.us/band/{band_no}/post
  • band bands lists all your bands with their band_no values
  • band post output rows: type=post (the post itself), type=comment (top-level comment), type=reply (nested reply)
  • Photo downloads use the full-resolution URL (thumbnail query params are stripped automatically)

Adapters Browser Barchart (`docs/adapters/browser/barchart.md`)

Barchart

Mode: 🔐 Browser · Domain: barchart.com

Commands

Command Description
opencli barchart quote Stock quote with price, volume, and key metrics
opencli barchart options Options chain with greeks, IV, volume, and open interest
opencli barchart greeks Options greeks overview (IV, delta, gamma, theta, vega)
opencli barchart flow Unusual options activity / options flow

Usage Examples

bash
# Get stock quote
opencli barchart quote AAPL

# View options chain
opencli barchart options TSLA

# Options greeks overview
opencli barchart greeks NVDA

# Unusual options flow
opencli barchart flow --limit 20 -f json

Prerequisites


Adapters Browser Bbc (`docs/adapters/browser/bbc.md`)

BBC News

Mode: 🌐 Public · Domain: bbc.com

Commands

Command Description
opencli bbc news Latest BBC News headlines (top stories)
opencli bbc topic <topic> Latest headlines for a single BBC topic feed

Usage Examples

bash
# Top stories
opencli bbc news --limit 5

# Topic-scoped feeds (RSS at feeds.bbci.co.uk/news/<topic>/rss.xml)
opencli bbc topic technology --limit 10
opencli bbc topic world --limit 20
opencli bbc topic business
opencli bbc topic science_and_environment

# JSON output
opencli bbc topic technology -f json

Topics

Valid <topic> values:

Topic slug Feed
world World news
business Business
politics UK politics
health Health
education Education & family
science_and_environment Science & environment
technology Technology
entertainment_and_arts Entertainment & arts

Pass any other value and the adapter raises ArgumentError with the full list.

Output Columns

Command Columns
news (see existing news row schema)
topic rank, title, description, pubDate, url

Prerequisites

  • No browser required — uses the public BBC RSS feeds at feeds.bbci.co.uk.

Adapters Browser Bilibili (`docs/adapters/browser/bilibili.md`)

Bilibili

Mode: 🔐 Browser · Domain: bilibili.com

Commands

Command Description
opencli bilibili hot
opencli bilibili search
opencli bilibili me
opencli bilibili favorite Read your first favorite folder, or a specific folder with --fid
opencli bilibili history
opencli bilibili feed Read the following feed, or a specific user's dynamics by uid/name
opencli bilibili feed-detail Read one dynamic in detail, including exclusive content
opencli bilibili subtitle
opencli bilibili video Get one video's metadata (title, author, duration, stats) by BV / URL / b23.tv link
opencli bilibili summary Get the official AI video summary and timestamped outline by BV / URL / b23.tv link
opencli bilibili comments Read top-level comments; --parent reads replies under a comment, --top reads only pinned comments
opencli bilibili comment Post a top-level comment or reply under a top-level comment (requires --execute)
opencli bilibili dynamic
opencli bilibili ranking
opencli bilibili following
opencli bilibili follow Follow a user by UID, profile URL, or resolvable name; verifies the relation after modify
opencli bilibili unfollow Unfollow a user by UID, profile URL, or resolvable name; verifies the relation after modify
opencli bilibili user-videos
opencli bilibili download
opencli bilibili creator-stats Read a curated manuscript-level metric snapshot from the latest creator-center comparison rows

Usage Examples

text
/* Detailed source-code truncated for AI context efficiency. */

Prerequisites

Notes

  • subtitle includes the selected track's language and track_type on every row. track_type is ai for an AI-marked track, cc for an explicitly non-AI track, and unknown when the source does not identify the track type.

  • opencli bilibili feed without uid reads your following feed

  • opencli bilibili feed reads a specific user's dynamics

  • user-videos fills likes from one extra medialist request per page (arc/search's vlist[] carries no like count at all, so the column used to read 0 for every row). likes_known says whether that row's number is real — medialist only lists uploads in pubdate order and skips some (paid courses, charging-exclusive), so rows it does not cover report likes: 0, likes_known: false rather than a fake zero. With --order click/stow most rows fall outside that order and stay unknown

  • feed, search, user-videos and video also emit machine-readable columns next to the display ones: duration_sec (seconds), plays/likes/danmaku (numbers, 万/亿 text parsed), pub_ts/created_ts/pubdate_ts (unix seconds), plus bvid, cover, mid and face. The display columns (time, date, publish_time, duration, score, author) keep their old meaning and format

  • opencli bilibili favorite defaults to the first favorite folder when --fid is omitted

  • feed-detail expects the dynamic ID from a https://t.bilibili.com/ URL

  • comments emits rpid; pass a top-level row's rpid to comments --parent to read its reply thread

  • comments --limit accepts 1..50; empty comment lists raise EmptyResultError

  • comments --top returns only pinned comments (from the API's top_replies); it cannot be combined with --parent, and a video with no pinned comment raises EmptyResultError

  • comment is a write command and refuses to post unless --execute is passed

  • comment --parent expects the top-level/root rpid; nested reply-to-reply targeting is not inferred

  • follow and unfollow are write commands; they no-op when the current relation already matches the requested state and otherwise re-read /x/relation after modify before reporting success

  • follow and unfollow accept numeric UID, exact space.bilibili.com/ profile URL, or a name that resolves through Bilibili search

  • creator-stats uses the logged-in creator-center session and searches the comparison endpoint's latest 100 manuscript rows. A missing BVID is reported as empty because it may be older, not owned by this account, or not analyzed yet; absence does not prove an ownership or login failure.

  • The command emits a fixed manuscript-level metric family as { bvid, metric, value, unit }. Counts use count, duration uses seconds, and documented basis-point rates are normalized to percent in the 0–100 range. A null value means that individual metric has not been generated yet.

  • The comparison endpoint is undocumented and treated as an internal, unstable contract: missing or malformed required fields fail closed instead of silently changing the output schema. The command does not claim per-part retention analytics.


Adapters Browser Binance (`docs/adapters/browser/binance.md`)

Binance

Access Binance market data from the terminal via the public API (no authentication required).

Mode: 🌐 Public · Domain: data-api.binance.vision

Commands

Command Description
opencli binance price Get 24h ticker stats for one symbol
opencli binance prices Get latest prices for all symbols
opencli binance ticker Get 24h ticker stats for all symbols
opencli binance pairs List exchange trading pairs
opencli binance trades Get recent trades for one symbol
opencli binance depth Get order-book depth for one symbol
opencli binance asks Show ask-side depth for one symbol
opencli binance klines Get candlestick data
opencli binance top Show top movers by volume
opencli binance gainers Show top gainers
opencli binance losers Show top losers

Usage Examples

bash
# One symbol, 24h stats
opencli binance price BTCUSDT

# Latest prices for all pairs
opencli binance prices

# Recent trades
opencli binance trades BTCUSDT --limit 20

# Order-book depth
opencli binance depth BTCUSDT --limit 20

# 1h candles
opencli binance klines BTCUSDT --interval 1h --limit 50

# JSON output
opencli binance top -f json

Prerequisites

  • No browser required — uses Binance public market-data endpoints

Notes

  • Symbols use Binance market format such as BTCUSDT or ETHUSDT
  • Public market-data endpoints can still be rate-limited upstream; retry if you hit transient failures

Adapters Browser Bloomberg (`docs/adapters/browser/bloomberg.md`)

Bloomberg

Mode: 🌐 / 🔐 Mixed · Domains: feeds.bloomberg.com, www.bloomberg.com

Commands

Command Description
opencli bloomberg main Bloomberg homepage top stories from RSS
opencli bloomberg markets Bloomberg Markets top stories from RSS
opencli bloomberg economics Bloomberg Economics top stories from RSS
opencli bloomberg industries Bloomberg Industries top stories from RSS
opencli bloomberg tech Bloomberg Tech top stories from RSS
opencli bloomberg politics Bloomberg Politics top stories from RSS
opencli bloomberg businessweek Bloomberg Businessweek top stories from the section page
opencli bloomberg opinions Bloomberg Opinion top stories from RSS
opencli bloomberg green Bloomberg Green top stories from RSS
opencli bloomberg crypto Bloomberg Crypto top stories from RSS
opencli bloomberg pursuits Bloomberg Pursuits top stories from RSS
opencli bloomberg feeds List the RSS feed aliases used by the adapter
opencli bloomberg news <link> Read a standard Bloomberg story/article page and return title, summary, media links, and article text

What works today

  • RSS-backed listing commands work without a browser:
    • main
    • markets
    • economics
    • industries
    • tech
    • politics
    • opinions
    • green
    • crypto
    • pursuits
    • feeds
  • bloomberg businessweek reads the live Businessweek section page through Browser Bridge because Bloomberg's legacy Businessweek RSS feed is currently empty.
  • bloomberg news works on standard Bloomberg story/article pages that expose #__NEXT_DATA__ and are accessible to your current Chrome session.

Current limitations

  • Audio pages and some other non-standard Bloomberg URLs may fail.
  • Some Bloomberg pages can return bot-protection or access-gated responses instead of article data.
  • This adapter is for data retrieval/extraction only. It does not bypass Bloomberg paywall, login, entitlement, or other access checks.

Usage Examples

bash
# List supported RSS feed aliases
opencli bloomberg feeds

# Fetch Bloomberg homepage headlines
opencli bloomberg main --limit 5

# Fetch a section feed as JSON
opencli bloomberg tech --limit 3 -f json

# Fetch Businessweek section stories
opencli bloomberg businessweek --limit 5 -f json

# Read a standard article page
opencli bloomberg news https://www.bloomberg.com/news/articles/2026-03-19/example -f json

# Relative article paths also work
opencli bloomberg news /news/articles/2026-03-19/example

Prerequisites

  • RSS commands do not require Chrome.
  • bloomberg businessweek requires Chrome and the Browser Bridge extension because it reads the section page.
  • bloomberg news requires:
    • Chrome running
    • a Chrome session that can already access the target Bloomberg article page
    • the Browser Bridge extension

Notes

  • Listing commands support --limit with a maximum of 20 items.
  • bloomberg feeds lists RSS-backed aliases only; businessweek is intentionally absent because it is section-page backed.
  • If bloomberg news fails on a page from RSS, try a different standard story/article link first; not every Bloomberg URL in feeds is a normal article page.

Adapters Browser Bluesky (`docs/adapters/browser/bluesky.md`)

Bluesky

Mode: 🌐 Public · Domain: bsky.app

Commands

Command Description
opencli bluesky profile User profile info
opencli bluesky user Recent posts from a user
opencli bluesky trending Trending topics
opencli bluesky search Search users
opencli bluesky feeds Popular feed generators
opencli bluesky followers User's followers
opencli bluesky following Accounts a user follows
opencli bluesky thread Post thread with replies
opencli bluesky starter-packs User's starter packs

Usage Examples

bash
# User profile
opencli bluesky profile --handle bsky.app

# Recent posts
opencli bluesky user --handle bsky.app --limit 10

# Trending topics
opencli bluesky trending --limit 10

# Search users
opencli bluesky search --query "AI" --limit 10

# Popular feeds
opencli bluesky feeds --limit 10

# Followers / following
opencli bluesky followers --handle bsky.app --limit 10
opencli bluesky following --handle bsky.app

# Post thread with replies
opencli bluesky thread --uri "at://did:.../app.bsky.feed.post/..."

# Starter packs
opencli bluesky starter-packs --handle bsky.app

# JSON output
opencli bluesky profile --handle bsky.app -f json

Prerequisites

None — all commands use the public Bluesky AT Protocol API, no browser or login required.


Adapters Browser Booking (`docs/adapters/browser/booking.md`)

Booking.com

Mode: 🔓 Public (browser) · Domain: www.booking.com

Commands

Command Description
opencli booking search Search hotels by destination + check-in/check-out dates

Usage Examples

bash
# Basic — 2 adults, 1 room, default Booking page size (25 results)
opencli booking search Tokyo --checkin 2026-06-15 --checkout 2026-06-17

# Force result locale and currency
opencli booking search Paris --checkin 2026-07-01 --checkout 2026-07-03 \
  --lang en-us --currency USD

# Family stay — 2 adults + 2 children, 1 room
opencli booking search Singapore --checkin 2026-06-15 --checkout 2026-06-20 \
  --adults 2 --children 2

# Paginate (Booking pages 25 per request)
opencli booking search Tokyo --checkin 2026-06-15 --checkout 2026-06-17 --offset 25

# JSON output for downstream tooling
opencli booking search Tokyo --checkin 2026-06-15 --checkout 2026-06-17 -f json

Output

Column Type Notes
rank int 1-based position within this query (carries --offset so paginated calls stay sortable)
name string Hotel display name. May be localized by browser session cookies — see Locale handling below
country string ISO-3166 alpha-2 country code parsed from URL path
slug string URL path slug — stable cross-locale identifier, round-trips into the canonical detail URL
star_rating int | null Booking star rating (1–5). null is common — Booking renders stars inconsistently on listing cards
review_score float | null Aggregate guest score on a 1.0–10.0 scale (e.g. 8.6)
review_count int | null Number of reviews backing the score
price_amount float | null Final per-stay price as a plain number, in price_currency
price_currency string | null ISO 4217 currency code. Pass --currency USD (or similar) to set Booking's selected_currency and force a stable output code
distance string | null Distance-from-centre string (locale-formatted, e.g. 3.4 km from centre / 离中心地区3.4千米)
recommended_room string | null Recommended room type + bed config + amenity/urgency hints, concatenated as Booking ships them
url string Canonical https://www.booking.com/hotel/<country>/<slug>.html

null semantics: a null field means Booking did not expose that field for
this card (e.g. some listings have no star rating, no review count yet, or no
price displayed because dates are unavailable). Failures (page failed to
render, captcha challenge) raise typed errors instead of silently returning
empty rows.

Validation (no silent clamp)

  • --checkin / --checkout must be YYYY-MM-DD; checkout must be strictly after checkin.
  • --adults 1..30, --rooms 1..30, --children 0..10 — out-of-range throws ArgumentError (no silent clamp).
  • --limit 1..100, --offset 0..1000 — out-of-range throws ArgumentError.
  • --lang must be one of the supported Booking locales (e.g. en-us, zh-cn, ja, ko, de, fr, es); anything else throws ArgumentError.
  • --currency must be a 3-letter ISO 4217 code (USD, JPY, CNY, …); symbols like US$ throw ArgumentError.

Locale handling

The URL path encodes the requested locale (searchresults.<lang>.html) and
selected_currency forces ISO 4217 price symbols. But bound browser
session cookies can still override hotel name strings to the user's preferred
language even when --lang en-us is set. The slug, url, country, and
numeric fields stay stable regardless — prefer slug (not name) as the
round-trip key. When --currency is provided and Booking renders a price,
the adapter reports that requested ISO code instead of guessing from ambiguous
symbols such as $ or ¥.

Anti-bot

Booking serves a /captcha verification page after sustained scraping. The
adapter detects this via title / body text inspection and raises
CommandExecutionError instead of silently returning empty rows. If you hit
this, slow your call rate or change browser profile / IP.

Notes

  • Strategy: Strategy.PUBLIC + browser: true. No login required.
  • Booking's search results are server-rendered HTML; the adapter scrapes
    [data-testid=property-card] cards via page.evaluate(EXTRACTOR). The
    [data-testid] attributes are stable, but layout details change
    occasionally.
  • The score block renders score text duplicated as 8.68.6 (a11y + visual
    copies); the extractor anchors on the first (\d{1,2})\.(\d) capture to
    avoid mis-parsing 8.6 as 8.68.

Adapters Browser Boss (`docs/adapters/browser/boss.md`)

BOSS Zhipin

Mode: 🔐 Browser · Domain: zhipin.com

Commands

Command Description
opencli boss search
opencli boss detail

Usage Examples

bash
# Quick start
opencli boss search --limit 5

# JSON output
opencli boss search -f json

# Verbose mode
opencli boss search -v

Prerequisites


Adapters Browser Brave (`docs/adapters/browser/brave.md`)

Mode: 🌐 Public · Domain: search.brave.com

Commands

Command Description
opencli brave search <keyword> Search Brave Search and extract results from the page

What works today

  • Uses browser mode to search search.brave.com and extract ranked results via DOM queries.
  • Supports --offset for GET-based pagination. Brave returns approximately 18 results per page.
  • Results include rank, title, URL, and snippet.
  • --limit must be between 1 and 18; --offset must be a non-negative page offset.

Current limitations

  • Requires browser mode. Brave Search does not offer a public, no-auth search API.
  • DOM structure uses Svelte-generated class names that may change with updates.
  • Some results may have empty snippets depending on Brave's layout.

Usage Examples

bash
# Basic search
opencli brave search "machine learning"

# Limit results
opencli brave search "machine learning" --limit 5

# Pagination (second page)
opencli brave search "machine learning" --offset 1

# JSON output
opencli brave search "machine learning" -f json

Prerequisites

Notes

  • Brave Search renders results server-side; all results are present in the initial HTML (no lazy loading).
  • Brave also shows an AI-generated summary box as the first result. The adapter filters this out via the .standalone class check.

Adapters Browser Chaoxing (`docs/adapters/browser/chaoxing.md`)

超星学习通 (Chaoxing)

Mode: 🔐 Browser · Domain: mooc2-ans.chaoxing.com

Commands

Command Description
opencli chaoxing assignments 学习通作业列表
opencli chaoxing exams 学习通考试列表

Usage Examples

bash
# List all assignments
opencli chaoxing assignments --limit 20

# Filter exams by course name
opencli chaoxing exams --course "高等数学"

# Filter exams by status
opencli chaoxing exams --status ongoing

# JSON output
opencli chaoxing assignments -f json

Options

Option Description
--course Filter by course name (fuzzy match)
--status Filter by status: all, upcoming, ongoing, finished
--limit Max number of results (default: 20)

Prerequisites


Adapters Browser Chatgpt (`docs/adapters/browser/chatgpt.md`)

ChatGPT Web

Mode: 🔐 Browser · Domain: chatgpt.com

Commands

Command Description
opencli chatgpt ask Send a prompt and wait for the visible response
opencli chatgpt ask-file --file Attach local files and wait for the response
opencli chatgpt send Send a prompt without waiting
opencli chatgpt read Read the current conversation
opencli chatgpt history List visible conversation history links from the sidebar
opencli chatgpt detail Open a conversation by /c/ and read it
opencli chatgpt deep-research-result Read a completed Deep Research report from a conversation
opencli chatgpt new Start a new conversation
opencli chatgpt status Check page and login state
opencli chatgpt image Generate images in ChatGPT web and optionally save them locally
opencli chatgpt model <level> Switch the ChatGPT web intelligence level

Usage Examples

text
/* Detailed source-code truncated for AI context efficiency. */

Options

Option Description
prompt Prompt to send (required for ask, send, and image)
--timeout Max seconds for ask to wait for a response (default: 120)
--wait For deep-research-result, wait until a Deep Research report completes or becomes extractable
--stable For deep-research-result, seconds the report text must remain unchanged when waiting (default: 6)
--new Start a new conversation before ask / send
--markdown Convert assistant message HTML to Markdown for read / detail
--limit Max visible history conversations to return (default: 20)
--image Local image path to attach before prompting; comma-separated paths are supported
--op Output directory for downloaded images (default: ~/Pictures/chatgpt)
--sd Skip download and only print the ChatGPT conversation link
model ChatGPT intelligence level for model: fast, balanced, advanced, very-high, or pro; aliases include speed/instant, balance/medium, high/thinking, ultra/xhigh/x-high/extra-high, professional, and the Chinese labels 极速/均衡/高级/超高/专业

Behavior

  • ChatGPT web commands use persistent site sessions by default, so consecutive ask / send / read / detail commands continue in the same ChatGPT tab. Use --site-session ephemeral for one-shot isolated tabs.
  • ask waits for the first stable assistant response after sending. send submits only and returns immediately.
  • ask-file targets the active composer, selects a compatible document input, and waits for new, visible attachment chips with exact filenames or standard numeric deduplication suffixes. Historical filename text, existing attachments, unrelated media, pending uploads, and error chips do not confirm this upload. The prompt is not sent if readiness cannot be confirmed. Older Browser Bridge versions use the same pinned file input through a compatibility path that transfers bounded chunks before a single file assignment, limited to 25 MB per file; larger files require current native file-input support.
  • history reads visible /c/ links from the ChatGPT sidebar; it does not use private backend APIs.
  • deep-research-result opens the requested conversation and extracts completed Deep Research output from that conversation's /backend-api/conversation/ payload, especially metadata.chatgpt_sdk.widget_state.report_message. It does not return a success row when no completed report is present.
  • model switches the visible ChatGPT web intelligence level. It recognizes the current English labels (Fast, Balanced, Advanced, Very High, Pro), legacy labels (Instant, Medium, High, Extra High), and Chinese labels (极速, 均衡, 高级, 超高, 专业). Advanced and Pro first try ChatGPT's authenticated backend model preference update, then the adapter falls back to the visible picker for UI-only levels. If labels are localized differently, it only falls back to option order after confirming the guarded five-option ChatGPT intelligence picker structure.
  • On the Power slider UI, fast, balanced, advanced, and very-high select Low, Medium, High, and Extra High reasoning effort for the current model. Selection uses the visible slider and verifies its resulting value; unavailable levels fail explicitly.
  • Image polling preserves local draft conversations when their temporary IDs become persisted IDs, and returns the final conversation URL.
  • image opens a fresh chatgpt.com/new page before sending the image prompt.
  • When --image is provided, local images are uploaded first and the prompt is sent as an image edit request.
  • image output is plain status / file / link, not a markdown table.
  • When --sd is enabled, the command does not download files and only prints the ChatGPT link.
  • Downloaded files are named with a timestamp to avoid overwriting prior runs.

Prerequisites

Caveats

  • This adapter targets the ChatGPT web UI, not the macOS desktop app.
  • It depends on the current browser session and can fail if ChatGPT shows login, challenge, quota, or other gating UI.
  • DOM or product changes on ChatGPT can break composer detection, image detection, or export behavior.

Consecutive prompts

Identical questions and answers in separate turns are retained by the upstream content-node message reader. Reused inactive ChatGPT automation tabs are activated within their own session.

After a timeout, check opencli chatgpt read before sending again: the original message may already have been submitted.


Adapters Browser Chess (`docs/adapters/browser/chess.md`)

Chess.com

Mode: 🌐 Public · Domain: api.chess.com / www.chess.com

Read-only adapter against the public Chess.com endpoints. stats, games, game use no-auth REST; analyze opens the Chess.com analysis board in a bound browser session.

Commands

Command Description
opencli chess stats Player rating + win/loss/draw record across game kinds (rapid / blitz / bullet / daily / chess960)
opencli chess games Recent games newest-first across one or more monthly archives
opencli chess game <game-url> Single-game detail (white, black, result, ECO, termination, ply count) by full game URL
opencli chess analyze <game-url> Open the game in Chess.com's analysis board in the bound browser session

Usage Examples

bash
# Stats
opencli chess stats hikaru
opencli chess stats magnuscarlsen -f json

# Recent games (default 10, max 100)
opencli chess games hikaru
opencli chess games erik --limit 25

# Single-game detail from a game URL
opencli chess game https://www.chess.com/game/live/168842570216
opencli chess game https://www.chess.com/game/daily/947761777

# Open in Chess.com analysis board (browser session required)
opencli chess analyze https://www.chess.com/game/live/168842570216

Columns

`stats`

Column Notes
kind rapid / blitz / bullet / daily / chess960_daily (only kinds the player has played)
rating_current Latest rating
rating_best All-time best rating
wins / losses / draws Cumulative record

`games`

Column Notes
date Game end date in YYYY-MM-DD (UTC)
time_class rapid / blitz / bullet / daily
rated Boolean
my_color white or black from the viewer's perspective
my_rating Viewer's rating in this game
my_result win / resigned / timeout / checkmated / agreed / repetition / etc
opponent Opponent's Chess.com username
opponent_rating Opponent's rating at game time
accuracy_white / accuracy_black Chess.com move-accuracy percentage (0-100) when computed by Game Review; empty when the game wasn't analyzed (unrated / very short / abandoned)
eco Raw ECO opening tag or full opening URL chess.com encodes on the row
opening_name Human-readable opening name parsed from the eco URL (e.g. Reti Opening Nimzo Larsen Variation); empty when eco is the short-code form (A01) which carries no name
url Game URL on chess.com

Username Validation

Usernames are normalized to lowercase and matched against ^[a-zA-Z0-9_-]{3,25}$. Invalid inputs raise ArgumentError before any HTTP call.

Archive Walk

games calls /pub/player//games/archives first to list every month the player has games in, then walks the list newest-first fetching one monthly archive at a time until --limit is filled. Capped at 6 monthly fetches per invocation so an obscure account with a long archive history doesn't fan out.

Limit Validation

--limit accepts integers in [1, 100]. Out-of-range / non-integer values raise ArgumentError (no silent clamp).

`game`

Column Notes
kind live or daily parsed from the URL
game_id Numeric id parsed from the URL
date YYYY-MM-DD from PGN headers (end-time fallback)
white / black Usernames; resolved from players.{top,bottom} keyed by .color, with pgnHeaders.{White,Black} fallback
white_rating / black_rating Per-player rating at game time
result PGN result token: 1-0, 0-1, 1/2-1/2
winner_color white, black, or empty on draw
termination Human-readable reason (e.g. "Hikaru won by resignation")
eco ECO opening code
time_control Wire TimeControl header for live (180 = 3 min), <N>d/turn for daily
rated Boolean
ply_count Half-move count
url Canonical game URL

`analyze`

Column Notes
kind live / daily parsed from the URL
game_id Numeric id parsed from the URL
analysis_url Resolved /analysis/game/<kind>/ URL the bound browser session navigated to

Endpoint Notes

game uses /callback/{live\|daily}/game/{id} on www.chess.com (the same JSON the Chess.com web client hits when rendering a game page). The public REST surface at api.chess.com/pub has no single-game endpoint; the callback path is the cleanest way to honour "PGN for specific game" without DOM scraping.

analyze is a thin wrapper around page.goto('/analysis/game/<kind>/'). Requires a bound browser session; if you only need to open a URL, opencli browser --session <session> open is the more general primitive.

Out of Scope

  • Live game tracking (live moves streaming): outside the public REST surface.
  • Move-by-move engine evaluation: separate concern, would belong in a future chess engine adapter.

Adapters Browser Claude (`docs/adapters/browser/claude.md`)

Claude

Mode: Browser · Domain: claude.ai

Commands

Command Description
opencli claude ask Send a prompt and get the response
opencli claude send Send a prompt without waiting for the response
opencli claude new Start a new conversation
opencli claude status Check login state and page availability
opencli claude read Read the current conversation
opencli claude history List recent conversations from /recents
opencli claude detail Open a conversation by ID and read its messages

Usage Examples

bash
# Ask a question
opencli claude ask "explain quicksort in 3 sentences"

# Start a new chat before asking
opencli claude ask "hello" --new

# Pick the model (default: sonnet; opus is paid-tier)
opencli claude ask "quick summary" --model haiku

# Enable Adaptive thinking
opencli claude ask "prove that sqrt(2) is irrational" --think

# Attach a file (image / PDF / text, up to ~1 MB raw)
opencli claude ask "describe this image" --file ./photo.png

# Combine modes
opencli claude ask "what does this PDF cover?" --file ./paper.pdf --think --new

# Custom timeout (default: 120s)
opencli claude ask "write a long essay" --timeout 240

# JSON output
opencli claude ask "hello" -f json

Options (ask)

Option Description
`` The message to send (required, positional)
--timeout Wait timeout in seconds (default: 120)
--new Start a new chat before sending (default: false)
--model Model to use: sonnet, opus, or haiku (default: sonnet)
--think Enable Adaptive thinking (default: false)
--file Attach a file (image, PDF, text) with the prompt

Prerequisites

Caveats

  • This adapter drives the Claude web UI in the browser, not an API
  • Claude commands default to persistent site sessions, so consecutive claude ask / claude read / claude detail invocations continue in the same Claude page. Pass --site-session ephemeral for a one-shot tab.
  • --model opus requires a paid Claude plan; on a free-tier account the adapter surfaces a usage error rather than silently falling back
  • The default Sonnet 4.6 model uses Adaptive thinking by default; --think is the explicit switch but Claude may still invoke thinking for complex prompts even when not requested
  • Adaptive-thinking and file-thumbnail widgets render duplicated label paragraphs (Thought process / View uploaded image) at the top of the response; these are stripped automatically so the row value is the actual answer
  • File upload is constrained by the daemon HTTP body limit (1 MB; src/daemon.ts:152); files up to ~700 KB raw work reliably, larger files (e.g. high-res images) may fail with ECONNRESET
  • Long responses (code, essays) may need a higher --timeout

Adapters Browser Cnki (`docs/adapters/browser/cnki.md`)

CNKI

Mode: 🔐 Browser · Domain: oversea.cnki.net

Commands

Command Description
opencli cnki search <query> Search CNKI Overseas papers by keyword

Usage Examples

bash
# Search CNKI papers
opencli cnki search "large language model"

# Limit returned results
opencli cnki search "retrieval augmented generation" --limit 5

Prerequisites


Adapters Browser Coingecko (`docs/adapters/browser/coingecko.md`)

CoinGecko

Access CoinGecko crypto market data from the terminal via the public API (no authentication required).

Mode: 🌐 Public · Domain: api.coingecko.com

Commands

Command Description
opencli coingecko top Top coins by market cap
opencli coingecko coin Single coin's market detail (price / supply / ATH / homepage)
opencli coingecko trending Top trending coins on CoinGecko in the last 24h
opencli coingecko exchanges Top exchanges ranked by trust score / 24h BTC volume
opencli coingecko categories Crypto sector categories (DeFi / Layer1 / Memes / …) with market cap
opencli coingecko derivatives Top crypto derivative (perpetual / futures) markets by 24h volume
opencli coingecko global Aggregate market totals: total cap, volume, BTC/ETH dominance

Usage Examples

bash
# Top 10 coins in USD (default)
opencli coingecko top

# Top 5 coins priced in CNY
opencli coingecko top --currency cny --limit 5

# Top 50 coins in EUR
opencli coingecko top --currency eur --limit 50

# Single coin detail (slug from `top` or coingecko URL)
opencli coingecko coin bitcoin
opencli coingecko coin ethereum --currency cny

# Trending in the last 24h (search-volume based)
opencli coingecko trending

# Top exchanges (trust score, 24h BTC volume)
opencli coingecko exchanges --limit 20

# Crypto sector categories (default sort: market_cap_desc)
opencli coingecko categories --limit 10
opencli coingecko categories --sort market_cap_change_24h_desc --limit 10

# Top derivative tickers (perpetuals + futures, sorted by 24h USD volume)
opencli coingecko derivatives --limit 20

# Filter derivatives by symbol substring (BTC pairs only)
opencli coingecko derivatives --symbol BTC --limit 10

# Aggregate market totals (BTC dominance, total cap, etc.)
opencli coingecko global
opencli coingecko global --currency cny

# JSON output
opencli coingecko top -f json

Options

`top`

Option Description
--currency Quote currency (usd / cny / eur / jpy / etc., default: usd)
--limit Number of coins to return (1–250, default: 10)

`coin`

Option Description
id (positional) CoinGecko coin slug (lowercase, e.g. bitcoin, ethereum, solana)
--currency Quote currency (default: usd)

No arguments — returns the current top-7 trending list.

`exchanges`

Option Description
--limit Number of exchanges to return (1–250, default: 20)

`categories`

Option Description
--sort One of market_cap_desc (default), market_cap_asc, name_desc, name_asc, market_cap_change_24h_desc, market_cap_change_24h_asc
--limit Number of categories to return (1–100, default: 20)

`derivatives`

Option Description
--limit Max rows to return (1–500, default: 20)
--symbol Optional symbol substring filter (e.g. BTC, ETHUSDT) — also matches the index_id field

`global`

Option Description
--currency Quote currency for total market cap / volume (default: usd)

Output Columns

Command Columns
top rank, symbol, name, price, change24hPct, marketCap, volume24h, high24h, low24h
coin id, symbol, name, rank, price, marketCap, volume24h, change24hPct, change7dPct, change30dPct, ath, athDate, atl, atlDate, circulatingSupply, totalSupply, maxSupply, genesisDate, homepage
trending rank, id, symbol, name, marketCapRank, priceBtc, thumb
exchanges rank, id, name, trustScore, volume24hBtc, country, yearEstablished, url
categories rank, id, name, marketCap, volume24h, marketCapChange24hPct, top3Coins
derivatives rank, market, symbol, indexId, contractType, price, change24hPct, fundingRate, openInterestUsd, volume24hUsd, expired
global currency, totalMarketCap, totalVolume24h, marketCapChange24hPct, btcDominancePct, ethDominancePct, activeCryptocurrencies, markets, ongoingIcos, updatedAt

Prerequisites

  • No browser required — uses CoinGecko's public market-data endpoint

Notes

  • The public endpoint is rate-limited; retry briefly if you hit transient HTTP 429 responses
  • All numeric values are denominated in the selected --currency; coin fails fast if CoinGecko returns no market fields for that currency
  • change24hPct is a raw percent (e.g. 2.34 means +2.34%), not a fraction
  • --limit is validated upfront and rejected with ArgumentError if non-positive or above 250 (the CoinGecko per_page upper bound) — no silent clamp

Adapters Browser Confluence (`docs/adapters/browser/confluence.md`)

Confluence

Mode: 🔑 Atlassian REST API · Domain: configured with ATLASSIAN_CONFLUENCE_BASE_URL

Read, search, create, and update Confluence pages through Atlassian REST APIs. The adapter supports Confluence Cloud and Confluence Data Center without driving a browser session.

Commands

Command Description
opencli confluence page Page detail with storage and Markdown body
opencli confluence search <CQL> Search content with CQL
opencli confluence create Create a page from Markdown or storage XHTML
opencli confluence update Update a page body from Markdown or storage XHTML

Configuration

bash
export ATLASSIAN_CONFLUENCE_BASE_URL=https://example.atlassian.net/wiki
export ATLASSIAN_DEPLOYMENT=cloud      # cloud | datacenter | auto
export [email protected]
export ATLASSIAN_API_TOKEN=...

For Data Center, use a personal access token when available:

bash
export ATLASSIAN_CONFLUENCE_BASE_URL=https://confluence.example.com
export ATLASSIAN_DEPLOYMENT=datacenter
export ATLASSIAN_PAT=...

Cloud page reads and writes use Confluence REST API v2. CQL search is still exposed through Confluence REST API v1, so search intentionally uses the v1 search endpoint for both Cloud and Data Center.

Usage Examples

bash
# Read a page
opencli confluence page 123456 -f json

# Search pages in a space
opencli confluence search "type = page and title ~ \"RCA\"" --space ENG --limit 20 -f json

# Create a page from Markdown
opencli confluence create --space 987654 --title "PROJ-123 RCA" --file rca.md --execute

# Update an existing page
opencli confluence update 123456 --file rca.md --version-message "Sync from Jira PROJ-123" --execute

Write Safety

create and update require --execute. Without it, the adapter fails before sending a remote write.

For Cloud, --space expects a space id. For Data Center, --space expects a space key. --parent can be used to place a new page under an existing page id.

Input Formats

Markdown is the default input format:

bash
opencli confluence create --space 987654 --title "Runbook" --file runbook.md --execute

To provide Confluence storage XHTML directly:

bash
opencli confluence update 123456 --file page.storage.html --representation storage --execute

Notes

  • update reads the current page version first and submits version.number + 1.
  • Markdown conversion covers headings, paragraphs, links, inline code, code blocks, flat and nested lists, and basic tables.
  • Expected auth, rate-limit, version-conflict, argument, and not-found failures are normalized to CliError subclasses.

Adapters Browser Coupang (`docs/adapters/browser/coupang.md`)

Coupang

Mode: 🔐 Browser · Domain: coupang.com

Commands

Command Description
opencli coupang search Search Coupang products with logged-in browser session
opencli coupang product Read full product detail (price, rating, seller, delivery) for a product ID
opencli coupang add-to-cart Add a product to the logged-in account's shopping cart

Usage Examples

bash
# List rocket-shipping mice (rank, product_id, title, price, rating, ...)
opencli coupang search "마우스" --filter rocket --limit 10

# Round-trip: pick a product_id from search and pull full detail
opencli coupang product 7654321

# Pass a full product URL instead of an ID
opencli coupang product --url https://www.coupang.com/vp/products/7654321

# JSON output (any subcommand)
opencli coupang product 7654321 -f json

# Add to cart (write — must be logged in)
opencli coupang add-to-cart 7654321

Output

Column Type Notes
rank int 1-based position within this query / page
product_id string Numeric Coupang product id; round-trips into coupang product
title string Product display name
price int | null Current selling price (KRW)
unit_price string Per-unit price label, e.g. (100ml당 1,200원)
rating float | null Average star rating
review_count int | null Number of reviews
rocket string Coupang-rocket badge label (로켓배송 / 로켓와우 / etc.) — empty string if no badge
delivery_type string 무료배송 / 일반배송 / empty
delivery_promise string 오늘도착 / 내일도착 / 새벽도착 / empty
url string Canonical product URL

`product`

Always returns a single row (or throws):

Column Type Notes
product_id string Numeric Coupang product id, normalised from input
title string | null Product display name; null if upstream did not provide
price int | null Current selling price (KRW)
original_price int | null Pre-discount price
discount_rate int | null Discount percent
rating float | null Average star rating
review_count int | null Number of reviews
seller string | null Vendor / seller name
brand string | null Brand label (when listed)
rocket string | null Coupang-rocket type label
delivery_promise string | null Arrival-window label
image_url string | null Primary product image
url string Canonical product URL

null semantics: a null field means upstream did not expose that field on
this product (e.g. some items have no original_price). Failures (login wall,
page mismatch, page failed to render) raise typed errors instead of silently
returning empty rows — callers should treat any returned row as real data.

`add-to-cart`

Column Type Notes
ok bool Always true on success (failures throw)
product_id string Coupang product id added
url string Canonical product URL
message string Added to cart

Validation (no silent clamp)

search --limit must be 1..50; out-of-range values throw ArgumentError
(no silent clamp to 50). search --page must be a positive integer. search --filter currently only accepts rocket; any other value throws
ArgumentError rather than being silently dropped during DOM lookup.

Prerequisites

Notes

  • search and product use the logged-in browser session because Coupang's
    /np/search JSON endpoint and product pages serve different (and often
    empty) responses to anonymous traffic.
  • product's extractor tries three sources in order: JSON-LD Product schema,
    window.__INITIAL_STATE__ / __NEXT_DATA__ bootstrap globals, and finally
    a DOM fallback. The merged result is what's returned.
  • Authentication failures raise AuthRequiredError; missing/empty results
    raise EmptyResultError with a helpful hint. No command silently returns
    [] when login is the actual reason.

Adapters Browser Crates (`docs/adapters/browser/crates.md`)

crates.io

Mode: 🌐 Public · Domain: crates.io

Search and inspect crates on the public Rust crate registry. Both commands hit the unauthenticated crates.io/api/v1 directly.

Commands

Command Description
opencli crates search <query> Search the public crates.io registry by keyword
opencli crates crate <name> Single crate metadata (latest version, downloads, license, repo)

Usage Examples

bash
# Free-text search (name / keywords / description)
opencli crates search tokio --limit 10
opencli crates search "async runtime" --limit 20

# Single-crate detail (name from search rows)
opencli crates crate serde
opencli crates crate tokio

# JSON output
opencli crates search tokio -f json

Output Columns

Command Columns
search rank, name, latestVersion, description, downloads, recentDownloads, repository, updated, url
crate name, latestVersion, description, downloads, recentDownloads, versions, license, homepage, documentation, repository, keywords, categories, created, updated, url

The name column from search round-trips into crate.

Options

Option Description
query (positional) Free-text search query
--limit Max results (1–100, default: 20). 100 is crates.io's per-page upper bound.

`crate`

Option Description
name (positional) crates.io crate name (e.g. serde, tokio). Must match Rust's identifier rule.

Caveats

  • crates.io requires a descriptive User-Agent per the data-access policy. The adapter sets one automatically.
  • license is sourced from the latest version row in the package's version index — crate-level metadata does not carry a license field.
  • recentDownloads is the rolling 90-day count exposed by the API; downloads is the lifetime total.
  • keywords and categories are joined with , for display.

Prerequisites

  • No browser required — uses crates.io/api/v1.

Adapters Browser Ctrip (`docs/adapters/browser/ctrip.md`)

Ctrip (携程)

Mode: 🌐 Public (search, hotel-suggest) · 🖥️ Browser + Cookie (hotel-search, hotel, flight, flight-round, train, bus, ferry, cruise, tour, package, attraction)
Domain: ctrip.com

Public destination + hotel-context suggestion lookup against the
m.ctrip.com/restapi/soa2/21881/json/gaHotelSearchEngine endpoint plus
browser-driven hotel listing and one-way flight search on hotels.ctrip.com
and flights.ctrip.com.

Commands

Command Mode Description
opencli ctrip search Public Suggest cities, scenic spots, railway stations and landmarks
opencli ctrip hotel-suggest Public Suggest cities, business areas and individual hotels
opencli ctrip hotel-search Browser (cookie) List hotels for a city + check-in/out date range
opencli ctrip hotel Browser (cookie) Single-hotel detail: rating breakdown, facilities, check-in/out policy
opencli ctrip flight Browser (cookie) One-way flight search by IATA route + departure date
opencli ctrip flight-round Browser (cookie) Round-trip flight search by IATA route + depart/return dates
opencli ctrip train Browser (cookie) Train ticket search by station/city name + departure date
opencli ctrip bus Browser (cookie) Intercity coach ticket search by city name + departure date
opencli ctrip ferry Browser (cookie) Passenger ferry sailing search by city name + departure date
opencli ctrip cruise Browser (cookie) Cruise package search by departure port name
opencli ctrip tour Browser (cookie) Group / self-guided tour package search by destination keyword
opencli ctrip package Browser (cookie) Flight-plus-hotel (自由行) package search by destination keyword
opencli ctrip attraction Browser (cookie) Top attractions for a city id (rating, review count, detail link)

One-way flight loading

flight opens a foreground browser window by default because Ctrip can leave
background pages as skeleton placeholders. It reads the page's own batchSearch
responses without reconstructing or replaying requests, waits up to 25 seconds
for completed response bodies and the upstream completion flag, and combines
batches before returning rows. Visible DOM cards are not required for extraction.
A captcha, failed response or timeout is reported explicitly; an unfinished
search is never reported as an empty flight list.

Usage Examples

bash
# Destination suggest
opencli ctrip search 苏州 --limit 10

# Hotel-context suggest (cities / business areas / hotels)
opencli ctrip hotel-suggest 陆家嘴 --limit 5

# Hotel listing (city ID from `search` / `hotel-suggest`)
opencli ctrip hotel-search 2 --checkin 2026-05-20 --checkout 2026-05-21 --limit 10

# Single-hotel detail (hotel id from `hotel-suggest`)
opencli ctrip hotel 375539
opencli ctrip hotel 375539 -f json

# One-way flight search
opencli ctrip flight BJS SHA --date 2026-05-20 --limit 20

# Round-trip flight search (depart + return dates)
opencli ctrip flight-round SHA BJS --depart 2026-08-15 --return 2026-08-22 --limit 20

# Train ticket search (station or city names)
opencli ctrip train 北京 上海 --date 2026-05-20 --limit 20
opencli ctrip train 杭州 上海虹桥 --date 2026-05-20 -f json

# Intercity coach ticket search (city names)
opencli ctrip bus 北京 天津 --date 2026-05-20 --limit 20

# Passenger ferry search (city names)
opencli ctrip ferry 大连 烟台 --date 2026-05-20 --limit 20

# Cruise package search (departure port name)
opencli ctrip cruise 上海 --limit 20

# Tour package search (destination keyword)
opencli ctrip tour 北京 --limit 20

# Flight-plus-hotel package search (destination keyword)
opencli ctrip package 三亚 --limit 20

# Top attractions for a city (numeric city id from `ctrip search`, e.g. 1 for 北京)
opencli ctrip attraction 1 --limit 20

# JSON output
opencli ctrip search 上海 -f json

Suggest Columns (`search` / `hotel-suggest`)

Both suggest commands share a uniform column shape:

Column Notes
rank 1-based position in the upstream list
id Upstream entity id (round-trips into URL)
type Raw type tag (City / Markland / Hotel / BusinessArea / RailwayStation)
displayType Localised label (城市 / 地标 / 酒店 / 商圈 / 火车站)
name Localised display name
eName English name (may be empty)
cityId, cityName, provinceName, countryName Geo context
lat, lon Best-available coords (gaode → google → flat → null)
score First non-zero of commentScore / cStar; null if both unrated
url Canonical Ctrip URL or null if the entity type has no public web page

--limit accepts integers in [1, 50]. Out-of-range values raise
ArgumentError (no silent clamp).

Column Notes
rank 1-based position in upstream list
hotelId Round-trips into https://hotels.ctrip.com/hotels/detail/?hotelid=…
name, enName Localised + English (English may be null)
star 1-5, null for unrated / 客栈 entries
score, scoreLabel e.g. 4.8 / "超棒"; both null if unrated
reviewCount Integer parsed from "13,966条点评"
cityName, district, address Geo context
lat, lon WGS84 (1) > GCJ02 (2) > BD09 (3) selection; null if all are 0
price, currency First room's quote; null when no rooms remain at the searched date
url Canonical detail URL or null if hotelId is missing

Args:

  • <city> (positional, required) — numeric Ctrip city ID (discover via ctrip search / ctrip hotel-suggest).
  • --checkin, --checkout (required) — YYYY-MM-DD, validated as real calendar dates with checkin < checkout.
  • --limit (1-30, default 10) — Ctrip's SSR first page ships ~13 entries (10 organic + ~3 promoted). Larger limits are not currently supported because the server ignores the URL pageSize param.

Flight Columns (`flight`)

Column Notes
rank 1-based position after filtering incomplete rows
airline, flightNo, aircraft Free-text from the rendered card; flightNo and aircraft may be null (the current .flight-item cards often omit the flight number)
departureTime, arrivalTime HH:MM strings
departureAirport, arrivalAirport, terminal Airport names + optional T1/T2 chunk
price, currency, cabin First quoted fare; cabin is the Chinese suffix (e.g. 经济舱)
url The search URL (Ctrip's flight cards don't expose per-row stable deeplinks)

Args:

  • <from>, <to> (positional, required) — 3-letter IATA codes; BJS/SHA metro codes work alongside single-airport codes like PEK/PVG.
  • --date (required) — YYYY-MM-DD.
  • --limit (1-50, default 20).

Rows are extracted from the rendered .flight-item cards (Ctrip migrated the
flight list to these; they omit a text flight number, so flightNo is often
null) because Ctrip's post-load XHR is not currently captured by the daemon
network buffer (see "Caveats" below). Cards with missing departure/arrival/airline
are dropped rather than emitted with sentinel values.

Round-Trip Flight Columns (`flight-round`)

flight-round returns the outbound (去程) leg of a round-trip search with the
same column shape as flight (rank, airline, flightNo, aircraft,
departureTime, departureAirport, arrivalTime, arrivalAirport, terminal,
price, currency, cabin, url), read from the .flight-item cards on the
round-<from>-<to> results page.

Args:

  • <from>, <to> (positional, required): 3-letter IATA codes (BJS/SHA metro codes work alongside single-airport codes like PEK/PVG).
  • --depart, --return (required): YYYY-MM-DD, with return on or after depart.
  • --limit (1-50, default 20).

Two differences from the one-way list: price is the round-trip total (往返总价)
for the outbound flight shown, and the round-trip cards omit the flight number, so
flightNo and aircraft are usually null (never a sentinel). Picking the return
leg is a second step in Ctrip's flow and is out of scope here.

Train Columns (`train`)

Column Notes
rank 1-based position after filtering incomplete rows
trainNo Train number (G531 / D701 / K528); the .checi icon suffix is stripped
departureTime, arrivalTime HH:MM strings
departureStation, arrivalStation Station names (e.g. 北京南, 上海虹桥)
duration Trip length as shown (e.g. 5时56分); null if absent
fromPrice Lowest fare shown for the train as a number; null if non-numeric
seats Seat-class availability joined by / (e.g. 二等座有票 / 一等座17张 / 商务座(抢))
url The search URL (train rows share the list page, no per-row deeplink)

Args:

  • <from>, <to> (positional, required): Chinese station or city names (e.g. 北京 / 上海虹桥); the list page resolves them the same way the website search box does.
  • --date (required): YYYY-MM-DD.
  • --limit (1-50, default 20).

Rows come from .card-white.list-item cards, read by stable class-keyed
fields (.from/.mid/.to/.rbox/.surplus-list) rather than positional innerText.
Cards missing the train number or endpoint times are dropped rather than
emitted with sentinel values.

Bus Columns (`bus`)

Column Notes
rank 1-based position after filtering incomplete rows
departureTime HH:MM departure time
fromStation, toStation Departure and arrival coach stations
duration Trip length as shown (e.g. 约2时30分); null if absent
price Fare as a number; null if non-numeric
status Availability text (e.g. 暂停网售, or a remaining-ticket count)
url The results URL (coach rows share the list page, no per-row deeplink)

Args:

  • <from>, <to> (positional, required): Chinese city names (e.g. 北京 / 天津); the results page returns the station-level departures between them.
  • --date (required): YYYY-MM-DD.
  • --limit (1-50, default 20).

The bus.ctrip.com/ landing is a client-only SPA that does not hydrate under
the browser bridge, so the command navigates the results route directly via its
?param=<json> deep link. Coach rows arrive through the busListV2 XHR and are
read from .list-item-parent cards by stable utility-class fields rather than
positional innerText.

Ferry Columns (`ferry`)

Column Notes
rank 1-based position after filtering incomplete rows
shipName Vessel name (e.g. 渤海晶珠); null if absent
departureTime, arrivalTime HH:MM strings
fromPort, toPort Departure and arrival passenger ports
duration Trip length as shown (e.g. 6时30分); null if absent
price Lowest fare as a number; null if non-numeric
status Availability text (e.g. 选择舱位, 售罄)
url The results URL (sailings share the list page, no per-row deeplink)

Args:

  • <from>, <to> (positional, required): Chinese city names (e.g. 大连 / 烟台); the results page returns the port-level sailings between them.
  • --date (required): YYYY-MM-DD.
  • --limit (1-50, default 20).

Sibling of bus: the ship.ctrip.com/ landing is a client-only SPA that does
not hydrate under the browser bridge, so the command navigates the results route
directly via its ?param=<json> deep link. Sailings arrive through the
getShipLineV2 XHR and are read from .list-item-parent cards by stable
class-keyed fields rather than positional innerText.

Cruise Columns (`cruise`)

Column Notes
rank 1-based position after filtering incomplete rows
title Line, ship, and itinerary (e.g. MSC地中海邮轮·荣耀号·上海-那霸(冲绳)-上海·5天4晚)
star Product star rating (1-5); null if unrated
boarding Boarding / disembarking note (e.g. 上海登船/离船)
sailingDate Next recommended sailing date; null if absent
tags Feature tags joined by / (e.g. 免签 / 岸上游 / 船上餐饮)
price Lowest per-person fare as a number; null if non-numeric
url The port results URL (cruises share the list page, no per-row deeplink)

Args:

  • `` (positional, required): a departure cruise port name (e.g. 上海 / 威尼斯 / 罗马), matched against the ports Ctrip lists (上海 carries most China departures, plus international ports).
  • --limit (1-50, default 20).

Cruise results live on the legacy newpackage/search/sN.html pages keyed by an
opaque per-port code, so the command first loads the 上海 page (which lists every
port as a link) to resolve the requested port name to its code, then loads that
port's results and reads the .route_info cards. A listed port with no current
sailings raises EmptyResultError. River cruises (三峡) are a separate product
and out of scope.

Tour Columns (`tour`)

Column Notes
rank 1-based position after filtering incomplete rows
title Package title (e.g. 北京5日4晚跟团游)
subtitle Highlights line; null if absent
tags Feature tags joined by / (e.g. 0购物 / 成团保障 / 亲子甄选)
score Rating out of 5; null if unrated
sold Units sold as an integer (from 已售N); null if absent
reviews Review count as an integer; null if absent
price Lowest per-person fare as a number; null if non-numeric
url The search results URL (packages share the list page, no per-row deeplink)

Args:

  • <destination> (positional, required): a destination keyword (e.g. 北京 / 三亚 / 马尔代夫), passed to the vacations search as sv.
  • --limit (1-50, default 20).

Results render server-side into .list_product_item cards; the price / score /
sold fields lazy-load a moment after the titles, so the command waits until every
rendered card carries a price before reading. A destination with no packages
raises EmptyResultError.

Package Columns (`package`)

package searches the 自由行 (flight-plus-hotel) tab of the same vacations search
as tour and returns the identical column shape (rank, title, subtitle,
tags, score, sold, reviews, price, url); it differs only in the
product section (freetravel rather than whole).

Args:

  • <destination> (positional, required): a destination keyword (e.g. 三亚 / 北京 / 曼谷).
  • --limit (1-50, default 20).

Attraction Columns (`attraction`)

Column Notes
rank 1-based position in the rendered list
name Attraction name
rating Guest rating out of 5; null when the card lists only a review count
reviews Review count as an integer (19.7w / 1.3万 expanded to thousands); null if absent
url The attraction's you.ctrip.com/sight/<city>/.html detail page

Args:

  • <city> (positional, required): a numeric Ctrip city id (discover via ctrip search; e.g. 1 for 北京, 2 for 上海).
  • --limit (1-50, default 20).

The you.ctrip.com place page routes by the trailing numeric city id (redirecting
any slug to the canonical one) and lists a destination's top-rated attractions as
/sight/<city>/.html links carrying the name, rating, and review count. Rows
anchor on those stable links, deduped by sight id, and drop links without a name.
Per-attraction ticket prices sit on each sight's own detail page and are out of
scope here.

Hotel Detail Columns (`hotel`)

Column Notes
hotelId Echoes the requested id
name, enName Localised + English (English may be null)
star 1-5, null for unrated / 客栈 entries
score, scoreLabel Overall rating (e.g. 4.8 / "超棒"); both null if unrated
reviewCount Total review count as an integer
ratingBreakdown The four sub-scores joined by / (e.g. 卫生 4.8 / 设施 4.8 / 环境 4.8 / 服务 4.8)
facilities Hot facilities joined by / (e.g. 接机服务 / 无线WIFI免费 / 行李寄存)
checkInOut Check-in / check-out policy lines joined by /
cityName, address Geo context
lat, lon Coordinates from the detail page; null if absent
url Canonical detail URL

Args:

  • `` (positional, required): numeric Ctrip hotel id (discover via ctrip hotel-suggest; e.g. 375539).

The profile is read from __NEXT_DATA__.props.pageProps.hotelDetailResponse
(the same SSR source style as hotel-search), surfacing the fields the listing
row does not carry. Room-level nightly prices load via a post-SSR XHR and are
out of scope here, the same way flight's post-load price XHR is; hotel-search
already reports a representative nightly price per hotel.

Notes

  • Suggest endpoint discriminator: searchType=D (search) vs searchType=H
    (hotel-suggest). Hotel and BusinessArea rows only appear in the H flavour.
  • Mainland China suggest rows ship gdLat/gdLon (gaode). International rows
    ship gLat/gLon (wgs84). The adapter picks the first non-zero pair.
  • Suggest in-band Result: false envelopes are surfaced as COMMAND_EXEC
    typed errors; HTTP non-2xx becomes FETCH_ERROR.

Caveats (browser-mode commands)

  • Cookie required: hotel-search / flight use Strategy.COOKIE against
    hotels.ctrip.com / flights.ctrip.com. If Ctrip serves a captcha redirect
    (suspected bot), an AuthRequiredError is raised — complete the captcha in
    your live browser session and retry.
  • No per-flight deeplink: Ctrip's flight cards funnel every row through a
    shared booking handoff. Until a stable per-flight bookingId surfaces, all
    rows share the search URL.
  • Round-trip + airline-filter unsupported: flight is one-way only and
    passes cabin=Y_S_C_F (all cabins) in v1. Round-trip + advanced filters
    tracked in the #1481 follow-up.
  • Hotel SSR page size is server-fixed: passing &pageSize=N is ignored
    upstream — first page returns ~13 rows. Larger result sets would need
    scroll-paginated DOM extraction (not implemented in v1).

Adapters Browser Dblp (`docs/adapters/browser/dblp.md`)

dblp

Mode: 🌐 Public data via Browser Bridge · Domain: dblp.org

dblp is the comprehensive computer-science bibliography maintained by Schloss Dagstuhl, indexing 7M+ publications across conferences, journals, books, and theses. All four commands read the public XML APIs from a browser session. No DBLP account is required, but the site may require browser verification.

Commands

Command Description
opencli dblp search <query> Free-text search across titles, authors, and venues
opencli dblp author <name> List one author's recent publications (newest first) by name or --pid
opencli dblp paper <key> Fetch a single record's full metadata by canonical dblp key
opencli dblp venue <query> Search dblp's venue (conference / journal) registry

Usage Examples

bash
# Free-text search (matches title / author / venue)
opencli dblp search "attention is all you need" --limit 5

# Author search
opencli dblp search "Yoshua Bengio" --limit 20

# Newest publications by a specific author (resolves the dblp PID for you)
opencli dblp author "Yoshua Bengio" --limit 20

# Same call, but skip name resolution by supplying the PID directly
opencli dblp author --pid 56/953 --limit 20

# Venue search
opencli dblp search "ICLR 2024" --limit 30

# Single-record detail (round-trip from search.key)
opencli dblp paper conf/nips/VaswaniSPUJGKP17

# arXiv mirror records use the journals/corr/abs-* form
opencli dblp paper journals/corr/abs-2509-05821

# Resolve a venue acronym to dblp's canonical venue page
opencli dblp venue ICLR --limit 5

# Browse venues that match a topic keyword
opencli dblp venue "neural networks" --limit 10

# JSON output
opencli dblp search "graph neural network" -f json

Output Columns

Command Columns
search rank, key, title, authors, venue, year, type, doi, url
author rank, key, title, authors, venue, year, type, doi, pid, url
paper key, type, title, authors, venue, year, pages, doi, open_access_url, dblp_url
venue rank, acronym, venue, type, url

The key column from search and author round-trips into paper — it is dblp's canonical record identifier (e.g. conf/nips/VaswaniSPUJGKP17, journals/corr/abs-2509-05821, phd/Smith20).

The pid column on author is dblp's stable per-author identifier (e.g. 56/953 for Yoshua Bengio). Pass it back with --pid to skip name resolution on subsequent calls.

Type Tag

The type column is a single-token simplification of dblp's verbose type strings:

Tag Source
conf Conference and Workshop Papers (``)
journal Journal Articles (<article>)
book Books and Theses
editorship Proceedings volumes
reference Reference Works
preprint Informal / Other Publications (CoRR, etc.)
incollection / phdthesis / mastersthesis (paper command only — kept distinct in the XML record)

Caveats

  • dblp does not expose abstracts via either endpoint. For the abstract, follow open_access_url (when present), doi, or pipe the title into arxiv search / openreview search.
  • Author names occasionally carry dblp's per-author homonym suffix ("Smith 0001"). The adapter strips trailing 4+ digit groups so you get clean Author, Author strings.
  • Search results include CoRR / arXiv mirror entries. These have keys like journals/corr/abs-2509-05821 and round-trip cleanly into paper.
  • dblp throttles aggressive clients. If you hit HTTP 429, wait a few seconds and lower --limit (max 100 per page).

Prerequisites

  • A connected Browser Bridge or supported direct CDP browser is required.
  • The adapter opens https://dblp.org and allows up to 15 seconds for normal page verification to settle. If verification remains, it returns SECURITY_BLOCK; resolve it in your browser before retrying.
  • API requests use XML in the same browser session. Challenge HTML, unexpected redirects and malformed XML are errors, not empty results. HTTP 429 stops without an automatic request retry.

Adapters Browser Deepseek (`docs/adapters/browser/deepseek.md`)

DeepSeek

Mode: Browser · Domains: chat.deepseek.com, platform.deepseek.com

Commands

Command Description
opencli deepseek ask Send a prompt and get the response
opencli deepseek new Start a new conversation
opencli deepseek status Check login state and page availability
opencli deepseek usage Read DeepSeek platform balance, spending, API request, and token usage
opencli deepseek read Read the current conversation
opencli deepseek history List conversation history from sidebar
opencli deepseek detail Read a specific conversation by ID or URL
opencli deepseek send Send a prompt to a specific conversation without waiting for a response

Usage Examples

bash
# Ask a question
opencli deepseek ask "explain quicksort in 3 sentences"

# Start a new chat before asking
opencli deepseek ask "hello" --new

# If DeepSeek offers model selection, choose Expert
opencli deepseek ask "prove that sqrt(2) is irrational" --model expert

# If DeepSeek offers model selection, choose Vision for an image
opencli deepseek ask "describe this image" --model vision --file ./image.png

# Enable DeepThink mode
opencli deepseek ask "prove that sqrt(2) is irrational" --think

# Enable web search
opencli deepseek ask "latest news about AI" --search

# Attach a file
opencli deepseek ask "summarize this document" --file ./report.pdf

# Combine DeepThink, web search, and a new chat
opencli deepseek ask "what happened today?" --think --search --new

# Custom timeout (default: 120s)
opencli deepseek ask "write a long essay" --timeout 180

# JSON output
opencli deepseek ask "hello" -f json

# Check login status
opencli deepseek status

# Read platform usage and balance
opencli deepseek usage

# Start a fresh conversation
opencli deepseek new

# Read current conversation
opencli deepseek read

# List recent conversations
opencli deepseek history --limit 10

# Read a specific conversation by UUID or /a/chat/s/<id> URL
opencli deepseek detail 749e6bbd-6a45-4440-beaa-ae5238bf06d8

# Send to a specific existing conversation
opencli deepseek send 749e6bbd-6a45-4440-beaa-ae5238bf06d8 "continue from the last answer"

Options (ask)

Option Description
`` The message to send (required, positional)
--timeout Wait timeout in seconds (default: 120)
--new Start a new chat before sending (default: false)
--model Explicitly select instant, expert, or vision when the DeepSeek UI offers model selection; omitted by default
--think Enable DeepThink mode (default: false)
--search Enable web search (default: false)
--file Attach a file (PDF, image, text) with the prompt (max 100 MB)

Options (detail)

Option Description
`` DeepSeek conversation UUID or full /a/chat/s/ URL

Options (send)

Option Description
`` DeepSeek conversation UUID or full /a/chat/s/ URL
`` The message to send (required, positional)

Prerequisites

Caveats

  • This adapter drives the DeepSeek web UI in the browser, not an API
  • DeepSeek commands default to persistent site sessions, so consecutive deepseek ask / deepseek read / deepseek detail invocations continue in the same DeepSeek page. Pass --site-session ephemeral for a one-shot tab.
  • usage navigates to the DeepSeek platform usage page and reads the account summary API plus visible usage period cards; missing auth, blocked API responses, or malformed page/API shapes are typed failures.
  • Without --model, ask uses DeepSeek's current default and does not require a model selector, including with --new. Explicit --model requires DeepSeek to offer model selection.
  • DeepThink and Search are synced on every invocation, so omitting either flag disables that feature
  • Expert and Vision modes do not support --search; omit --model to use DeepSeek's default for web search
  • send requires an explicit conversation ID; use history to find a conversation URL or ID first
  • Long responses (code, essays) may need a higher --timeout
  • File upload prefers the browser file-input path, falls back to base64 injection when needed, and rejects files over 100 MB

Adapters Browser Defillama (`docs/adapters/browser/defillama.md`)

DefiLlama

Mode: 🌐 Public · Domain: defillama.com

Browse top DeFi protocols by TVL and fetch detailed protocol metadata. Both commands hit the unauthenticated api.llama.fi directly.

Commands

Command Description
opencli defillama protocols Top DeFi protocols by current TVL (slug, name, category, TVL, mcap, change, chains)
opencli defillama protocol <slug> Single protocol details (current TVL, mcap, chains, twitter, github, description)

Usage Examples

bash
# Top 30 protocols by TVL (default)
opencli defillama protocols

# Top 100, JSON output
opencli defillama protocols --limit 100 -f json

# Single protocol details (slug from protocols rows)
opencli defillama protocol aave-v3
opencli defillama protocol lido

# Parent protocols (e.g. "aave") aggregate their children's chains
opencli defillama protocol aave

Output Columns

Command Columns
protocols rank, slug, name, category, tvl, mcap, change_1d, change_7d, chains, listedAt, url
protocol slug, name, category, isParent, tvl, tvlAt, mcap, chains, twitter, github, audits, listedAt, description, website, url

The slug column from protocols round-trips into protocol.

Options

`protocols`

Option Description
--limit Number of rows to return (1–500, default: 30). DefiLlama lists ~7400 protocols total.

`protocol`

Option Description
slug (positional) DefiLlama protocol slug (e.g. aave-v3, lido, pancakeswap-amm)

Notes

  • TVL is in USD. tvl and mcap are scalar floats; consumers should format as money.
  • Parent vs child protocols. "Parent" entries (isParent=true, e.g. aave covers aave-v3, aave-v2, etc.) are present on protocol but not on protocols. The adapter aggregates child chains so parents still surface a useful chains value.
  • change_1d / change_7d are percentages (already as percent, e.g. 0.84 = +0.84%).
  • No API key required. DefiLlama throttles unauthenticated traffic; an HTTP 429 surfaces as CommandExecutionError.
  • Errors. Bad slug → ArgumentError; unknown slug → EmptyResultError (DefiLlama returns HTTP 400 "Protocol not found" which is normalised); other 4xx/5xx → CommandExecutionError.

Adapters Browser Devto (`docs/adapters/browser/devto.md`)

Dev.to

Mode: 🌐 Public · Domain: dev.to

Fetch the latest and greatest developer articles from the DEV community without needing an API key.

Commands

Command Description
opencli devto top Top DEV.to articles of the day
opencli devto latest Latest published articles across all tags (paginated)
opencli devto tag <tag> Latest articles for a specific tag
opencli devto user Recent articles from a specific user
opencli devto read Read the body of a single article

Listing columns

top, latest, tag, and user all surface the same agent-native columns so the
article id is round-trippable into devto read:

Column Source Notes
rank local 1-indexed position in the result
id item.id Numeric article id, feed into devto read
title item.title
author item.user.username (omitted for user since it's user-scoped)
reactions item.public_reactions_count
comments item.comments_count
reading_time item.reading_time_minutes Minutes
published_at item.published_at ISO 8601 timestamp
tags item.tag_list Comma-separated
url item.url Canonical article URL

`read` columns

devto read returns a single row with the article body. DEV.to's public API
does not expose article comments, so this reader does not emit a comment tree.

Column Source
id article.id
title article.title
author article.user.username
reactions article.public_reactions_count
reading_time article.reading_time_minutes
tags article.tag_list (joined)
published_at article.published_at
body article.body_markdown (truncated by --max-length)
url article.url

Usage Examples

bash
# Top articles today
opencli devto top --limit 5

# Latest published articles (newest first; supports --page for pagination)
opencli devto latest --limit 20
opencli devto latest --limit 20 --page 2

# Articles by tag (positional argument)
opencli devto tag javascript
opencli devto tag python --limit 20

# Articles by a specific author
opencli devto user ben
opencli devto user thepracticaldev --limit 5

# Read a single article body by id
opencli devto read 3605688
opencli devto read 3605688 --max-length 5000

# JSON output
opencli devto top -f json
opencli devto read 3605688 -f json

Prerequisites

  • No browser required — uses the public DEV.to API

Adapters Browser Dianping (`docs/adapters/browser/dianping.md`)

dianping

Mode: 🔐 Browser · Domain: www.dianping.com

Commands

Command Description
opencli dianping search "<keyword>" --city <name-or-id> --limit <n> Search shops/restaurants on www.dianping.com
opencli dianping shop <shop_id> Read shop detail by shop id (alias: detail)

Usage Examples

bash
# Search "火锅" in 北京 (top 5 results, table view)
opencli dianping search 火锅 --city beijing --limit 5

# JSON output
opencli dianping search 火锅 --city 北京 --limit 5 -f json

# Search using a numeric cityId (path segment in dianping URLs)
opencli dianping search 火锅 --city 2

# Search using the cookie's currently-selected city (omit --city)
opencli dianping search 火锅

# Read a shop detail by id
opencli dianping shop GxJZ4urc9TnKE3kY

# `detail` alias works the same way
opencli dianping detail GxJZ4urc9TnKE3kY -f json

# Pass a full /shop/<id> URL — the id segment is auto-extracted
opencli dianping shop https://www.dianping.com/shop/GxJZ4urc9TnKE3kY

Prerequisites

  • Chrome running and logged into dianping.com
  • Browser Bridge extension installed
  • The PC site (www.dianping.com) is the primary target. The mobile site
    (m.dianping.com) is intentionally crippled for non-mobile UAs and is not
    used by these adapters.

Notes

  • search --limit is between 1 and 15 (dianping fixed page size). Default is 15.
  • --city accepts a Chinese name (北京/上海), pinyin (beijing/shanghai),
    or a numeric cityId. When omitted, the cookie's currently-selected city is
    used.
  • search columns: rank, shop_id, name, rating, reviews, price, cuisine, district, url.
    shop_id round-trips into dianping shop.
  • shop returns a field, value sheet so missing fields surface as null
    rather than fabricated values. The phone number is intentionally hidden on
    the PC web (only revealed in the native app), so it is not included.

Troubleshooting

  • If you hit a captcha redirect to verify.meituan.com (icon-tap challenge),
    the adapter will throw AUTH_REQUIRED with the captcha URL. Open the URL
    manually in the same Chrome profile, solve the captcha, then retry.
  • If dianping shop fails with EMPTY_RESULT, the shop may have been removed
    or relocated; verify the id by visiting https://www.dianping.com/shop/
    in the browser.
  • If dianping search returns zero rows, try a more specific keyword or a
    different city — dianping's search is keyword-coverage dependent.

Adapters Browser Dictionary (`docs/adapters/browser/dictionary.md`)

Dictionary

Mode: 🌐 Public · Domain: api.dictionaryapi.dev

Search the open dictionary to quickly fetch native definitions, part of speech contexts, and phonetic pronunciations directly in your IDE terminal.

Commands

Command Description
opencli dictionary search Fetch the exact definition of a word
opencli dictionary synonyms Find related synonyms for a word
opencli dictionary examples Read real-world sentence usage examples

Usage Examples

bash
# Look up a complex term
opencli dictionary search serendipity

# Discover phonetics
opencli dictionary search ephemeral

Prerequisites

  • No browser required — utilizes the fast, open JSON definitions API.

Adapters Browser Dockerhub (`docs/adapters/browser/dockerhub.md`)

Docker Hub

Mode: 🌐 Public · Domain: hub.docker.com

Search and inspect public Docker Hub repositories without auth or browser. Two commands cover discovery and per-repository metadata.

Commands

Command Description
opencli dockerhub search <query> Search Docker Hub repositories by keyword
opencli dockerhub image <name> Repository metadata (stars, pulls, last updated, status)

Usage Examples

bash
# Search repositories
opencli dockerhub search nginx --limit 10
opencli dockerhub search "bitnami redis" --limit 5

# Single repository metadata (use `image` from search rows)
opencli dockerhub image nginx              # implicit `library/nginx`
opencli dockerhub image library/nginx
opencli dockerhub image bitnami/redis

# JSON output
opencli dockerhub search nginx -f json
opencli dockerhub image nginx -f json

Output Columns

Command Columns
search rank, image, official, stars, pulls, description, url
image image, official, stars, pulls, description, lastUpdated, lastModified, registered, status, url

The image column from search round-trips into image exactly. Bare repository names (e.g. nginx) resolve to the implicit library owner that Docker Hub uses for official images.

Options

Option Description
query (positional) Search keyword
--limit Max repositories (1-100, default: 25)

`dockerhub image`

Option Description
image (positional) Repository slug (nginx, library/nginx, bitnami/redis)

Caveats

  • Image slugs are validated upfront against Docker Hub's [a-z0-9][a-z0-9._-]* pattern (2-255 chars). Bad input raises ArgumentError.
  • Anonymous traffic is throttled. HTTP 429 surfaces as a typed CommandExecutionError with a retry hint.
  • Timestamp columns (lastUpdated, lastModified, registered) are normalized to second-precision YYYY-MM-DDTHH:MM:SSZ.

Prerequisites

  • No browser required — uses hub.docker.com/v2/search/repositories/ and hub.docker.com/v2/repositories/<owner>/<name>/.

Adapters Browser Dongchedi (`docs/adapters/browser/dongchedi.md`)

懂车帝 Dongchedi

Mode: 🌐 Public · Domain: dongchedi.com

No login, no cookies, no signature. Every command does a plain HTTP GET of a
server-rendered page and parses the __NEXT_DATA__ JSON embedded in the HTML,
so it works out of the box.

Commands

Command Description
opencli dongchedi search <keyword> Search car series by keyword → series + 指导价/经销商价
opencli dongchedi series <series_id> Series overview: brand, prices, 懂车分, sales rank, trim count
opencli dongchedi models <series_id> Trims (款型) with guide / dealer / owner prices
opencli dongchedi specs <series_id> Config overview: dimensions, powertrain, drivetrain, airbags
opencli dongchedi score <series_id> 懂车分 rating — 8 axes vs same-class average
opencli dongchedi koubei <series_id> Owner reviews (口碑): rating, trim bought, likes, full text

series, models, specs, score, and koubei all take a series_id —
get one from search (the series_id column) or paste a
https://www.dongchedi.com/auto/series/ URL.

Usage Examples

bash
# Find a car series
opencli dongchedi search "宝马X5" --limit 5
opencli dongchedi search "汉兰达"

# One series at a glance (prices + 懂车分 + ranks)
opencli dongchedi series 5273

# Trims and their prices
opencli dongchedi models 5273
opencli dongchedi models 5273 --status offline   # discontinued trims

# Key configuration overview
opencli dongchedi specs 5273

# Rating breakdown vs same-class average
opencli dongchedi score 5273

# Owner reviews (full body in the content column)
opencli dongchedi koubei 5273 --limit 10

# JSON output
opencli dongchedi search "汉兰达" -f json

Output Columns

Command Columns
search rank, series_id, name, brand, official_price, dealer_price, pictures, url
series field, value (series_id, name, brand, sub_brand, official_price, dealer_price, used_price, score, review_count, sale_rank, score_rank, models, url)
models car_id, name, year, official_price, dealer_price, owner_price
specs field, value (dimensions, wheelbase, power, engine, gearbox, energy, acceleration, drivetrain, suspension, airbags)
score dimension, score, same_level_avg
koubei rank, user, car, score, likes, comments, content, url

Scores are rescaled to a 0–5 float (Dongchedi stores them as x100 ints; 422 → 4.22).

Notes & Limits

  • Why SSR, not the JSON API: Dongchedi's /motor/... XHR endpoints are
    ByteDance-signature gated (a_bogus / X-Bogus) and 404 without a valid
    signature. The SSR pages expose the same data unsigned, so this adapter reads
    those instead — no signature replication, no breakage when the signing scheme
    rotates.
  • specs is the overview, not the full parameter sheet. The complete
    per-trim parameter table lives behind a signed XHR; rather than fabricate it,
    specs returns the unsigned SSR overview (dimensions, powertrain, drivetrain,
    suspension, airbags). For per-trim names/prices use models.
  • koubei is a single SSR page (up to ~15 reviews). Deep pagination uses the
    signed API and is intentionally not implemented.

Prerequisites

None — public site, no authentication required.


Adapters Browser Douban (`docs/adapters/browser/douban.md`)

豆瓣 (Douban)

Mode: 🔐 Browser (Cookie) · Domain: douban.com

Commands

Command Description
opencli douban search 搜索豆瓣电影、图书或音乐
opencli douban top250 豆瓣电影 Top 250
opencli douban subject 条目详情
opencli douban photos 获取电影海报/剧照图片列表
opencli douban download 下载电影海报/剧照图片
opencli douban marks 我的标记
opencli douban reviews 我的短评
opencli douban movie-hot 豆瓣电影热门榜单
opencli douban book-hot 豆瓣图书热门榜单

Usage Examples

bash
# 搜索电影
opencli douban search "流浪地球"

# 搜索图书
opencli douban search --type book "三体"

# 搜索音乐
opencli douban search --type music "周杰伦"

# 电影 Top 250
opencli douban top250 --limit 10

# 电影详情
opencli douban subject 1292052

# 图书详情
opencli douban subject 2567698 --type book
opencli douban subject 2567698 --type book -f json

# 获取海报直链(默认 type=Rb)
opencli douban photos 30382501 --limit 20

# 下载海报到本地目录
opencli douban download 30382501 --output ./douban

# 只下载指定 photo_id 的一张图
opencli douban download 30382501 --photo-id 2913621075 --output ./douban

# 返回 JSON,便于上层界面直接渲染图片并右键取图
opencli douban photos 30382501 -f json

# 电影热门
opencli douban movie-hot --limit 10

# 图书热门
opencli douban book-hot --limit 10

# JSON output
opencli douban top250 -f json

Prerequisites

  • Chrome logged into douban.com
  • Browser Bridge extension installed

图书搜索和图书详情在稳定批量使用时默认需要已登录的豆瓣浏览器会话。


Adapters Browser Doubao (`docs/adapters/browser/doubao.md`)

doubao

Browser adapter for Doubao Chat.

Commands

Command Description
opencli doubao status Check whether the page is reachable and whether Doubao appears logged in
opencli doubao new Start a new Doubao conversation
opencli doubao send "..." Send a message to the current Doubao chat
opencli doubao read Read the visible Doubao conversation
opencli doubao ask "..." Send a prompt and wait for a reply
opencli doubao detail 对话详情
opencli doubao history 历史对话列表
opencli doubao meeting-summary 会议总结
opencli doubao meeting-transcript 会议记录

Prerequisites

  • Chrome is running
  • You are already logged into doubao.com
  • Browser Bridge extension is installed and enabled for OpenCLI

Examples

bash
opencli doubao status
opencli doubao new
opencli doubao send "帮我总结这段文档"
opencli doubao read
opencli doubao ask "请写一个 Python 快速排序示例" --timeout 90

Notes

  • The adapter targets the web chat page at https://www.doubao.com/chat
  • Doubao commands default to persistent site sessions, so consecutive doubao ask / doubao read / doubao detail invocations continue in the same Doubao page. Pass --site-session ephemeral for a one-shot tab.
  • new first tries the visible "New Chat / 新对话" button, then falls back to the new-thread route
  • ask uses DOM polling, so very long generations may need a larger --timeout

Adapters Browser Douyin (`docs/adapters/browser/douyin.md`)

Douyin (抖音创作者中心)

Mode: 🔐 Browser · Domain: creator.douyin.com

Commands

Command Description
opencli douyin detail <target> 单条视频或图文详情(ID、HTTPS 视频链接或分享短链)
opencli douyin profile 获取账号信息
opencli douyin videos 获取作品列表
opencli douyin drafts 获取草稿列表
opencli douyin draft 上传视频并保存为草稿
opencli douyin publish 定时发布视频到抖音
opencli douyin update 更新视频信息
opencli douyin delete 删除作品
opencli douyin stats 查询作品数据分析
opencli douyin collections 获取合集列表
opencli douyin activities 获取官方活动列表
opencli douyin location 搜索发布可用的地理位置
opencli douyin hashtag search 按关键词搜索话题
opencli douyin hashtag suggest 基于封面 URI 推荐话题
opencli douyin hashtag hot 获取热点词

Usage Examples

bash
# 账号与作品
opencli douyin profile
opencli douyin videos --limit 10
opencli douyin videos --status scheduled
opencli douyin drafts

# 发布前辅助信息
opencli douyin collections
opencli douyin activities
opencli douyin location "东京塔"
opencli douyin hashtag search "春游"
opencli douyin hashtag hot --limit 10

# 保存草稿
opencli douyin draft ./video.mp4 \
  --title "春游 vlog" \
  --caption "#春游 先存草稿"

# 定时发布
opencli douyin publish ./video.mp4 \
  --title "春游 vlog" \
  --caption "#春游 今天去看樱花" \
  --schedule "2026-04-08T12:00:00+09:00"

# 也支持 Unix 秒字符串
opencli douyin publish ./video.mp4 \
  --title "春游 vlog" \
  --schedule 1775617200

# 更新与删除
opencli douyin update 1234567890 --caption "更新后的文案"
opencli douyin update 1234567890 --reschedule "2026-04-09T20:00:00+09:00"
opencli douyin delete 1234567890

# JSON 输出
opencli douyin profile -f json

Prerequisites

  • Chrome running and logged into creator.douyin.com
  • The logged-in account must have access to Douyin Creator Center publishing features
  • Browser Bridge extension installed

Notes

  • publish requires --schedule to be at least 2 hours later and no more than 14 days later
  • draft and publish upload the video through Douyin/ByteDance browser-authenticated APIs, so cookies in the active browser session must be valid
  • hashtag suggest expects a valid cover/cover_uri value produced during the publish pipeline; for normal manual use, hashtag search and hashtag hot are usually more convenient

Public content details

opencli douyin detail <target> -f json uses your browser session on www.douyin.com. It returns the caption, author and sec_uid, engagement counts, UTC creation time, duration, music, media URLs and image list. The target accepts a 16–20 digit ID, a Douyin video URL, or an HTTPS v.douyin.com share URL. Short links follow at most six redirects within known Douyin domains. Deleted, restricted, mismatched and failed API responses produce explicit errors. Media URLs may expire.


Adapters Browser Dribbble (`docs/adapters/browser/dribbble.md`)

Dribbble

Mode: 🌐 Browser · Domain: dribbble.com

Commands

Command Description
opencli dribbble shot <query> Search shots by keyword
opencli dribbble shot-detail <shot> Show one shot's authorship, media, palette, and availability
opencli dribbble designer Browse designers and agencies
opencli dribbble profile <designer> Show a designer's public profile and about fields
opencli dribbble portfolio <designer> List a designer's published or liked shots
opencli dribbble service <designer> List and filter a designer's services
opencli dribbble collection <designer> List a designer's public collections
opencli dribbble member <designer> List a team profile's public members
opencli dribbble whoami Show the signed-in Dribbble identity
opencli dribbble login Open Dribbble's sign-in flow

Usage Examples

bash
# Search Dribbble's public popular or New & Noteworthy views
opencli dribbble shot "mobile ui" --sort popular --limit 10 -f json
opencli dribbble shot "mobile ui" --sort recent --limit 10 -f json

# The personalized Following view requires a signed-in browser session
opencli dribbble shot "mobile ui" --sort following --limit 10 -f json

# Inspect a shot and a designer's public surfaces
opencli dribbble shot-detail 27679566 -f json
opencli dribbble profile halolab -f json
opencli dribbble portfolio halolab --type work --limit 10 -f json
opencli dribbble service halolab --query branding --limit 10 -f json
opencli dribbble collection halolab --limit 10 -f json
opencli dribbble member halolab --limit 10 -f json

# Browse designers and verify authentication
opencli dribbble designer --query product --limit 10 -f json
opencli dribbble whoami -f json

shot-detail accepts either a numeric shot id or a full dribbble.com/shots/... URL. Designer arguments are Dribbble usernames or profile slugs. List limits must be positive integers and cannot exceed 30.

For portfolio --type likes, designer identifies each shot's author, not the profile that liked it. It remains empty when Dribbble omits the author label; OpenCLI does not guess ownership.

Output

Shot commands return stable identity and URL fields plus the metadata visible on Dribbble, such as author, likes, views, media URLs, palette, or work availability. Profile output includes biography, counts, location, membership date, skills, languages, social links, website, and avatar. The remaining list commands preserve rank plus the visible identity and metadata for each service, collection, or team member.

Public reads use Dribbble's server-rendered browser pages. Direct HTTP requests are challenged by AWS WAF, and the official Dribbble API requires a separate OAuth application and token, so the adapter does not depend on a private web API.

Prerequisites

  • Chrome running with the Browser Bridge extension installed
  • A Dribbble login only for whoami, login, and shot --sort following

Adapters Browser Duckduckgo (`docs/adapters/browser/duckduckgo.md`)

DuckDuckGo

Mode: 🌐 Public · Domains: html.duckduckgo.com, duckduckgo.com

Commands

Command Description
opencli duckduckgo search <keyword> Search DuckDuckGo and extract results from the page
opencli duckduckgo suggest <keyword> Get DuckDuckGo search suggestions

What works today

  • duckduckgo search uses browser mode to search html.duckduckgo.com and extract ranked results.
  • duckduckgo suggest uses the public JSON API at duckduckgo.com/ac/ — no browser needed.
  • search supports --region (e.g. jp-jp, us-en, cn-zh) and --time (d, w, m, y) filters.
  • search supports --offset for pagination via XHR POST (avoids page navigation issues with form.submit()).

Current limitations

  • duckduckgo search requires browser mode due to anti-bot protections on DuckDuckGo.
  • The HTML version returns a maximum of 10 results per page; --limit must be between 1 and 10.
  • Pagination uses POST-based navigation; results may have some overlap at page boundaries.
  • Snippet extraction is based on the HTML version's DOM structure (.result__snippet).

Usage Examples

bash
# Basic search
opencli duckduckgo search "machine learning"

# Limit results
opencli duckduckgo search "machine learning" --limit 5

# Region-specific search
opencli duckduckgo search "machine learning" --region jp-jp

# Time filter (past week)
opencli duckduckgo search "machine learning" --time w

# Pagination (second page)
opencli duckduckgo search "machine learning" --offset 10

# JSON output
opencli duckduckgo search "machine learning" -f json

# Search suggestions
opencli duckduckgo suggest "machine" --limit 5

Prerequisites

  • suggest does not require Chrome.
  • search requires Chrome running (Standalone mode will auto-launch) or the Browser Bridge extension.

Notes

  • DuckDuckGo uses uddg= URL redirects; the adapter automatically decodes them to return clean URLs.
  • The ac/ suggest API returns phonetic suggestions for CJK queries, which may not always match expected results.
  • Region codes follow DuckDuckGo's format (e.g. jp-jp, us-en, uk-en). Default is all regions.

Adapters Browser Eastmoney (`docs/adapters/browser/eastmoney.md`)

Eastmoney

Mode: 🔐 Browser · Domain: guba.eastmoney.com

Access 东方财富 (Eastmoney) stock-market data from the terminal.

Commands

Command Description
opencli eastmoney hot-rank 东方财富热股榜 (Eastmoney hot-stock ranking)

Usage Examples

bash
# Top 20 hot stocks (default)
opencli eastmoney hot-rank

# Top 50 hot stocks
opencli eastmoney hot-rank --limit 50

# JSON output
opencli eastmoney hot-rank -f json

Options

Option Default Description
--limit 20 返回数量 (number of rows to return)

Output Columns

rank · symbol · name · price · changePercent · heat · url

Prerequisites

  • Chrome extension installed and connected
  • Visit guba.eastmoney.com once in the browser so cookies are populated

Adapters Browser Endoflife (`docs/adapters/browser/endoflife.md`)

endoflife.date

Mode: 🌐 Public · Domain: endoflife.date

Look up release cycles and end-of-life / LTS / support dates for hundreds of products (Node.js, Python, Ubuntu, Java, Postgres, Kubernetes, etc.). Hits the unauthenticated endoflife.date/api directly.

Commands

Command Description
opencli endoflife product <name> Release cycles + EOL / LTS / support dates for one product

Usage Examples

bash
# Node.js cycles (newest first)
opencli endoflife product nodejs

# Python, JSON output for scripts
opencli endoflife product python -f json

# Ubuntu LTS schedule
opencli endoflife product ubuntu

Output Columns

Command Columns
product product, cycle, releaseDate, latest, latestReleaseDate, lts, support, eol, extendedSupport, eolStatus, url

Options

`product`

Option Description
product (positional) endoflife.date product slug (e.g. nodejs, python, ubuntu, kubernetes)

Notes

  • eolStatus is a derived projection (active / eol / ongoing / null) computed against today's UTC date — agents can answer "is this version still supported?" without parsing dates.
  • Boolean dates → strings. endoflife.date sometimes ships true for "ongoing support" / false for "no LTS". The adapter normalises:
    • true → "ongoing"
    • false / null → null
    • ISO date string → returned as-is
  • No API key required. Slugs are exactly what appears at https://endoflife.date/.
  • Errors. Bad slug shape → ArgumentError; unknown product → EmptyResultError (HTTP 404); rate-limited → CommandExecutionError.

Adapters Browser Facebook (`docs/adapters/browser/facebook.md`)

Facebook

Mode: 🔐 Browser · Domain: facebook.com

Commands

Command Description
opencli facebook profile Get user/page profile info
opencli facebook notifications Get recent notifications with unread / time / url / notif_id / notif_type
opencli facebook feed Get news feed posts
opencli facebook search Search people, pages, posts
opencli facebook marketplace-listings List your Marketplace seller listings
opencli facebook marketplace-inbox List recent Marketplace buyer/seller conversations

Usage Examples

bash
# View a profile
opencli facebook profile zuck

# Get notifications (default 15, max 100)
opencli facebook notifications --limit 10

# News feed
opencli facebook feed --limit 5

# Search
opencli facebook search "OpenAI" --limit 5

# Marketplace seller listings and inbox
opencli facebook marketplace-listings --limit 10
opencli facebook marketplace-inbox --limit 10

# JSON output
opencli facebook profile zuck -f json

Output

`notifications`

Column Type Notes
index int 1-based row number across the returned page
unread bool Derived from the explicit 未读 / Unread badge child; falls back to the anchor text prefix
text string Notification body text. Read first from the per-row "Mark as read" button's aria-label (with the locale prefix stripped) so it does not include the unread badge or trailing time. Full body, no silent truncation
time string | null Time-ago label from the row's <abbr>, e.g. 2天 / 5 hrs. null when the abbr is missing — never the legacy '-' sentinel
url string Full notification anchor href, including notif_id / notif_t query params, so callers can follow up
notif_id string | null notif_id query param parsed from url; null when absent
notif_type string | null notif_t query param (e.g. onthisday, approve_from_another_device, group_recommendation); null when absent

--limit accepts a positive integer in [1, 100]. Out-of-range or
non-numeric input raises ArgumentError upfront — no silent clamp.

If Facebook redirects to a login/checkpoint path (for example
/login.php, /login/identify/, or /checkpoint/; session expired)
the command raises AuthRequiredError. An empty notification list after
a successful auth check raises EmptyResultError instead of a silent
[].

Prerequisites


Adapters Browser Flathub (`docs/adapters/browser/flathub.md`)

Flathub

Mode: 🌐 Public · Domain: flathub.org

Search the Flathub Linux flatpak app registry and fetch full appstream metadata for any app. Flathub is the canonical flatpak distribution channel for Linux desktop applications.

Commands

Command Description
opencli flathub search <query> Search Flathub apps by keyword
opencli flathub app <appId> Full Flathub appstream metadata for an app id

Usage Examples

bash
# Keyword search
opencli flathub search firefox
opencli flathub search "image editor" --limit 10
opencli flathub search blender

# App detail (appId round-trips from search)
opencli flathub app org.mozilla.firefox
opencli flathub app org.gnome.Calculator
opencli flathub app org.blender.Blender

Output Columns

Command Columns
search rank, appId, name, summary, developer, license, isFreeLicense, mainCategories, installsLastMonth, updatedAt, url
app appId, name, summary, developer, license, isFreeLicense, isEol, categories, keywords, latestVersion, latestReleaseDate, homepage, bugtracker, donation, url

The appId column round-trips between commands.

Options

Option Description
query (positional) Search keyword
--limit Max apps (1–100, default: 25)

`app`

Option Description
appId (positional) AppStream id, reverse-DNS form (e.g. org.mozilla.firefox, org.gnome.Calculator)

Notes

  • appId is the reverse-DNS AppStream id (org.mozilla.firefox), not the underscored cache id (org_mozilla_firefox) Flathub returns alongside it. We always emit the dotted form so the search → app round-trip works without translation.
  • updatedAt normalisation: Flathub's /search endpoint emits updated_at as unix-seconds (integer); /appstream/ emits it as ISO date strings. The adapter normalises /search to ISO date (YYYY-MM-DD) so both surfaces look consistent.
  • releases[].timestamp is a numeric string, not an int — quirk of the appstream layer. The adapter coerces both shapes when picking the latest release.
  • isEol is true for end-of-life apps (no longer maintained).
  • isFreeLicense uses Flathub's classification of project_license (e.g. MPL-2.0, GPL-3.0-or-later). Don't use this in lieu of reading the actual license; useful as a quick filter.
  • installsLastMonth (search only) is Flathub's 30-day install count per app. Useful for popularity ranking; null when not yet aggregated.
  • mainCategories is a single string in /search (e.g. 'network'); on /appstream/ the broader categories list is used ('Network, WebBrowser').
  • No API key required. Flathub's API is public and unauthenticated; bursts → CommandExecutionError.
  • Errors. Empty query / bad appId / bad limit → ArgumentError; unknown appId (HTTP 404) → EmptyResultError; transport / 429 / non-200 → CommandExecutionError.

Adapters Browser Flomo (`docs/adapters/browser/flomo.md`)

Flomo

Mode: 🌐 Cookie · Domain: flomoapp.com, v.flomoapp.com

Commands

Command Description
opencli flomo memos List your Flomo memos

What works today

  • Lists memos from your Flomo account using the browser login session.
  • Reads the access token automatically from localStorage.me.access_token — no manual token setup required.
  • Supports --limit from 1 to 200. Invalid values fail instead of being silently clamped.
  • Supports --since to filter by update time.
  • Supports --slug <cursor> for pagination from a previous memo page.
  • Returns stable id / url fields plus memo content (HTML), slug, tags, image URLs, and timestamps.

Current limitations

  • Requires browser mode with an active Flomo login session.
  • The Flomo API uses a custom MD5 signing mechanism with a fixed secret key (embedded in the adapter). If the signing key changes, the adapter will break.
  • --slug pagination is experimental and may not work reliably.
  • Image URLs have expiration timestamps in the query string; they may expire after some time.
  • Rate limited to 360 requests per hour.

Usage Examples

bash
# List recent memos
opencli flomo memos

# Fetch all memos
opencli flomo memos --limit 200

# Filter by time (Unix timestamp)
opencli flomo memos --since 1735689600

# Continue from a memo cursor
opencli flomo memos --slug memo_abc123 --limit 50

# JSON output
opencli flomo memos --limit 200 -f json

Prerequisites

  • Requires Chrome running with an active Flomo session at v.flomoapp.com.
  • Standalone mode will auto-launch Chrome; use the Browser Bridge extension for an established session.

Notes

  • The adapter authenticates via Strategy.COOKIE — it reads the Bearer token from localStorage in the browser context, then calls the signed API from Node.js.
  • Memo content is stored as HTML (including formatting tags like , , ``, etc.).
  • Image attachments are returned as thumbnail URLs from Flomo's CDN (static.flomoapp.com).
  • The --since parameter expects a Unix timestamp in seconds (e.g. 1735689600 = 2025-01-01 00:00:00 UTC).
  • id is the memo slug returned by Flomo and url opens the memo in Flomo's web app when the session has access.

Adapters Browser Gemini (`docs/adapters/browser/gemini.md`)

Gemini

Mode: 🔐 Browser · Domain: gemini.google.com

Commands

Command Description
opencli gemini new Start a new Gemini web chat
opencli gemini ask [--model <value>] [--thinking <level>] Send a prompt and return only the assistant reply
opencli gemini image Generate images in Gemini and optionally save them locally
opencli gemini models List available Gemini models
opencli gemini deep-research Start a Gemini Deep Research run and confirm it
opencli gemini deep-research-result <query> Export Deep Research report URL from a Gemini conversation
opencli gemini status Check Gemini web page availability and login state
opencli gemini history [--limit N] List visible Gemini conversation history from the sidebar
opencli gemini detail Open a Gemini conversation by id, URL, or sidebar title and read its turns
opencli gemini read Read the turns visible in the current Gemini web conversation

Usage Examples

bash
# Start a fresh chat
opencli gemini new

# Ask Gemini and return minimal plain-text output
opencli gemini ask "Reply with exactly: HELLO"

# Ask with a specific model selected
opencli gemini ask "Explain quantum computing in one sentence" --model 2.5-flash

# Ask in a new chat and wait longer
opencli gemini ask "Summarize this design in 3 bullets" --new true --timeout 90

# Ask with extended thinking
opencli gemini ask "Explain quantum computing" --thinking extended

# Ask with standard thinking in a fresh chat
opencli gemini ask "Hello" --new true --thinking standard

# Ask with a specific model and thinking level combined
opencli gemini ask "Explain quantum computing in one sentence" --model 2.5-pro --thinking extended

# Ask in a new chat with a specific model and thinking level
opencli gemini ask "Summarize this design in 3 bullets" --new true --model 2.5-flash --thinking standard

# Generate an icon image with short flags
opencli gemini image "Generate a tiny cyan moon icon" --rt 1:1 --st icon

# Only generate in Gemini and print the page link without downloading files
opencli gemini image "A watercolor sunset over a lake" --sd true

# Save generated images to a custom directory
opencli gemini image "A flat illustration of a robot" --op ~/tmp/gemini-images

# List available models
opencli gemini models

# List models as JSON for scripting
opencli gemini models -f json

Options

`ask`

Option Description
prompt Prompt to send (required positional argument)
--model Gemini model to use (e.g. 2.5-flash, 2.5-pro). Use opencli gemini models to list available values.
--timeout Max seconds to wait for a reply (default: 60)
--new Start a new chat before sending (default: false)
--thinking Thinking level: standard or extended (omitted = leave unchanged)

`image`

Option Description
prompt Image prompt to send (required positional argument)
--rt Aspect ratio shorthand: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3
--st Optional style shorthand, e.g. icon, anime, watercolor
--op Output directory for downloaded images (default: ~/tmp/gemini-images)
--sd Skip download and only print the Gemini page link

`models`

Column Description
model Canonical model ID (e.g. 2.5-flash, 2.5-pro, 2.5-flash-lite)
thinkingValues Per-model thinking levels only when Gemini exposes them directly on the model entry; otherwise []. The current Gemini UI usually exposes thinking controls for the active model, so this command does not infer support for every model.
  • models discovers available models from the visible Gemini web UI model picker.
  • The command is read-only: it does not select a model, change a thinking level, start a new chat, or submit a prompt.
  • Model IDs match the canonical format used by later gemini ask model selection.
  • Throws a command error when the model picker cannot be opened, which helps surface Gemini Web UI changes. Returns an empty list only when the picker opens but no model entries are available.

Behavior

  • Reused Gemini automation tabs are activated within their session so response rendering can resume after another adapter has run.

  • Native prompt insertion replaces the selected composer contents while preserving the rich editor structure, preventing visible text from becoming detached from the editor state.

  • Response polling uses fixed elapsed-time waits, so quiet model reasoning does not prematurely exhaust --timeout. The current submitted turn remains the reply anchor across consecutive asks.

  • When --new true is combined with --model and/or --thinking, the new chat is created first, then the model and thinking level are selected, then the snapshot is read, and finally the prompt is submitted.

  • ask --model <value> selects the requested model before reading the page state and sending the prompt. The selected model remains visible in the Gemini web UI after the command completes. Short aliases like pro or flash are rejected—use canonical model IDs from opencli gemini models.

  • When --model is omitted, ask does not change the current model.

  • All other Gemini commands (image, deep-research, etc.) are unaffected and do not accept --model.

  • ask uses plain minimal output and returns only the assistant response text prefixed with 💬.

  • image also uses plain output and prints status / file / link instead of a table.

  • image always starts from a fresh Gemini chat before sending the prompt.

  • When --sd is enabled, image keeps the generation in Gemini and only prints the conversation link.

Prerequisites

  • Chrome is running

  • You are already logged into gemini.google.com

  • Browser Bridge extension is installed

  • Account identity detection supports localized Google account labels.

Caveats

  • This adapter drives the Gemini consumer web UI, not a public API.
  • Gemini commands default to persistent site sessions, so consecutive gemini ask / gemini image / gemini deep-research-result invocations continue in the same Gemini page. Pass --site-session ephemeral for a one-shot tab.
  • It depends on the current browser session and may fail if Gemini shows login, consent, challenge, quota, or other gating UI.
  • DOM or product changes on Gemini can break composer detection, new-chat handling, or image export behavior.

Timeouts

A missing completed reply is a typed TIMEOUT failure (exit code 75), rather than a successful [NO RESPONSE] row. Check opencli gemini read before sending again because the original message may already have been submitted. Successful response formatting and the shared renderer/error envelope remain unchanged.


Adapters Browser Geogebra (`docs/adapters/browser/geogebra.md`)

GeoGebra

Mode: Browser | Domain: www.geogebra.org

Commands

Command Description
opencli geogebra eval "<cmd1>;<cmd2>;..." Execute one or more GeoGebra commands in a fresh automation page
opencli geogebra add-point --name A --coords 1,2 Create one point
opencli geogebra add-line --points A,B --type segment Create a line, segment, or ray from existing points
opencli geogebra add-circle --center A --radius 3 Create a circle from an existing center
opencli geogebra add-polygon --points A,B,C Create a polygon from existing points
opencli geogebra triangle --size 4 Draw an equilateral triangle
opencli geogebra hexagon --size 3 Draw a regular hexagon
opencli geogebra list List current objects on the canvas
opencli geogebra info --name A Inspect one object

Two Workflows

1. Fresh automation page

Use the site command directly when OpenCLI is allowed to open its own GeoGebra page.

bash
opencli geogebra triangle --size 4
opencli geogebra eval "A=(0,0);B=(4,0);c=Circle(A,B);d=Circle(B,A);C=Intersect(c,d,1);Polygon(A,B,C)"

Important:

  • Each opencli geogebra ... command runs in its own fresh browser session.
  • add-point, triangle, and hexagon are self-contained and work on a blank Geometry canvas.
  • add-line, add-circle, add-polygon, list, and info need an already-populated canvas or a bound tab workflow.
  • For multi-step constructions, prefer one eval call with semicolon-separated commands, or use a shape-specific helper like triangle.

2. Already-open user tab

Use this when a human or another agent already has the right geogebra.org tab open and you want to draw in that exact tab.

bash
opencli browser --session research bind --workspace bound:geogebra --domain www.geogebra.org
opencli browser --workspace bound:geogebra get url
opencli browser --workspace bound:geogebra eval "(() => {
  const cmds = [
    'OCLIA=(0,0)',
    'OCLIB=(4,0)',
    'OCLIc=Circle(OCLIA,OCLIB)',
    'OCLId=Circle(OCLIB,OCLIA)',
    'OCLIC=Intersect(OCLIc,OCLId,1)',
    'OCLIt=Polygon(OCLIA,OCLIB,OCLIC)',
  ];
  return cmds.map(cmd => ({ cmd, label: ggbApplet.evalCommandGetLabels(cmd) }));
})()"

This bound-tab workflow is the safest option when:

  • the user explicitly asks to use an existing Chrome tab
  • the tab is already positioned the way the user wants
  • you do not want OpenCLI to navigate away or replace the user's page state

Geometry Notes

  • On the GeoGebra Geometry page, RegularPolygon(...) is not reliable here and may show an "unknown command" error.
  • Prefer explicit constructions built from Circle, Intersect, Segment, and Polygon.
  • ggbApplet.evalCommandGetLabels(...) can return multiple labels for commands like Polygon(...); that is expected.
  • The source of truth is the page's ggbApplet API. Adapter commands treat applet load failures, malformed Browser Bridge/evaluate results, invalid object labels, invalid numeric arguments, and failed GeoGebra command execution as typed command failures instead of returning success rows.
  • Object names accepted by helper commands are intentionally conservative ASCII labels (A, B1, poly_1). Use geogebra eval for advanced GeoGebra syntax that needs broader command text.

Agent Notes

  • Start with opencli doctor if Browser Bridge behavior looks stale.
  • If the user wants the current visible tab, bind first and operate through opencli browser --workspace bound:geogebra ....
  • If a fresh page is acceptable, use opencli geogebra eval ... or opencli geogebra triangle.
  • Use unique temporary labels like OCLIA, OCLIB, OCLIC in bound tabs to avoid colliding with the user's existing objects.

Prerequisites


Adapters Browser Gitee (`docs/adapters/browser/gitee.md`)

Gitee

Mode: 🌐 Public (Browser) · Domain: gitee.com

Commands

Command Description
opencli gitee trending Recommended open-source projects from Gitee Explore
opencli gitee search Search Gitee repositories by keyword
opencli gitee user Show user profile panel (nickname, followers, public repos, Gitee index)

Usage Examples

bash
# Explore recommended projects
opencli gitee trending --limit 10

# Search repositories
opencli gitee search opencli --limit 10

# User profile panel
opencli gitee user fu-qingrong

# JSON output
opencli gitee trending --limit 5 -f json
opencli gitee search "ai agent" --limit 5 -f json
opencli gitee user jackwener -f json

Prerequisites


Mode: 🌐 Public · Domain: github.com

Commands

Command Description
opencli github-trending repos List repositories from GitHub Trending

Usage Examples

bash
# Daily trending repositories
opencli github-trending repos --limit 10

# Weekly Rust trending repositories
opencli github-trending repos --language rust --since weekly --limit 10

# Language slugs are URL-encoded before calling github.com/trending
opencli github-trending repos --language "c++" --since monthly -f json

Arguments

Argument Description
--since Time range: daily, weekly, or monthly (default: daily)
--language Optional GitHub Trending language slug, for example python, rust, or c++
--limit Number of repositories to return, 1-25

Output Columns

rank, repo, description, language, stars, forks, starsSince, url

Notes

  • This command reads the public server-rendered https://github.com/trending page. GitHub does not expose an official REST endpoint for Trending.
  • It does not use the logged-in GitHub browser session and does not call gh.
  • Parser drift is treated as a command execution error. A true empty result requires GitHub's explicit empty-state page.

Adapters Browser Github (`docs/adapters/browser/github.md`)

GitHub

Mode: 🔐 Browser · Domain: github.com

Commands

Command Description
opencli github whoami Show the currently logged-in GitHub account
opencli github login Open GitHub login and wait until the browser session is authenticated

Usage Examples

bash
# Check current GitHub identity
opencli github whoami

# Open the login page if the current browser session is not authenticated
opencli github login

# JSON output for agents/scripts
opencli github whoami -f json

Prerequisites

Notes

  • whoami verifies the current browser cookie session and does not open the login page.
  • login opens https://github.com/login in a foreground browser window and waits until OpenCLI can verify the account.
  • OpenCLI never fills credentials, CAPTCHA, 2FA, or passkeys. The user completes authentication in the browser; OpenCLI only verifies the resulting session.

Adapters Browser Gmail (`docs/adapters/browser/gmail.md`)

Gmail

Mode: 🔐 Browser · Domain: mail.google.com

Commands

Command Description
opencli gmail whoami Show the signed-in Gmail identity
opencli gmail login Open Gmail's Google sign-in flow
opencli gmail search <query> Search threads with Gmail search syntax
opencli gmail inbox List inbox threads
opencli gmail unread List unread threads
opencli gmail starred List starred threads
opencli gmail sent List sent threads
opencli gmail drafts List draft threads
opencli gmail trash List trashed threads
opencli gmail spam List spam threads
opencli gmail snoozed List snoozed threads
opencli gmail important List important threads
opencli gmail labels List system and user labels
opencli gmail thread Read all messages in a thread
opencli gmail attachments List attachment metadata for a thread

Usage Examples

bash
# Search and use the returned threadId to read a conversation
opencli gmail search 'from:[email protected] newer_than:30d' --limit 20 -f json
opencli gmail thread 'thread-f:1234567890123456789' -f json

# Common mailbox views and labels
opencli gmail inbox --limit 50
opencli gmail unread --limit 50
opencli gmail labels -f json

# List attachment metadata without downloading files
opencli gmail attachments 'thread-f:1234567890123456789' -f json

All list commands accept --account for Gmail URLs under /mail/u//. Thread-list commands also accept --limit from 1 to 200.

Output

Search and mailbox views return thread identity, subject, sender, snippet, message count, unread/starred flags, timestamp, and Gmail label ids. thread returns one row per message, including recipients, body text, and an attachment array. attachments flattens that array to one row per file.

Reads let Gmail perform its normal search/navigation and parse the resulting browser response. Recently cached threads may use the already rendered message containers instead. The adapter does not reconstruct Gmail's private authentication or write requests.

Prerequisites

  • Chrome running and logged into Gmail
  • Browser Bridge extension installed
  • Use opencli gmail whoami to verify the active account before reading mail

Adapters Browser Google Scholar (`docs/adapters/browser/google-scholar.md`)

Google Scholar

Mode: 🌐 Public · Domain: scholar.google.com

Commands

Command Description
opencli google-scholar search <query> Search Google Scholar papers by keyword
opencli google-scholar cite <query> Fetch a citation export for a Scholar search result
opencli google-scholar profile <author> Open an author profile and list top papers

Usage Examples

bash
opencli google-scholar search "transformer"
opencli google-scholar search "retrieval augmented generation" --limit 5
opencli google-scholar cite "attention is all you need" --style bibtex
opencli google-scholar profile "Yann LeCun" --limit 5

Notes

  • Uses browser DOM extraction over public Google Scholar results
  • Availability can vary by region or anti-bot challenges

Adapters Browser Google (`docs/adapters/browser/google.md`)

Google

Mode: 🌐 / 🔐 Mixed · Domains: google.com, suggestqueries.google.com, news.google.com, trends.google.com

Commands

Command Description
opencli google images <keyword> Search Google Images and extract visible photo/image results
opencli google news [keyword] Get Google News headlines (top stories or search)
opencli google search <keyword> Search Google and extract results from the page
opencli google suggest <keyword> Get Google search suggestions
opencli google trends Get Google Trends daily trending searches

What works today

  • Public API commands work without a browser:
    • news — RSS feed, supports top stories and keyword search
    • suggest — JSON API, no auth needed
    • trends — RSS feed, supports different regions
  • google search uses browser mode to extract results from google.com.
  • google images uses browser mode to extract visible Google Images results. By default it opens image previews and decodes Google's imgurl value so imageUrl is the original file URL when Google exposes it. Use --resolve false to skip preview clicks and return faster thumbnail-only rows.

Current limitations

  • google search may trigger CAPTCHA in Standalone browser mode. Extension mode (with an established Chrome session) is more reliable.
  • google images uses the same browser-backed Google session as search, so it can hit the same CAPTCHA or consent-page limitations.
  • Google frequently changes its DOM structure. If search stops returning results, selectors may need updating.
  • Image result pages are especially dynamic; some rows may still expose only thumbnail URLs if Google does not load an imgurl value after the preview opens.
  • Snippet extraction may return empty for some results depending on Google's layout.

Usage Examples

bash
# Search Google Images / photos
opencli google images "golden gate bridge at sunset" --limit 10

# Faster thumbnail-only image search
opencli google images "golden gate bridge at sunset" --limit 10 --resolve false

# Get top news headlines
opencli google news --limit 5

# Search news for a topic
opencli google news "artificial intelligence" --limit 10 --lang en --region US

# Search Google
opencli google search "typescript tutorial" --limit 10

# Get search suggestions
opencli google suggest python

# Output as JSON
opencli google search "machine learning" -f json

# Get trending searches in Japan
opencli google trends --region JP --limit 10

Prerequisites

  • suggest, news, trends do not require Chrome.
  • search and images require:
    • Chrome running (or Standalone mode will auto-launch)
    • For best results, use the Browser Bridge extension with an established Google session

Notes

  • suggest defaults to --lang zh-CN; other commands default to --lang en.
  • news supports --lang and --region parameters for localized results.
  • trends traffic values are raw strings (e.g. "500K+", "1,000,000+"), not numeric.
  • search output includes three result types: result (standard), snippet (featured answer box), and paa (People Also Ask).
  • images output includes rank, title, imageUrl, thumbnailUrl, sourceUrl, source, width, and height. With default preview resolution, imageUrl is the original image URL when Google provides one; otherwise it falls back to the visible thumbnail URL.
  • images --resolve false skips preview clicks, so it is faster but more likely to return thumbnail URLs in imageUrl.

Adapters Browser Goproxy (`docs/adapters/browser/goproxy.md`)

Go Module Proxy

Mode: 🌐 Public · Domain: proxy.golang.org

Fetch latest version + VCS origin metadata or list every published version tag for a Go module. Hits the unauthenticated Go module proxy (the canonical mirror used by GOPROXY).

Commands

Command Description
opencli goproxy module Latest version + VCS origin metadata for a Go module
opencli goproxy versions Published version tags for a Go module (newest first)

Usage Examples

bash
# Latest released version of a module
opencli goproxy module github.com/gin-gonic/gin
opencli goproxy module golang.org/x/net

# Every published tag, semver-sorted (descending)
opencli goproxy versions github.com/gin-gonic/gin

# Larger window
opencli goproxy versions github.com/spf13/cobra --limit 100

# Include publish times (one extra request per row)
opencli goproxy versions golang.org/x/net --limit 10 --with-time

Output Columns

Command Columns
module module, version, publishedAt, vcs, repository, commit, ref, pkgGoDevUrl, url
versions rank, module, version, publishedAt, url

The module column round-trips between commands; the version column from versions round-trips into goproxy module's version field.

Options

`module`

Option Description
module (positional) Go module path (e.g. github.com/gin-gonic/gin, golang.org/x/net)

`versions`

Option Description
module (positional) Go module path
--limit Max rows to return (1–200, default: 30)
--with-time Fetch each version's publish time (one extra request per row, slower but adds the publishedAt column)

Notes

  • Module paths must be canonical. Use what appears in your go.mod (host/path/...). The adapter rejects bare names without a host segment.
  • Pre-release tags sort lower than releases. The default sort is descending semver; v2.0.0 > v1.10.1 > v1.10.0 > v1.9.0 (NOT alphabetic).
  • publishedAt is null by default for versions to keep the request count at 1. Use --with-time only when you actually need the dates.
  • module returns the proxy's resolved upstream — vcs (e.g. git), the actual repo URL, the resolved commit hash, and the tag/ref. Useful when a module path doesn't obviously map to a GitHub repo (golang.org/x/net → go.googlesource.com/net).
  • No API key required. HTTP 404 / 410 (gone, e.g. retracted modules) → EmptyResultError; 429 → CommandExecutionError.
  • Errors. Malformed module path or bad limit → ArgumentError; unknown module → EmptyResultError; transport / non-200 → CommandExecutionError.

Adapters Browser Gov Law (`docs/adapters/browser/gov-law.md`)

Gov Law

Mode: 🌐 Public · Domain: flk.npc.gov.cn

Commands

Command Description
opencli gov-law search <query> Search the National Laws and Regulations Database
opencli gov-law recent List the most recent laws and regulations

Usage Examples

bash
opencli gov-law search "人工智能"
opencli gov-law recent --limit 10

Notes

  • Uses the site's Vue Router to navigate the law search SPA
  • If the site restructures and Vue Router disappears, the command fails with a descriptive FRAMEWORK_CHANGED error

Adapters Browser Gov Policy (`docs/adapters/browser/gov-policy.md`)

Gov Policy

Mode: 🌐 Public · Domain: www.gov.cn / sousuo.www.gov.cn

Commands

Command Description
opencli gov-policy search <query> Search policy documents on gov.cn
opencli gov-policy recent List the latest State Council policy documents

Usage Examples

bash
opencli gov-policy search "科技创新"
opencli gov-policy recent --limit 10

Notes

  • Both commands run in browser mode over public pages
  • search uses the gov.cn policy search endpoint with dataTypeId=107

Adapters Browser Grok (`docs/adapters/browser/grok.md`)

Grok

Drive Grok (grok.com) chat from the terminal. All commands run through your existing browser session — no API key needed.

Mode: 🔐 Browser · Domain: grok.com

Commands

Command Description Access
opencli grok status Page availability, login state, current model and session read
opencli grok history List recent conversations from the sidebar (requires login) read
opencli grok read Read messages in the current conversation read
opencli grok detail Open a conversation by ID and read its messages read
opencli grok export Export visible conversation history metadata from the history dialog read
opencli grok export-all Export conversation metadata plus per-conversation transcript JSON read
opencli grok ask Send a prompt and wait for the assistant reply write
opencli grok send Fire-and-forget: send a prompt without waiting write
opencli grok new Start a fresh conversation write
opencli grok image Generate images via Grok and return their URLs write
opencli grok pin Pin a conversation from the sidebar context menu write
opencli grok unpin Unpin a conversation from the sidebar context menu write
opencli grok delete --yes Delete a sidebar conversation after an explicit --yes confirmation write

Usage Examples

bash
# Sanity check
opencli grok status

# Recent conversations
opencli grok history --limit 10

# Read the active conversation as markdown
opencli grok read --markdown true

# Read a specific historical conversation by ID (or full URL)
opencli grok detail 7c4197f2-10a1-4ebb-a84a-fea89f4f1d06
opencli grok detail https://grok.com/c/7c4197f2-10a1-4ebb-a84a-fea89f4f1d06 --markdown true

# Export loaded history metadata, then export transcripts from that manifest
opencli grok export --limit 25 -f json > grok-history.json
opencli grok export-all --manifestPath grok-history.json --limit 25 -f json > grok-transcripts.json

# Ask a question and wait for the reply
opencli grok ask "Explain quantum computing in simple terms"

# Ask in a brand-new chat
opencli grok ask "Hello" --new true

# Fire-and-forget (don't wait for the reply)
opencli grok send "continue the previous answer"

# Start a new conversation
opencli grok new

# Generate an image
opencli grok image "a cyberpunk mechanical owl, neon purple and blue" --new true

# Pin or unpin a conversation by ID (or full https://grok.com/c/<id> URL)
opencli grok pin 7c4197f2-10a1-4ebb-a84a-fea89f4f1d06
opencli grok unpin https://grok.com/c/7c4197f2-10a1-4ebb-a84a-fea89f4f1d06

# Preview then explicitly delete a conversation
opencli grok delete 7c4197f2-10a1-4ebb-a84a-fea89f4f1d06
opencli grok delete 7c4197f2-10a1-4ebb-a84a-fea89f4f1d06 --yes true

Options

`ask` / `send`

Option Description
prompt Prompt to send (required positional)
--new Start a new chat before sending (default: false)
--timeout (ask only) Max seconds to wait for the reply (default: 120)

`read`

Option Description
--markdown Emit assistant replies as markdown (default: false)

`detail`

Option Description
id Session ID (UUID) or full https://grok.com/c/ URL (required positional)
--markdown Emit assistant replies as markdown (default: false)

`history`

Option Description
--limit Max conversations to list (default: 20, max 100)

`export`

Option Description
--limit Max conversations to export; 0 means all loaded history (default: 0)
--maxScrolls Max history-dialog scroll rounds (default: 80, max 500)

`export-all`

Option Description
--limit Max conversations to export; 0 means all loaded history or all manifest rows after offset
--offset Skip this many conversations before exporting (default: 0)
--manifestPath Optional JSON output from grok export; when present, skips history discovery and visits listed /c/ pages
--maxScrolls Max history-dialog scroll rounds when no manifest is provided (default: 80, max 500)
--pageScrolls Max per-conversation scroll-to-bottom rounds (default: 30, max 200)
--pageTimeoutMs Max wait for each conversation page to show messages (default: 30000)
--delayMinMs Minimum polite delay after a conversation page loads (default: 0)
--delayMaxMs Maximum polite delay after a conversation page loads (default: 5000)

`pin` / `unpin` / `delete`

Option Description
id Session ID (UUID) or full https://grok.com/c/ URL (required positional)
--yes (delete only) Actually delete the conversation; without it the command returns a dry-run row

Output Columns

Command Columns
status Status, Login, Model, SessionId, Url
history Index, Title, Url
read Role, Text
detail Role, Text
export index, id, title, date, url
export-all index, id, title, date, url, status, messageCount, error, messagesJson
ask response
send Status, Prompt
new Status
pin status, id
unpin status, id
delete status, id

Prerequisites

Notes

  • read works in the current tab even without an explicit ID; pair it with status to discover the active session ID first.
  • Grok commands default to persistent site sessions, so consecutive grok ask / grok read / grok detail invocations continue in the same Grok page. Pass --site-session ephemeral for a one-shot tab.
  • ask waits for the streaming reply to stabilize; send returns immediately after submission.
  • history reads the visible sidebar — if Grok lazy-loads older conversations, scroll the sidebar in your browser before re-running, or use detail directly.
  • export opens the full history dialog and scrolls it to collect real https://grok.com/c/ conversation URLs. Malformed history rows are treated as selector drift, not silently dropped.
  • export-all visits each conversation URL and records per-conversation status. A page with no visible transcript produces an empty row with an error message; malformed transcript rows produce a failed row; malformed history or manifest identity fails before export.
  • pin, unpin, and delete operate on conversations visible in the sidebar. pin / unpin verify the post-action context-menu state; delete --yes verifies the sidebar entry disappears before returning success.
  • status returns Model / SessionId as null when they cannot be detected (e.g. page still loading) rather than a string sentinel — branch on null in agent code.
  • DOM or product changes on Grok can break composer detection — opencli grok status is the quickest sanity check.
  • limit is validated and rejected with ArgumentError if non-positive or above the documented max (history max 100); no silent clamp.

Adapters Browser Guazi (`docs/adapters/browser/guazi.md`)

瓜子二手车 Guazi

Mode: 🌐 Public · Domain: guazi.com

No login, no cookies, no signature. Reads the mobile site m.guazi.com,
which server-renders the full listing list and car detail into the HTML (the
desktop www.guazi.com SPA loads data from a signature-locked API and is not
usable from a plain HTTP client).

Commands

Command Description
opencli guazi browse [city] Used cars for sale in a city → price / mileage / year
opencli guazi car <clue_id> One listing's detail → price, registration, mileage, specs, condition

car takes a clue_id — get one from browse (the clue_id column) or paste
a https://m.guazi.com/car-detail/c.html URL.

Usage Examples

bash
# Browse listings (defaults to Beijing)
opencli guazi browse
opencli guazi browse 上海 --limit 30
opencli guazi browse sz            # city code also works

# One listing in detail
opencli guazi car 168029452296957
opencli guazi car https://m.guazi.com/car-detail/c168029452296957.html

# JSON output
opencli guazi browse 北京 -f json

Output Columns

Command Columns
browse rank, clue_id, title, price, down_payment, mileage, year, city, url
car field, value (clue_id, title, tag, price, reg_date, mileage, transfers, source_city, color, engine, gearbox, drivetrain, emission, condition, listing_no, url)

Cities

Pass a Chinese city name or a Guazi city code. Known names:
北京(bj), 上海(sh), 广州(gz), 深圳(sz), 杭州(hz), 成都(cd), 重庆(cq), 南京(nj),
武汉(wh), 天津(tj), 西安(xa), 苏州(su), 郑州(zz), 长沙(cs), 青岛(qd), 沈阳(sy),
大连(dl), 济南(jn), 合肥(hf), 佛山(fs). Any two/three-letter code is passed through
as-is, so other cities work by code too.

Notes & Limits

  • First SSR page only. Deep pagination and brand/keyword filtering route
    through Guazi's signed mapi.guazi.com API, so browse returns the first
    server-rendered page (~40 fresh listings) per city. Listings rotate, so
    re-running surfaces new cars rather than the same page.
  • Condition is a summary, not the full inspection checklist (基础车况 +
    accident/transfer flags). The full 检测报告 sits behind the signed API and is
    intentionally not faked.
  • If Guazi ever pushes the mobile pages behind their anti-bot challenge, the
    commands fail loudly with an auth-required error rather than returning blanks.

Prerequisites

None — public site, no authentication required.


Adapters Browser Hackernews (`docs/adapters/browser/hackernews.md`)

HackerNews

Mode: 🌐 Public · Domain: news.ycombinator.com

Commands

Command Description
opencli hackernews top Hacker News top stories
opencli hackernews new Hacker News newest stories
opencli hackernews best Hacker News best stories
opencli hackernews ask Hacker News Ask HN posts
opencli hackernews show Hacker News Show HN posts
opencli hackernews jobs Hacker News job postings
opencli hackernews search <query> Search Hacker News stories
opencli hackernews user Hacker News user profile
opencli hackernews read Read a story and its comment tree

Usage Examples

bash
# Top stories
opencli hackernews top --limit 5

# Newest stories
opencli hackernews new --limit 10

# Search stories
opencli hackernews search "machine learning" --limit 5

# User profile
opencli hackernews user pg

# JSON output
opencli hackernews top -f json

# Sort search by date
opencli hackernews search "rust" --sort date

# Read a story and its top comments (id from any listing's `id` column)
opencli hackernews read 47999636 --limit 5 --depth 2

Prerequisites

  • No browser required — uses public API

Adapters Browser Hf (`docs/adapters/browser/hf.md`)

Hugging Face

Mode: 🌐 Public · Domain: huggingface.co

Commands

Command Description
opencli hf top Top upvoted Hugging Face papers
opencli hf paper <arxivId> Single paper detail (title / authors / summary / AI keywords / upvotes)
opencli hf models Top Hugging Face models (downloads / likes / trending / freshness)
opencli hf datasets Top Hugging Face datasets
opencli hf spaces Top Hugging Face Spaces (gradio / streamlit / docker / static demos)

Usage Examples

bash
# Today's top papers
opencli hf top --limit 10

# Single paper detail by arXiv id (mirrors HF's paper page)
opencli hf paper 1706.03762         # Attention Is All You Need
opencli hf paper 2005.14165         # GPT-3 paper

# All papers (no limit)
opencli hf top --all

# Specific date
opencli hf top --date 2025-03-01

# Weekly/monthly top papers
opencli hf top --period weekly
opencli hf top --period monthly

# Top models by downloads (default)
opencli hf models --limit 20

# Top text-generation models with name filter
opencli hf models --pipeline text-generation --search llama --sort likes --limit 10

# Top datasets by likes
opencli hf datasets --sort likes --limit 10

# Top Spaces by likes
opencli hf spaces --limit 20

# Filter Spaces by SDK
opencli hf spaces --sdk gradio --search llm --limit 10

# JSON output
opencli hf top -f json

`top` Options

Option Description
--limit Number of papers (default: 20)
--all Return all papers, ignoring limit
--date Date in YYYY-MM-DD format (defaults to most recent)
--period Time period: daily, weekly, or monthly (default: daily)

Returns paper listing rows with rank, id, title, upvotes, authors. The id value round-trips into opencli hf paper .

`paper` Options

Option Description
id (positional) arXiv id (e.g. 1706.03762, optionally with version suffix v3)

Returns one row with id, title, authors, publishedAt, upvotes, aiKeywords, summary, aiSummary, url. The summary is the original arXiv abstract; aiSummary and aiKeywords are HF's AI-generated metadata (may be empty for older or non-curated papers). Returns EmptyResultError if HF has no paper page for that id.

`models` Options

Option Description
--sort downloads / likes / trending / created_at / last_modified (default: downloads)
--search Optional name/owner substring filter (e.g. llama, mistralai/)
--pipeline Pipeline tag filter (e.g. text-generation, image-classification)
--limit Max models (1–100, default: 20)

`datasets` Options

Option Description
--sort Same set as models (default: downloads)
--search Optional name/owner substring filter
--limit Max datasets (1–100, default: 20)

`spaces` Options

Option Description
--sort likes / created_at / last_modified (default: likes; HF doesn't accept trending for spaces)
--search Optional name/owner substring filter (e.g. stability, openai/)
--sdk SDK filter: gradio / streamlit / docker / static
--limit Max spaces (1–100, default: 20)

Returns rows with rank, id, author, sdk, likes, tags, lastModified, url.

Prerequisites

  • No browser required — uses public Hugging Face API

Adapters Browser Hltv (`docs/adapters/browser/hltv.md`)

HLTV

Mode: 🌐 Browser · Domain: hltv.org

The HLTV adapter reads visible CS2/CS:GO stats pages through the Browser
Bridge. HLTV does not expose a stable public JSON API for these views, so the
commands parse search results, player stats, match mapstats, team stats, and
series pages from the rendered DOM.

Commands

Command Description
opencli hltv search <query> Search players, teams, events, and articles
opencli hltv player-summary Read a player's summary page and complete stats link
opencli hltv player-matches Read a player's stats Matches tab
opencli hltv player-form Aggregate recent player maps by summary, map, and opponent
opencli hltv player-map-pool Aggregate a player's recent maps into map-pool buckets
opencli hltv player-vs-team <team> Filter a player's maps against one team
opencli hltv player-teammate-impact Compare shared and non-shared map samples for two teammates
opencli hltv player-duel Compare two players on shared maps, including direct kills when available
opencli hltv match-map <match> Read all player rows from one mapstats page
opencli hltv match-series <match> Expand a BO1/BO3/BO5 into summary, map, and player rows
opencli hltv team-matches <team> Read recent team map results
opencli hltv team-map-pool <team> Read a team's visible map-pool stats
opencli hltv event-matches <event> Read stats match rows for one event

Usage Examples

bash
# Search and discover HLTV entity links
opencli hltv search niko --limit 5

# Read player pages and recent form
opencli hltv player-summary --player 3741/niko
opencli hltv player-matches --player 3741/niko --limit 10 -f json
opencli hltv player-form --player 19230/m0nesy --limit 30

# Compare two players
opencli hltv player-duel 3741/niko 21167/donk
opencli hltv player-duel 19230/m0nesy 3741/niko --mode history --limit 10

# Expand a series or inspect one mapstats URL
opencli hltv match-series https://www.hltv.org/stats/matches/126993/spirit-vs-falcons
opencli hltv match-map "https://www.hltv.org/stats/matches/mapstatsid/231594/falcons-vs-natus-vincere" -f json

# Team and event views
opencli hltv team-matches 6667/falcons --limit 10
opencli hltv team-map-pool 11283/falcons
opencli hltv event-matches 8301 --limit 10

Common Subjects

  • Player refs accept id/slug, player URLs, and compatible stats player URLs.
  • Team refs accept id/slug, team URLs, and compatible stats team URLs.
  • Match refs accept normal match URLs, stats series URLs, and mapstats URLs where
    supported.
  • Event refs accept event IDs, /events/:id/:slug URLs, and stats URLs with an
    event= query parameter.

Prerequisites

  • Chrome running with the Browser Bridge extension
    installed
  • HLTV accessible in the active browser session
  • If HLTV shows a Cloudflare or human-verification page, complete it in Chrome
    before retrying the command

Notes

  • The adapter is read-only and does not require HLTV login.
  • Heavy match or duel commands may load multiple HLTV pages and can take longer
    than search or summary commands.
  • Use --window foreground --keep-tab true when debugging HLTV page structure
    or Cloudflare interruptions.
  • Primary subjects use positional arguments; filters such as --limit,
    --period, --ranking, --map, and --version remain named options.

Error Behaviour

Condition Error
Invalid player, team, event, match, limit, offset, or filter argument ArgumentError
Visible HLTV page contains no rows for the requested subject/filter EmptyResultError
HLTV page structure changed or parser returns an unexpected shape CommandExecutionError
Browser navigation or selector wait exceeds the command timeout TimeoutError

Adapters Browser Homebrew (`docs/adapters/browser/homebrew.md`)

Homebrew

Mode: 🌐 Public · Domain: formulae.brew.sh

Inspect Homebrew formulae and casks, plus the official install-rank analytics, without auth or browser. Three commands.

Commands

Command Description
opencli homebrew formula <name> Single Homebrew core formula's metadata
opencli homebrew cask <token> Single Homebrew cask's (macOS app) metadata
opencli homebrew popular Most-installed formulae or casks (Homebrew analytics ranking)

Usage Examples

bash
# Inspect a formula
opencli homebrew formula wget
opencli homebrew formula gcc@13
opencli homebrew formula imagemagick

# Inspect a cask (macOS package)
opencli homebrew cask firefox
opencli homebrew cask visual-studio-code

# Most popular installs (defaults to formula / 30d / top 30)
opencli homebrew popular
opencli homebrew popular --type cask --window 90d --limit 50
opencli homebrew popular --type formula --window 365d --limit 100

# JSON output
opencli homebrew popular -f json

Output Columns

Command Columns
formula formula, tap, version, license, description, homepage, dependencies, deprecated, disabled, source, url
cask cask, tap, name, version, description, homepage, deprecated, disabled, download, url
popular rank, token, type, installs, percent, window, url

The token column from popular round-trips into formula (when type=formula) or cask (when type=cask).

Options

`homebrew formula`

Option Description
name (positional) Formula name (wget, gcc@13, imagemagick)

`homebrew cask`

Option Description
token (positional) Cask token (firefox, visual-studio-code)
Option Description
--type formula (default) or cask
--window 30d (default) / 90d / 365d
--limit Max rows (1-500, default: 30)

Caveats

  • Formula / cask tokens are validated against Homebrew's [A-Za-z0-9][A-Za-z0-9._+@-]* pattern (max 100 chars). Bad input raises ArgumentError.
  • --type and --window are validated against the only values Homebrew analytics actually publishes. Anything else raises ArgumentError.
  • Homebrew analytics serves install counts as comma-formatted strings ("139,972"); we coerce them to plain numbers.
  • The endpoints are static GitHub Pages JSON regenerated daily, so timestamps lag by up to 24 h.

Prerequisites

  • No browser required — uses formulae.brew.sh/api/formula/<name>.json, formulae.brew.sh/api/cask/<token>.json, and formulae.brew.sh/api/analytics/(install|cask-install)/<window>.json.

Adapters Browser Huodongxing (`docs/adapters/browser/huodongxing.md`)

Huodongxing

Mode: 🌐 Public / Browser · Domain: www.huodongxing.com

Commands

Command Description
opencli huodongxing events Search Huodongxing events by tag, city, date range, event type, and title keyword

Usage Examples

bash
# AI events across all cities for a date range
opencli huodongxing events --tag AI --city 全部 --date 2026-06-09 --dateTo 2026-06-12

# Offline events only
opencli huodongxing events --tag AI --city 上海 --eventType 1

# Online events only
opencli huodongxing events --eventType 2 --qs Agentic --limit 10

# JSON output
opencli huodongxing events --tag AI --city 北京 -f json

Filters

  • --tag maps to Huodongxing tag
  • --city maps to Huodongxing city
  • --date maps to Huodongxing date
  • --dateTo maps to Huodongxing dateTo
  • --eventType 1 filters offline events
  • --eventType 2 filters online events
  • --qs filters by event title keyword

Prerequisites

Chrome running with Browser Bridge extension installed. Login is not required for public event listings.


Adapters Browser Hupu (`docs/adapters/browser/hupu.md`)

Hupu (虎扑)

Mode: 🌐 Public / 🔐 Browser · Domain: bbs.hupu.com

Commands

Command Description
opencli hupu hot Read Hupu hot threads
opencli hupu search <keyword> Search Hupu threads by keyword
opencli hupu detail <tid> Read one thread and optional hot replies
opencli hupu mentions Read replies that mentioned you
opencli hupu reply <tid> <text> Reply to a thread or quote one reply
opencli hupu like <tid> Like one reply
opencli hupu unlike <tid> Cancel like on one reply

Usage Examples

bash
# Hot threads
opencli hupu hot --limit 5

# Search threads
opencli hupu search 湖人 --limit 10

# Read one thread and include hot replies
opencli hupu detail 638234927 --replies true

# Read mentions that replied to you
opencli hupu mentions --limit 20

# Reply to the thread
opencli hupu reply 638234927 "hello from opencli" --topic_id 502

# Quote one hot reply by pid
opencli hupu reply 638234927 "replying to this comment" --topic_id 502 --quote_id 174908

# Like / unlike one reply
opencli hupu like 638234927 174908 --fid 4860
opencli hupu unlike 638234927 174908 --fid 4860

# JSON output
opencli hupu detail 638234927 -f json

Notes

  • reply --topic_id maps to Hupu's API topicId, for example 502 for Basketball News
  • reply --quote_id is the quoted reply pid
  • mentions reads my.hupu.com notification APIs from the logged-in browser session
  • like / unlike --fid uses the forum ID from thread metadata
  • detail --replies true appends top hot replies to the content field
  • hot --limit is validated upfront: must be a positive integer in [1, 100]. Out-of-range or non-integer values raise ArgumentError — no silent clamp.

Output

`hot`

Reads the public bbs.hupu.com/ landing page (no login required) via an in-page querySelectorAll('.t-info') walk. Replaces a legacy documentElement.outerHTML regex that conflated navigation links with thread rows.

Column Type Notes
rank int 1-based position on the home page
tid string 9-digit hupu thread id; round-trips into hupu detail <tid>
title string Thread title from .t-title; trimmed
lights int | null "亮" count (likes-equivalent), null if upstream omitted the span; 0 is a real value, never an unknown sentinel
replies int | null "回复" count, same null semantics as lights. 万-suffixed counts are expanded (1.2万 → 12000)
forum string Sub-section name (e.g. 步行街主干道, NBA湿乎乎的话题) from the row's .t-label link
is_hot bool true when hupu tagged the row with class=" hot" — exposes hupu's own hot marker; rows are returned in page order regardless
url string Canonical https://bbs.hupu.com/<tid>.html

Empty home page → EmptyResultError (the page structure may have changed); never a silent [].

Prerequisites

  • Chrome running and able to open bbs.hupu.com and my.hupu.com
  • Browser Bridge extension installed
  • For mentions, reply, like, and unlike, a valid Hupu login session in Chrome is required

Adapters Browser Imdb (`docs/adapters/browser/imdb.md`)

IMDb

Mode: 🌐 Public (Browser) · Domain: www.imdb.com

Commands

Command Description
opencli imdb search Search movies, TV shows, and people
opencli imdb title Get movie or TV show details
opencli imdb top IMDb Top 250 Movies
opencli imdb trending IMDb Most Popular Movies
opencli imdb person Get actor or director info
opencli imdb reviews Get user reviews for a title

Usage Examples

bash
# Search for a movie
opencli imdb search "inception" --limit 10

# Get movie details
opencli imdb title tt1375666

# Get TV series details (also accepts full URL)
opencli imdb title "https://www.imdb.com/title/tt0903747/"

# Top 250 movies
opencli imdb top --limit 20

# Currently trending movies
opencli imdb trending --limit 10

# Actor/director info with filmography
opencli imdb person nm0634240 --limit 5

# User reviews
opencli imdb reviews tt1375666 --limit 5

# JSON output
opencli imdb top --limit 5 -f json

Prerequisites

  • Chrome with Browser Bridge extension installed
  • No login required (all data is public)

Adapters Browser Indeed (`docs/adapters/browser/indeed.md`)

Indeed

Mode: 🍪 Browser (cookie) · Domain: www.indeed.com

Indeed sits behind Cloudflare and answers bare HTTP fetches with 403
and a cf-mitigated: challenge header, so the adapter drives a real
browser session. DOM extraction happens against the rendered page.

Commands

Command Description
opencli indeed search <query> Keyword job search on the US site
opencli indeed job <jk> (alias detail, view) Read the full job posting by jk (job key)

Usage Examples

bash
# Quick start — first run will route through the browser session
opencli indeed search "rust developer" --limit 10

# Narrow to recent jobs in a location, sorted by date
opencli indeed search "site reliability engineer" \
  --location "Remote" --fromage 7 --sort date

# Read a job posting using the `id` surfaced by `search`
opencli indeed job dccc07ac5a6a3683

# JSON output
opencli indeed search "data engineer" -f json

Output Columns

Command Columns
search rank, id, title, company, location, salary, tags, url
job id, title, company, location, salary, job_type, description, url

id is the Indeed job key (jk) — a 16-character lowercase hex
identifier. Pipe it into opencli indeed job <jk> to drill into the full
posting (per the
listing↔detail ID pairing convention).

Args

Arg Type Default Notes
query (positional, required) string — Job title / skill / company
--location string (none) E.g. "Remote", "New York, NY"
--fromage string (none) Recency filter, days back: 1 / 3 / 7 / 14
--sort string relevance relevance or date
--start int 0 Pagination offset (multiple of 10, 0-based)
--limit int 15 Max rows to return (1–25, capped to one page)

`job`

Arg Type Default Notes
id (positional, required) string — Job key (16-char lowercase hex from search)

Prerequisites

Indeed protects the site with Cloudflare. The first run in a fresh
browser session may surface the Just a moment… interstitial, in which
case the adapter throws:

text
Indeed served a Cloudflare challenge page
hint: Open https://www.indeed.com in the connected browser and clear the
challenge, then retry.

Open the connected browser, complete the human check on indeed.com once,
and the cookies will carry forward into subsequent adapter calls
(Strategy.COOKIE).

Limitations

  • US site (www.indeed.com) only. Indeed runs region-specific subdomains
    (uk.indeed.com, de.indeed.com, ...) — adding them is mostly a
    question of swapping the origin and re-checking the DOM selectors.
  • Salary parsing pulls the visible text without normalizing currencies or
    ranges. Pipe through your own normalizer if you need structured values.
  • Tag column is a ·-joined free-text list (job type, schedule, etc.);
    Indeed's metadata pills change wording per A/B bucket so don't expect a
    fixed taxonomy.

Adapters Browser Instagram (`docs/adapters/browser/instagram.md`)

Instagram

Mode: 🔐 Browser · Domain: instagram.com

Commands

Command Description
opencli instagram profile Get user profile info
opencli instagram search Search users
opencli instagram user Get recent posts from a user
opencli instagram explore Discover trending posts
opencli instagram followers List user's followers
opencli instagram following List user's following
opencli instagram saved Get your saved posts (or one collection)
opencli instagram collection-create Create a new saved-posts collection
opencli instagram collection-delete Delete a saved-posts collection by name or id

Usage Examples

bash
# View a user's profile
opencli instagram profile nasa

# Search users
opencli instagram search nasa --limit 5

# View a user's recent posts
opencli instagram user nasa --limit 10

# Discover trending posts
opencli instagram explore --limit 20

# List followers/following
opencli instagram followers nasa --limit 20
opencli instagram following nasa --limit 20

# Get your saved posts (default "All posts" feed)
opencli instagram saved --limit 10

# Get posts from a specific collection (case-insensitive name match)
opencli instagram saved --collection inspiration --limit 10

# Create a new saved-posts collection
opencli instagram collection-create "design refs"

# Delete a collection by name (or by numeric id, e.g. 17853899493659567)
opencli instagram collection-delete "design refs"

# JSON output
opencli instagram profile nasa -f json

Profile photos

instagram profile and instagram search include an avatar_url column with the account's profile photo (profile prefers the HD version). It is empty when Instagram sends none. These are signed cdninstagram.com / fbcdn.net URLs: they expire, and Instagram's CDN often refuses to load them on other sites. Download the image when you need it; don't store the URL for later hotlinking.

Notes on collections

  • instagram saved without --collection returns the unsegmented "All posts" bucket (same as the original behaviour).
  • With --collection <name> it resolves the name to an id via /api/v1/collections/list/, then fetches /api/v1/feed/collection/{id}/posts/. Match is case-insensitive after trimming. An unknown name throws an error that lists the available names.
  • instagram collection-create <name> calls POST /api/v1/collections/create/ with a multipart name field. Instagram silently accepts duplicate names — the API just returns a new collection_id each time, so dedupe client-side if you care.
  • instagram collection-delete <name-or-id> calls POST /api/v1/collections/{id}/delete/. Pass either a case-insensitive collection name or a numeric collection_id. If the name resolves to multiple collections (e.g. duplicates from collection-create), the adapter throws and lists the candidate ids so you can disambiguate by passing the id explicitly. Unknown names list the available collections in the error message.
  • Saving an existing post directly into a named collection in one shot is not exposed by the web app's documented endpoints (/api/v1/web/save/{pk}/save/ only writes to "All posts"). Use instagram save first, then move the post in the UI, or extend with the /api/v1/collections/{id}/edit/ mutation.

Prerequisites


Adapters Browser Jd (`docs/adapters/browser/jd.md`)

JD.com

Mode: 🔐 Browser · Domain: item.jd.com

Commands

Command Description
opencli jd item <sku> Fetch product details (price, shop, specs, AVIF images)

Usage Examples

bash
# Get product details by SKU
opencli jd item 100291143898

# Limit returned AVIF images
opencli jd item 100291143898 --images 5

# JSON output
opencli jd item 100291143898 -f json

Prerequisites


Adapters Browser Jianyu (`docs/adapters/browser/jianyu.md`)

Jianyu

Mode: 🔐 Browser · Domain: www.jianyu360.cn

Commands

Command Description
opencli jianyu search "<query>" --limit <n> [--since_days <n>] Search Jianyu bid notices and keep only accessible detail links
opencli jianyu detail "" Extract detail-page evidence blocks from a search URL

Usage Examples

bash
# Search by keyword
opencli jianyu search "procurement" --limit 20 -f json

# Search another keyword with an explicit recency window
opencli jianyu search "substation" --limit 10 --since_days 30 -f json

# Extract structured detail evidence
opencli jianyu detail "https://www.jianyu360.cn/nologin/content/....html" -f json

Prerequisites

Notes

  • search returns accessible procurement rows with published_at, detail_status, project_code, budget_or_limit, url, plus compatible publish_time/date.
  • search keeps all reachable rows by default. --since_days enables an explicit recency filter.
  • detail returns the same structured fields and adds detail_text + evidence_blocks.
  • Date fields are normalized to YYYY-MM-DD when date text is detectable.
  • Results are deduplicated by stable notice id when it is available.
  • --limit defaults to 20 and is capped at 50.

Troubleshooting

  • If the page shows login/verification prompts, complete it in Chrome and retry.
  • If the command returns no valid rows due to noise/navigation pages, it reports taxonomy-style extraction errors instead of silent weak results.

Adapters Browser Jike (`docs/adapters/browser/jike.md`)

即刻 (Jike)

Mode: 🔐 Browser · Domain: web.okjike.com

Commands

Command Description
opencli jike feed 即刻首页动态流
opencli jike search 搜索即刻帖子
opencli jike post 帖子详情及评论
opencli jike topic 话题详情
opencli jike user 用户资料
opencli jike create 发布即刻动态
opencli jike comment 评论即刻帖子
opencli jike like 点赞即刻帖子
opencli jike repost 转发即刻帖子
opencli jike notifications 即刻通知

Usage Examples

bash
# View feed
opencli jike feed --limit 10

# Search posts
opencli jike search "AI" --limit 20

# View post details and comments
opencli jike post <post-id>

# Create a new post
opencli jike create --content "Hello Jike!"

# Like a post
opencli jike like <post-id>

# JSON output
opencli jike feed -f json

Listing Columns

feed, search, and user expose id for each post row. Pass that value
directly to opencli jike post for the detail view.

Prerequisites


Adapters Browser Jimeng (`docs/adapters/browser/jimeng.md`)

即梦AI (Jimeng)

Mode: 🔐 Browser · Domain: jimeng.jianying.com

Commands

Command Description
opencli jimeng generate 即梦AI 文生图 — 输入 prompt 生成图片
opencli jimeng history 查看生成历史

Usage Examples

bash
# Generate an image
opencli jimeng generate --prompt "一只在星空下的猫"

# Use a specific model
opencli jimeng generate --prompt "cyberpunk city" --model high_aes_general_v50

# Set custom wait timeout
opencli jimeng generate --prompt "sunset landscape" --wait 60

# View generation history
opencli jimeng history --limit 10

Options (generate)

Option Description
--prompt Image description prompt (required)
--model Model: high_aes_general_v50 (5.0 Lite), high_aes_general_v42 (4.6), high_aes_general_v40 (4.0)
--wait Wait seconds for generation (default: 40)

Prerequisites


Adapters Browser Jira (`docs/adapters/browser/jira.md`)

Jira

Mode: 🔑 Atlassian REST API · Domain: configured with ATLASSIAN_JIRA_BASE_URL

Read Jira issues, comments, attachments, and links through Atlassian REST APIs. The adapter supports Jira Cloud and Jira Data Center without driving a browser session.

Commands

Command Description
opencli jira issue <KEY> Normalized issue context for agents
opencli jira search <JQL> Search issues with JQL
opencli jira comments <KEY> Issue comments as Markdown
opencli jira attachments <KEY> Issue attachment metadata
opencli jira links <KEY> Linked Jira issues

Configuration

bash
export ATLASSIAN_JIRA_BASE_URL=https://example.atlassian.net
export ATLASSIAN_DEPLOYMENT=cloud      # cloud | datacenter | auto
export [email protected]
export ATLASSIAN_API_TOKEN=...

To request a specific set of Jira fields, pass a comma-separated list to the
issue command. The list replaces the default field list:

bash
opencli jira issue PROJ-123 --fields 'summary,status,customfield_12345'

The result adds selectedFields, an ordered list of { id, name, value }
entries. The stable Jira field id is always preserved; display names are
metadata, so duplicate names and names that collide with standard fields do not
lose data. Explicit lists keep their first-requested order and ignore duplicate
ids.

Set --fields to auto to explicitly request Jira's *all field set. The
result uses the same selectedFields structure, ordered by stable field id;
null and structured JSON values are preserved:

bash
opencli jira issue PROJ-123 --fields auto

For Data Center, use a personal access token when available:

bash
export ATLASSIAN_JIRA_BASE_URL=https://jira.example.com
export ATLASSIAN_DEPLOYMENT=datacenter
export ATLASSIAN_PAT=...

Cloud instances default to Jira REST API v3. Data Center instances use Jira REST API v2. ATLASSIAN_DEPLOYMENT=auto treats *.atlassian.net as Cloud and other hosts as Data Center.

Usage Examples

bash
# Full issue context, including description, comments, attachments, and links
opencli jira issue PROJ-123 -f json

# Search with JQL
opencli jira search "project = PROJ order by updated desc" --limit 20 -f json

# Focused reads
opencli jira comments PROJ-123 -f json
opencli jira attachments PROJ-123 -f json
opencli jira links PROJ-123 -f json

Output Notes

  • issue returns an agent-friendly object with key, summary, status, priority, description.markdown, comments, attachments, linkedIssues, versions, components, and timestamps.
  • Jira Cloud ADF descriptions and comments are converted to Markdown.
  • Rendered Jira HTML from Data Center is converted through OpenCLI's Markdown converter.
  • Invalid issue keys fail early with ArgumentError.

Custom Fields

Some Jira fields are instance-specific. Set these environment variables to include them in jira issue output:

bash
export ATLASSIAN_JIRA_ACCEPTANCE_FIELD=customfield_12345
export ATLASSIAN_JIRA_SPRINT_FIELD=customfield_10020
export ATLASSIAN_JIRA_STORY_POINTS_FIELD=customfield_10016

Notes

  • The adapter only reads Jira data; it does not generate RCA, design docs, or release notes itself.
  • Agents should generate documentation from jira issue ... -f json, then write it with the Confluence adapter.
  • Expected auth, rate-limit, argument, and not-found failures are normalized to CliError subclasses.

Adapters Browser Juejin (`docs/adapters/browser/juejin.md`)

Juejin

Mode: 🌐 Public · Domain: api.juejin.cn

Commands

Command Description
opencli juejin recommend Juejin (掘金) homepage recommended article feed
opencli juejin hot Juejin (掘金) hot article ranking, optionally scoped to a category

Usage Examples

bash
# Front-page recommendation feed
opencli juejin recommend --limit 10

# Paginate the feed with the next-page cursor returned in the previous batch
opencli juejin recommend --cursor "1718900000000000000" --limit 10

# Hot ranking, default backend category
opencli juejin hot --limit 20

# Hot ranking scoped to AI / frontend
opencli juejin hot --category ai --limit 10
opencli juejin hot --category frontend --limit 10

# Hot ranking by raw category id (the API returned id)
opencli juejin hot --category 6809637773935378440 --limit 5

# JSON output
opencli juejin hot -f json

`recommend` Options

Option Description
--limit Max articles (1-100, default 20)
--cursor Pagination cursor; pass back the previous response's cursor to keep scrolling (default "0")

Returns rows with rank, article_id, title, brief, views, likes, comments, author, tags, url, next_cursor, has_more. The article_id round-trips into https://juejin.cn/post/. Use next_cursor as the next --cursor value when has_more is true.

`hot` Options

Option Description
--category Category slug or numeric id. Slugs: backend, frontend, android, ios, ai (default backend)
--limit Max articles (1-50, default 20)

Returns rows with rank, article_id, title, brief, views, likes, comments, hot_rank, author, url.

Prerequisites

  • No browser required; uses public Juejin API endpoints.

Adapters Browser Ke (`docs/adapters/browser/ke.md`)

Ke

Mode: 🔐 Browser · Domain: ke.com

Commands

Command Description
opencli ke ershoufang Browse second-hand housing listings
opencli ke zufang Browse rental listings
opencli ke xiaoqu Browse neighborhood / community listings
opencli ke chengjiao Browse recent transaction records

Usage Examples

bash
# Beijing second-hand housing
opencli ke ershoufang --city bj --district chaoyang --limit 10

# Rentals in Shanghai
opencli ke zufang --city sh --district pudong --max-price 8000 --limit 10

# Communities in Guangzhou
opencli ke xiaoqu --city gz --district tianhe --limit 10

# Recent transactions in Beijing Haidian
opencli ke chengjiao --city bj --district haidian --limit 10

Prerequisites

Notes

  • city uses short city codes such as bj, sh, gz, sz
  • district expects the district slug used in Beike URLs, for example chaoyang or haidian

Adapters Browser Kimi (`docs/adapters/browser/kimi.md`)

Kimi

Drive Kimi (kimi.com) from the terminal through your existing browser session.

Mode: 🔐 Browser · Domain: kimi.com

Commands

Command Description Access
opencli kimi status Check page connection, login state, and current URL read
opencli kimi account Read sidebar account labels read
opencli kimi usage Read Kimi membership quota usage, rate limits, gift quota, and booster balance read
opencli kimi history List visible sidebar conversations read
opencli kimi detail Open a chat by ID or trusted /chat/ URL and read messages read
opencli kimi read Read messages in the current or selected chat read
opencli kimi send Send a prompt without waiting for the assistant reply write
opencli kimi ask Send a prompt and wait for the assistant reply write
opencli kimi new Start a new chat write
opencli kimi model Read, list, or switch the active model write
opencli kimi mode [name] List or navigate to a Kimi work mode write
opencli kimi copy-message Copy or return the last assistant message write
opencli kimi react Like or dislike the last assistant message write
opencli kimi regenerate Regenerate the last assistant message write
opencli kimi share Open the share dialog for the last assistant message write
opencli kimi history-rename --yes Rename a chat from the history page write
opencli kimi sidebar-toggle Toggle the sidebar write
opencli kimi view-all-history Navigate to the full history page write
opencli kimi settings Open settings write
opencli kimi sign-out --yes Sign out from settings write
opencli kimi upgrade Open the membership/upgrade entry point write
opencli kimi dismiss-banner Close a visible sidebar banner write
opencli kimi templates List template cards on a mode page read
opencli kimi storage-keys List localStorage or sessionStorage keys read
opencli kimi storage-get <key> Read one storage value read
opencli kimi cookies List JavaScript-visible cookies read
opencli kimi idb-list List IndexedDB databases read

Usage Examples

bash
# Check the current Kimi tab
opencli kimi status

# Read Kimi membership quota usage
opencli kimi usage

# Start a new chat and ask a question
opencli kimi new
opencli kimi ask "Summarize this plan in three bullets"

# Continue the current chat without waiting for a reply
opencli kimi send "Now expand the second bullet"

# List and read conversations
opencli kimi history --limit 10
opencli kimi detail https://kimi.com/chat/<chat-id>
opencli kimi read --conv /chat/<chat-id>

# Inspect or switch model
opencli kimi model
opencli kimi model --list true
opencli kimi model --set "K2"

# Rename a chat only after explicit confirmation
opencli kimi history-rename <chat-id> "New title" --yes true

Options

Option Description
prompt Prompt to send for ask / send
--conv Chat id, exact /chat/ path, or trusted https://kimi.com/chat/ URL for commands that target a chat
--timeout Max seconds for ask to wait for a reply
--limit Max rows for history, read, detail, or storage listings
--set Model name to switch to; exact match is preferred, otherwise only a unique partial match is allowed
--list Open the model menu and list model options
--yes Required for destructive or account-changing commands such as history-rename and sign-out

Behavior

  • Kimi commands use a persistent browser site session and operate on the live kimi.com UI.
  • usage navigates to the Kimi membership subscription quota page and reads visible quota sections without writing account state.
  • Chat ids accept bare ids, exact relative /chat/ paths, or https://kimi.com/chat/ / https://www.kimi.com/chat/ URLs only.
  • send / ask verify that a new user turn containing the prompt appears after clicking Send.
  • ask waits for an assistant turn to appear and stabilize; timeout is reported as a typed timeout instead of a successful row.
  • Model switching rejects ambiguous partial matches before clicking and verifies the selected model by reading the UI back.
  • copy-message --click-button writes to the local clipboard, so the command is marked as write access.

Prerequisites

Caveats

  • This adapter targets the Kimi web UI and can break when Kimi changes DOM structure, labels, or SVG names.
  • Sidebar/history commands only see conversations that the current UI has rendered.
  • Cookie output is limited to cookies visible to JavaScript; httpOnly cookies are intentionally not exposed.

Adapters Browser Lesswrong (`docs/adapters/browser/lesswrong.md`)

LessWrong

Mode: Public · Domain: www.lesswrong.com

Rationality community and AI alignment research forum.

Commands

Command Description
opencli lesswrong curated Editor's picks
opencli lesswrong frontpage Algorithmic frontpage feed
opencli lesswrong new Latest posts
opencli lesswrong top Top rated (all time)
opencli lesswrong top-week Top rated this week
opencli lesswrong top-month Top rated this month
opencli lesswrong top-year Top rated this year
opencli lesswrong read Read full post by URL or ID
opencli lesswrong comments Top comments on a post
opencli lesswrong user User profile
opencli lesswrong user-posts List a user's posts
opencli lesswrong tag Posts by tag
opencli lesswrong tags List popular tags
opencli lesswrong sequences Post collections
opencli lesswrong shortform Quick takes

Usage Examples

bash
# Browse curated posts
opencli lesswrong curated --limit 5

# Top posts this week
opencli lesswrong top-week --limit 10

# Read a specific post
opencli lesswrong read CzoiqGzpShprcv2Jd
opencli lesswrong read https://www.lesswrong.com/posts/xxx/slug

# Posts tagged "AI"
opencli lesswrong tag ai --limit 5

# User profile and posts
opencli lesswrong user zvi
opencli lesswrong user-posts zvi --limit 5

# Comments on a post
opencli lesswrong comments CzoiqGzpShprcv2Jd --limit 10

# JSON output
opencli lesswrong curated -f json

Prerequisites

  • No browser required — uses public LessWrong GraphQL API

Adapters Browser Lichess (`docs/adapters/browser/lichess.md`)

Lichess

Mode: 🌐 Public · Domain: lichess.org

Look up public Lichess player profiles and per-perf top-N leaderboards. Lichess is a free open-source chess platform; its REST API is fully public and unauthenticated for these read-only endpoints.

Commands

Command Description
opencli lichess user Lichess player profile (rating, perfs, win/loss counts)
opencli lichess top Top-N leaderboard for a perf type (bullet/blitz/rapid/classical/...)

Usage Examples

bash
# Player profile
opencli lichess user DrNykterstein
opencli lichess user penguingm1

# Top-N leaderboards (username round-trips into `lichess user`)
opencli lichess top blitz
opencli lichess top bullet --limit 50
opencli lichess top rapid --limit 25
opencli lichess top chess960

Output Columns

Command Columns
user username, id, title, patron, online, tosViolation, createdAt, seenAt, gamesAll, gamesWin, gamesLoss, gamesDraw, topPerfName, topPerfRating, topPerfGames, fideRating, country, bio, url
top rank, username, id, title, rating, progress, patron, url

The username column round-trips from top into user.

Options

`user`

Option Description
username (positional) Lichess username (case-insensitive, 2–30 chars, letters/digits/underscore/dash)

`top`

Option Description
perf (positional) Perf type: ultraBullet, bullet, blitz, rapid, classical, chess960, crazyhouse, antichess, atomic, horde, kingOfTheHill, racingKings, threeCheck
--limit Top-N rows (1–200, default: 10)

Notes

  • topPerfName/topPerfRating/topPerfGames picks the perf with the most games played, excluding non-game perfs (puzzle, storm, racer, streak). For most active accounts this is bullet or blitz. For inactive accounts the field surfaces whatever the account played most before going quiet.
  • Closed accounts → EmptyResultError. Lichess marks deleted/closed accounts with disabled: true and strips most fields; surfacing a row of nulls would be silent-fallback. We surface as EmptyResultError instead so the agent knows the account is gone.
  • tosViolation is true when the account has been flagged for cheating / TOS abuse — important when interpreting their rating progression.
  • progress (top only) is the perf's recent rating delta (last 12 games). null when not enough recent games to compute.
  • fideRating / country / bio are user-supplied profile fields; commonly null for accounts that haven't filled them in.
  • No API key required. Lichess throttles anonymous traffic at ~60 req/min per IP; bursts → CommandExecutionError.
  • Errors. Bad username / unknown perf / bad limit → ArgumentError; unknown / disabled user → EmptyResultError; transport / 429 / non-200 → CommandExecutionError.

Adapters Browser Linkedin Learning (`docs/adapters/browser/linkedin-learning.md`)

LinkedIn Learning

Mode: 🔐 Browser + Cookie · Domain: linkedin.com

Read-only adapter for LinkedIn Learning courses, videos, and learning paths. Shares cookie session with linkedin.com, no Commercial Use Limit (Learning queries are separate from people-search CUL).

Commands

Command Description
opencli linkedin-learning search Search courses, videos, and paths by keyword via learning-api/searchV2
opencli linkedin-learning trending Browse personalized recommendation carousels via learning-api/feedRecommendationGroups
opencli linkedin-learning course Course detail by slug or full /learning/<slug> URL via learning-api/courses?q=slug

Usage Examples

bash
# Search
opencli linkedin-learning search "AI agent"
opencli linkedin-learning search "rust programming" --limit 20

# Personalized recommendations
opencli linkedin-learning trending --limit 10

# Course detail (slug or full URL)
opencli linkedin-learning course agentic-ai-build-your-first-agentic-ai-system
opencli linkedin-learning course https://www.linkedin.com/learning/agentic-ai-build-your-first-agentic-ai-system

# JSON output
opencli linkedin-learning search "data science" -f json

Columns

Column Notes
rank 1-based position in upstream order
type COURSE / VIDEO / LEARNING_PATH / etc
title From headline.title.text
instructor Joined firstName lastName of all authors
difficulty BEGINNER / INTERMEDIATE / etc (uppercase from searchV2)
duration_sec Length in seconds (empty if non-SECOND unit)
rating Average rating to 2 decimals, computed from ratingSum/ratingCount if no averageRating
rating_count Number of ratings
viewers Cumulative viewer count
url https://www.linkedin.com/learning/<slug>
Column Notes
rank 1-based across all carousels in document order
group Carousel title (e.g. "Top picks for you") or annotation (TOP_PICKS)
type Same as search
title Course / video title
difficulty Same as search
viewers Cumulative viewer count
url Course URL

Cards are deduplicated by slug across carousels (first-seen wins).

`course`

Column Notes
title Course title
slug Stable slug used in URL
description Full course description returned by /learning-api/courses?q=slug
difficulty Beginner / Intermediate / etc (mixed case from detail endpoint)
duration_sec Total length in seconds
videos_count Number of videos in the course
rating Average rating to 2 decimals (empty when /courses?q=slug omits ratings; see Caveats)
rating_count Number of ratings (empty when omitted)
released Activation date (YYYY-MM-DD)
url https://www.linkedin.com/learning/<slug>

Prerequisites

Caveats

  • The course-detail endpoint (/learning-api/courses?q=slug) does not always include rating / rating_count even when the search endpoint reports them for the same slug. Use search "<slug words>" to get ratings if needed; a future revision may make a second call to /learning-api/reviews?contentUrn=...&q=findByContent to fill these in.
  • trending returns personalized recommendations (carousel annotation: TOP_PICKS and similar), not a globally-ranked popularity list. The output reflects the logged-in user's recent activity and skills.
  • Voyager search-cluster endpoints (used by the standard linkedin/search jobs adapter and linkedin/people-search) do not serve Learning data; learning-api/* is the dedicated REST surface.

Limit Validation

  • search and trending cap --limit at 50 with strict-integer validation (no silent clamp).
  • course returns exactly one row by definition.

Adapters Browser Linkedin (`docs/adapters/browser/linkedin.md`)

LinkedIn

Mode: 🔐 Browser · Domain: linkedin.com

Commands

Command Description
opencli linkedin connect Send a fail-closed connection request after verifying the exact profile
opencli linkedin inbox List LinkedIn messaging inbox conversations and unread status
opencli linkedin job-detail Read one LinkedIn job page with description, apply URL, workplace type, applicants, and company metadata
opencli linkedin jobs-preferences Read visible LinkedIn Jobs preferences and alert settings without changing them
opencli linkedin people-search Search standard LinkedIn for people by keyword (SSR DOM scrape). Each query counts toward LinkedIn's monthly Commercial Use Limit
opencli linkedin profile-analytics Read visible profile dashboard counters such as profile views, post impressions, and search appearances
opencli linkedin profile-experience Read visible LinkedIn profile experience entries with titles, dates, locations, skills, media, and URLs
opencli linkedin profile-read Read visible profile sections including headline, About, experience, education, services, and featured text
opencli linkedin posts Export visible posts from a LinkedIn profile activity page with engagement metrics
opencli linkedin post-analytics Summarize raw visible LinkedIn post counters without custom scoring or classification
opencli linkedin profile-projects Read visible LinkedIn profile projects with descriptions, dates, skills, media, and URLs
opencli linkedin safe-send Verify exact recipient/thread context before optionally sending a message
opencli linkedin salesnav-inbox List Sales Navigator message conversations with API pagination
opencli linkedin salesnav-message Validate or send a Sales Navigator InMail to an exact lead
opencli linkedin salesnav-search Search Sales Navigator people leads by keyword
opencli linkedin salesnav-thread Return Sales Navigator message history for a thread or lead
opencli linkedin search Search LinkedIn jobs (Voyager API), with optional --details enrichment
opencli linkedin sent-invitations List pending sent LinkedIn invitations
opencli linkedin services-read Read a LinkedIn Services page, including overview, services, availability, pricing, and media metadata
opencli linkedin thread-snapshot Load a LinkedIn messaging thread and return available context
opencli linkedin timeline Read posts from your LinkedIn home feed

Usage Examples

text
/* Detailed source-code truncated for AI context efficiency. */

Output

Always returns: rank · title · company · location · listed · salary · url

When --details is set, each row additionally has:

Column Type Notes
description string | null Full "About the job" body. null if upstream had nothing or fetch failed (see detail_error).
apply_url string | null First apply-labelled link on the page. null if upstream had nothing or fetch failed.
detail_error string | null null on success. Otherwise short reason: 'no url' (row had no jobId), 'fetch failed: <message>' (navigation/parse threw), or 'missing description' (page loaded but body was empty).

Previously the adapter returned description: '', apply_url: '' for both the missing-url path and the silent-catch path — callers couldn't tell upstream gaps apart from fetch failures. The current shape preserves backward compatibility on success and surfaces failures with null + a typed reason on detail_error. Per-row failures still don't abort the batch.

--limit must be between 1 and 100, and --start must be a non-negative integer. LinkedIn login/auth walls abort with AuthRequiredError instead of being folded into detail_error.

Job preference commands

jobs-preferences opens the LinkedIn Jobs page and returns open_to_work, job_titles, locations, job_alerts, preferences_url, alerts_url, and raw_preferences. It reads visible settings only and does not change preferences or alerts.

job-detail accepts a https://www.linkedin.com/jobs/view/ URL and returns title, company, location, workplace_type, job_type, applicants, listed, apply_url, company_url, url, and description. It normalizes the URL to LinkedIn's logged-in job detail surface and combines inline metadata with the rendered description.

Returns rank, name, headline, location, and profile_url from the rendered LinkedIn people-search page. profile_url is the row identity and must be a stable /in/<handle>/ LinkedIn profile URL; malformed extraction payloads fail typed instead of being reported as empty results.

--limit must be between 1 and 10. LinkedIn login/auth walls abort with AuthRequiredError; Commercial Use Limit redirects abort with CommandExecutionError because the page no longer contains a trustworthy result list.

Profile and services commands

profile-read opens a profile URL, or /in/me/ by default, and returns profile_url, name, headline, location, about, about_character_count, about_skills, experience, education, services, and featured. It reads visible profile sections and fails typed if LinkedIn returns an auth wall. Editor-only fields such as about_character_count and about_skills are only populated for the default self-profile flow.

profile-analytics opens a profile URL, or /in/me/ by default, and returns visible dashboard counters: profile_views, post_impressions, search_appearances, followers, connections, plus raw_analytics.

profile-experience opens a profile URL, or /in/me/ by default, resolves it to the profile's Experience detail page, and returns visible experience rows: rank, total_count, title, employment_type, company, date_range, start_date, end_date, location, location_type, description, skills, media, urls, skill_url, media_url, profile_url, and raw_text. If the authenticated profile has no visible Experience section, the command returns EmptyResultError instead of placeholder rows.

services-read accepts either --services-url or a profile URL that links to a Services page. It returns service_url, page_title, overview, availability, work_locations, pricing, services_provided, services_count, media_count, media, messages, and reviews_visibility. Owner-only edit/media fields are only populated for the default self-profile flow.

`posts`

Activity cards can be located through their post permalinks when legacy card classes are absent. Each inferred container must identify a single post. A page with post permalinks but no supported cards reports a layout error rather than an empty profile.

Exports visible rows from a LinkedIn profile activity page. It opens /in/me/recent-activity/all/ by default, or accepts --profile-url https://www.linkedin.com/in/<handle>/.

Returns rank, author, posted_at, body, reactions, comments, reposts, impressions, media, media_urls, url, and raw_text. media_urls only includes non-decorative media or external link URLs that LinkedIn exposes in the rendered card; profile photos and reaction sprites are filtered out.

--limit must be between 1 and 100. LinkedIn login/auth walls abort with AuthRequiredError.

`post-analytics`

Summarizes raw counters from visible LinkedIn profile activity posts. It opens /in/me/recent-activity/all/ by default, or accepts --profile-url https://www.linkedin.com/in/<handle>/.

Returns posts_analyzed, total_reactions, total_comments, total_reposts, total_impressions, posts_with_media, posts_with_urls, latest_posted_at, latest_reactions, latest_comments, latest_reposts, latest_impressions, and latest_url.

This command does not compute custom engagement scores, topic labels, format labels, or recommendations. --limit must be between 1 and 100.

`profile-projects`

Opens a profile URL, or /in/me/ by default, resolves it to the profile's Projects detail page, and returns visible project rows.

Returns rank, title, date_range, associated_with, description, skills, media, urls, profile_url, and raw_text. If the authenticated profile has no visible Projects section, the command returns EmptyResultError instead of emitting placeholder rows.

Messaging commands

inbox returns rank, thread_url, thread_id, person_name, last_message_preview, unread, and timestamp. It loads the LinkedIn messaging page with your browser session, then reuses the page's own messengerConversations API request as the row source instead of scraping the virtualized inbox DOM.

connect and safe-send are write commands but dry-run by default. They only click LinkedIn write actions when --send is explicitly passed. connect requires an exact https://www.linkedin.com/in// URL and verifies the landed profile plus visible name before sending. safe-send requires an exact https://www.linkedin.com/messaging/thread// URL and verifies the landed thread, visible recipient name, composer presence, and optional latest-message guard before filling or sending.

thread-snapshot opens an exact messaging thread URL, validates --max-scrolls before navigation, scrolls for available history, and returns a JSON snapshot suitable for caller-side recipient safety checks.

Sales Navigator commands

salesnav-search uses the Sales Navigator lead search API and returns rank, name, title, company, location, degree, profile_url, lead_url, and recipient_urn. Missing lead identity or malformed API payloads fail typed instead of emitting unaddressable rows.

salesnav-inbox and salesnav-thread use Sales Navigator messaging APIs rather than virtualized DOM rows. They require a signed-in LinkedIn session with Sales Navigator access; auth/API failures and malformed thread payloads fail typed, while a valid empty inbox/thread is reported as an empty result.

salesnav-message is a write command but dry-run by default. It resolves the recipient to a Sales Navigator lead identity, checks profile/credit state, and only sends when --send is explicitly passed. Post-send verification checks the Sales Navigator lead page for sent activity.

sent-invitations reads the pending invitations page for CRM reconciliation and returns rank, name, profile_url, and invited_date_text.

Prerequisites


Adapters Browser Linux Do (`docs/adapters/browser/linux-do.md`)

LINUX DO

Mode: 🔐 Browser · Domain: linux.do

Commands

Command Description
opencli linux-do feed Browse topics (site-wide, by tag, or by category)
opencli linux-do categories List all categories
opencli linux-do tags List popular tags
opencli linux-do search <query> Search topics
opencli linux-do topic View topic posts
opencli linux-do topic-content Read the main topic body as Markdown
opencli linux-do user-topics Topics created by a user
opencli linux-do user-posts Replies posted by a user

feed

Browse topic listings. Defaults to latest topics when called with no arguments.

  • Supports filtering by --tag, --category, or both
  • --tag accepts tag name, slug, or ID
  • --category accepts category name, slug, ID, or Parent / Child path for sub-categories
  • Use --view to switch between latest / hot / top

Basic

bash
# Latest topics (default)
opencli linux-do feed

# Hot topics
opencli linux-do feed --view hot

# Top topics — default period is weekly
opencli linux-do feed --view top
opencli linux-do feed --view top --period daily
opencli linux-do feed --view top --period monthly

# Sort by views descending
opencli linux-do feed --order views

# Sort by created time ascending
opencli linux-do feed --order created --ascending

# Limit results
opencli linux-do feed --limit 10

# JSON output
opencli linux-do feed -f json

Filter by tag

bash
# By tag name, slug, or ID — all equivalent
opencli linux-do feed --tag "ChatGPT"
opencli linux-do feed --tag chatgpt
opencli linux-do feed --tag 3

# Tag + hot view
opencli linux-do feed --tag "ChatGPT" --view hot

# Tag + top view with period
opencli linux-do feed --tag "OpenAI" --view top --period monthly

Filter by category

Supports both top-level and sub-categories. Sub-categories auto-resolve their parent path.

bash
# Top-level category — name, slug, or ID
opencli linux-do feed --category "开发调优"
opencli linux-do feed --category develop
opencli linux-do feed --category 4

# Sub-category
opencli linux-do feed --category "开发调优 / Lv1"
opencli linux-do feed --category "网盘资源"

# Category + hot / top view
opencli linux-do feed --category "开发调优" --view hot
opencli linux-do feed --category "开发调优" --view top --period weekly

Category + tag

Combine --category and --tag to narrow results within a category.

bash
opencli linux-do feed --category "开发调优" --tag "ChatGPT"
opencli linux-do feed --category "网盘资源" --tag "OpenAI"
opencli linux-do feed --category 94 --tag 4 --view top --period monthly

Parameters

Parameter Description Default
--view V latest, hot, top latest
--tag VALUE Tag name, slug, or ID —
--category VALUE Category name, slug, or ID —
--limit N Number of results 20
--order O default, created, activity, views, posts, category, likes, op_likes, posters default
--ascending Sort ascending instead of descending off
--period P all, daily, weekly, monthly, quarterly, yearly (only with --view top) weekly

Output columns: title, replies, created, likes, views, url

categories

List forum categories with optional sub-category expansion.

bash
opencli linux-do categories
opencli linux-do categories --subcategories
opencli linux-do categories --limit 50

When --subcategories is enabled, sub-categories are rendered as Parent / Child so the name value can be copied directly into opencli linux-do feed --category ....

Output columns: name, slug, id, topics, description

tags

List tags sorted by usage count.

bash
opencli linux-do tags
opencli linux-do tags --limit 50

Output columns: rank, name, count, url

Search topics by keyword.

bash
opencli linux-do search "NixOS"
opencli linux-do search "Docker" --limit 10
opencli linux-do search "Claude" -f json

Output columns: rank, title, views, likes, replies, url

topic

View summarized first-page posts within a topic.

bash
opencli linux-do topic 1234
opencli linux-do topic 1234 --limit 50

Notes:

  • content is a plain-text summary extracted from each first-page post
  • Each summary is truncated to 200 characters
  • Use opencli linux-do topic-content for the full main post body in Markdown

Output columns: author, content, likes, created_at

topic-content

Read the main topic body as Markdown.

bash
opencli linux-do topic-content 1234
opencli linux-do topic-content 1234 -f json

Notes:

  • Default output prints the Markdown body directly for copy/paste or piping into LLMs
  • Use -f json if you want a machine-readable wrapper

Output columns: content

user-topics

List topics created by a user.

bash
opencli linux-do user-topics neo
opencli linux-do user-topics neo --limit 10

Output columns: rank, title, replies, created_at, likes, views, url

user-posts

List replies posted by a user.

bash
opencli linux-do user-posts neo
opencli linux-do user-posts neo --limit 10

Output columns: index, topic_user, topic, reply, time, url

Prerequisites


Adapters Browser Lobsters (`docs/adapters/browser/lobsters.md`)

Lobsters

Mode: 🌐 Public · Domain: lobste.rs

Commands

Command Description
opencli lobsters hot Hottest stories
opencli lobsters newest Latest stories
opencli lobsters active Most active discussions
opencli lobsters tag <tag> Stories by tag
opencli lobsters domain <domain> Stories submitted from a specific source domain
opencli lobsters read <short_id> Read a story and its comment tree

Usage Examples

bash
# Quick start
opencli lobsters hot --limit 10

# Filter by tag
opencli lobsters tag rust --limit 5

# Stories from a specific source domain
opencli lobsters domain github.com --limit 10
opencli lobsters domain arxiv.org --limit 5

# Read a specific story (use the short_id surfaced as `id` in any listing)
opencli lobsters read 6cmh6h --limit 25 --depth 2

# JSON output
opencli lobsters hot -f json

Output Columns

Command Columns
hot / newest / active / tag rank, id, title, score, author, comments, created_at, tags, url
domain rank, id, title, score, author, comments, created_at, tags, submission_url, comments_url
read type, author, score, text (POST + L0/L1/… comments, with [+N more replies] stubs)

id is the lobste.rs short_id — pipe it into read to drill into the discussion.

domain returns both submission_url (the underlying article URL on the source site) and comments_url (the lobste.rs discussion page). The legacy listing commands collapse these into a single url (= comments_url).

Prerequisites

None — all commands use the public JSON API, no browser or login required.


Adapters Browser Maimai (`docs/adapters/browser/maimai.md`)

Maimai (脉脉)

Mode: 🔐 Browser · Domain: maimai.cn

Commands

Command Description
opencli maimai search-talents Search Maimai talent profiles with keyword and structured filters

Usage Examples

bash
# Search by keyword
opencli maimai search-talents Java

# Narrow by company and city
opencli maimai search-talents 产品经理 --companies "阿里巴巴,字节跳动" --cities 北京市

# Filter by school, degree, and work years
opencli maimai search-talents 算法 --schools "北京大学,清华大学" --degrees 3 --worktimes 3

# Prioritize recently active candidates
opencli maimai search-talents 运营 --sortby 1 --is_direct_chat 1

# JSON output for downstream processing
opencli maimai search-talents Java --size 10 -f json

Key Filters

  • --positions: filter by role or title
  • --companies: comma-separated current or historical companies
  • --schools: comma-separated school names
  • --provinces / --cities: location filters
  • --worktimes: 1=1-3y, 2=3-5y, 3=5-10y, 4=10+y
  • --degrees: 1=大专, 2=本科, 3=硕士, 4=博士, 5=MBA
  • --professions: industry codes such as 01=互联网, 02=金融
  • --is_211 / --is_985: set to 1 to require those school tiers
  • --sortby: 0=relevance, 1=activity, 2=work_years, 3=education
  • --is_direct_chat: set to 1 to keep only candidates available for direct chat

Prerequisites

  • Chrome running and logged into maimai.cn
  • The logged-in browser should be able to open https://maimai.cn/ent/talents/discover/search_v2
  • Browser Bridge extension installed

Notes

  • page is zero-based, so the first page is --page 0
  • Output includes current company plus a deduplicated historical_companies field from work experience
  • If the command reports login failure, first verify the same Chrome profile can access the talent search page directly

Adapters Browser Manus (`docs/adapters/browser/manus.md`)

manus

Adapter for Manus — the "Hands On AI" autonomous agent web app at manus.im/app.

Auth

Cookie-mode. After the user signs in to https://manus.im/app in the Browser Bridge profile, the session_id cookie carries a JWT that the adapter re-uses as a Bearer token when calling Manus's Connect-RPC backend at https://api.manus.im/.

Commands

Command Description
manus status Account snapshot — email, display name, user ID, membership tier, and headline credit numbers.
manus list [--limit N] [--archived] List recent Manus sessions with round-trippable id values. Hides archived sessions unless --archived is passed. Default --limit 20.
manus read Show full field-level detail for a single session (looked up by the id emitted from manus list).
manus credits Full credit breakdown — total / free / periodic / pro monthly / refresh / max refresh / next refresh / interval.
manus connectors [--limit N] List available Manus connectors (Apify, GitHub, Outlook, Slack, …). Default --limit 50.
manus skills List skills, both user-added (source=user) and system (source=system).

Examples

text
$ opencli manus status
Field: Email                Value: [email protected]
Field: Display Name         Value: Lin Zhongyue
Field: Membership Tier      Value: 60
Field: Total Credits        Value: 12311
Field: Periodic Credits     Value: 12000
Field: Refresh Credits      Value: 300

$ opencli manus list --limit 3
id: 8UcpCxMFLrNk63ZJmzALfV  Title: 制作技术方案路演风格PPT的详细要求  Status: stopped
id: YOpdpcVj7vPFD4gsBfEwVu  Title: Defining Empire: …                Status: stopped

$ opencli manus read 8UcpCxMFLrNk63ZJmzALfV
Field: UID            Value: 8UcpCxMFLrNk63ZJmzALfV
Field: Title          Value: 制作技术方案路演风格PPT的详细要求
Field: Status         Value: SESSION_STATUS_STOPPED
Field: Mode           Value: AGENT_TASK_MODE_HIGH_EFFORT
Field: Credits        Value: 4564

Notes

  • Implementation is API-first: every command issues exactly one Connect-RPC POST against api.manus.im instead of scraping the DOM, so it is resilient to UI re-skins.
  • The CLI surface intentionally excludes destructive / state-changing actions (new task submission, chat replies, archive, delete). Manus's /app route is a pure React SPA with no per-session URL — there is no /app/session/ page — so there is no verifiable post-state for those operations to assert against. They are deliberately out of scope until the Manus team exposes a per-session route or confirmation dialog.
  • manus read calls ListSessions with pageSize=100 and filters in-process. If the matching session lives beyond the first 100 most-recent sessions, the command will report it as not found.
  • Status and Mode are returned as the raw RPC enum strings (SESSION_STATUS_STOPPED, AGENT_TASK_MODE_HIGH_EFFORT, …). Membership Tier is the numeric tier code (e.g. 60).

NOT exposed

  • manus open — /app/session/ returns 404; the SPA has no URL routing for individual sessions.
  • manus new-task , manus chat <message>, manus pause/resume/cancel — destructive state mutations whose effect cannot be verified from a stable post-state (URL never changes, no confirmation dialog).
  • manus delete / manus archive — same reasoning; no confirmation dialog and no URL-anchored post-state.

Adapters Browser Maven (`docs/adapters/browser/maven.md`)

Maven Central

Mode: 🌐 Public · Domain: search.maven.org

Search Maven Central artifacts and pull per-artifact version histories without auth or browser. Two commands.

Commands

Command Description
opencli maven search <query> Search Maven Central by keyword (artifact name, groupId, tag)
opencli maven artifact <coordinate> Version history for groupId:artifactId[:version]

Usage Examples

bash
# Free-text search
opencli maven search jackson --limit 10
opencli maven search "ai.koog" --limit 5

# Version history for a specific artifact (use `coordinate` from search rows)
opencli maven artifact com.fasterxml.jackson.core:jackson-databind --limit 10
opencli maven artifact com.google.guava:guava --limit 5

# Pin to a specific version
opencli maven artifact com.google.guava:guava:33.0.0-jre

# JSON output
opencli maven search jackson -f json

Output Columns

Command Columns
search rank, coordinate, groupId, artifactId, latestVersion, packaging, versions, lastPublished, repository, url
artifact groupId, artifactId, version, packaging, publishedAt, tags, url

The coordinate column from search round-trips into artifact exactly. To pin a single version, append :<version>.

Options

Option Description
query (positional) Free-text query
--limit Max artifacts (1-200, default: 30)

`maven artifact`

Option Description
coordinate (positional) groupId:artifactId or groupId:artifactId:version
--limit Max versions (1-200, default: 20). Ignored when version is pinned.

Caveats

  • Coordinates are validated upfront — groupId and artifactId must be [A-Za-z0-9][A-Za-z0-9._-]* (max 200 chars each). Bad input raises ArgumentError.
  • lastPublished / publishedAt are derived from Solr's epoch-ms timestamp and rendered as second-precision YYYY-MM-DDTHH:MM:SSZ.
  • Maven Central throttles bursts; HTTP 429 surfaces as a typed CommandExecutionError with a retry hint.
  • versions (in search) is the count Solr reports — it includes pre-releases as well as stable versions.

Prerequisites

  • No browser required — uses search.maven.org/solrsearch/select (Solr endpoint).

Adapters Browser Mdn (`docs/adapters/browser/mdn.md`)

MDN Web Docs

Mode: 🌐 Public · Domain: developer.mozilla.org

Search the official Mozilla Developer Network web docs without auth or browser. One command.

Commands

Command Description
opencli mdn search <query> Search MDN Web Docs by keyword

Usage Examples

bash
# Web platform feature search
opencli mdn search fetch --limit 10
opencli mdn search flexbox --limit 5

# JS reference lookups
opencli mdn search "Array.prototype.map"

# Localized search (default: en-US)
opencli mdn search fetch --locale ja --limit 5
opencli mdn search fetch --locale zh-CN --limit 5

# JSON output
opencli mdn search fetch -f json

Output Columns

Command Columns
search rank, title, slug, locale, summary, url

The slug column round-trips into MDN's URL space (https://developer.mozilla.org/<locale>/docs/<slug>).

Options

Option Description
query (positional) Free-text query
--limit Max results (1–50, default: 10)
--locale Doc locale (default: en-US). Allowed: en-US, de, es, fr, ja, ko, pt-BR, ru, zh-CN, zh-TW.

Caveats

  • Only the locales MDN actually publishes are accepted; passing anything else raises ArgumentError.
  • The summary field is MDN's pre-computed search excerpt with whitespace collapsed; it is not the full document body.
  • MDN throttles aggressive bursts; HTTP 429 surfaces as a typed CommandExecutionError with a retry hint.

Prerequisites

  • No browser required — uses developer.mozilla.org/api/v1/search.

Adapters Browser Medium (`docs/adapters/browser/medium.md`)

Medium

Mode: 🌗 Mixed · Domain: medium.com

Commands

Command Description
opencli medium feed Get hot Medium posts, optionally scoped to a topic
opencli medium search Search Medium posts by keyword
opencli medium user Get recent articles by a user
opencli medium tag <tag> Latest articles for a Medium tag (public RSS, no browser)

Usage Examples

bash
# Get the general Medium feed
opencli medium feed --limit 10

# Search posts by keyword
opencli medium search ai

# Get articles by a user
opencli medium user @username

# Topic feed as JSON
opencli medium feed --topic programming -f json

# Latest articles for a tag (public RSS — fastest, no browser)
opencli medium tag programming --limit 10
opencli medium tag artificial-intelligence --limit 20

`tag` columns

rank, title, author, description, categories, published, url

  • description is the full RSS <description> (no silent truncation; pipe through head if you want a preview).
  • categories is comma-joined Medium tags from each item's <category> blocks.
  • published is the original pubDate ISO string when available.

Prerequisites

  • opencli medium search and opencli medium tag can run without a browser (the latter parses medium.com/feed/tag/<tag> RSS)
  • opencli medium feed and opencli medium user require Browser Bridge access to medium.com

Adapters Browser Mercury (`docs/adapters/browser/mercury.md`)

Mercury

Mode: 🔐 Browser · Domain: app.mercury.com

Mercury reimbursements are authenticated browser UI flows. There is no public
API and no stable JSON endpoint for creating an expense, so the adapter drives
the visible Mercury reimbursements page through OpenCLI Browser Bridge. It
creates a draft, uploads a local receipt file, waits for Mercury OCR, then
re-applies the agent-provided fields because OCR can overwrite amount, currency,
date, or merchant.

The write command is deliberately conservative: it stops at Mercury's Review
step and never clicks the final Submit expense button. A human or responsible
agent must inspect the Review page before any final submission.

Commands

Command Description
opencli mercury reimbursement-plan Validate a reimbursement payload locally without opening Mercury
opencli mercury check-login Open Mercury reimbursements and report whether the selected browser profile is logged in
opencli mercury reimbursement-draft Create a reimbursement draft, attach the receipt, correct OCR-overwritten fields, and stop at Review

reimbursement-plan and reimbursement-draft take the same business payload:

Flag Meaning
--receipt Absolute or relative path to a local receipt/proof file
--amount Original-currency positive amount, e.g. 140.00
--currency Original currency code, default CNY
--date Expense date as YYYY-MM-DD
--merchant Merchant name to show in Mercury
--category Mercury expense category, default Marketing & Advertising
--notes Business purpose / reimbursement notes
--ocr-wait-seconds Seconds to wait after receipt upload before reapplying fields, default 8
--close-after-review Close Review after verification; still never submits

Agent Workflow

bash
# 1. Confirm the selected browser profile is logged into Mercury
opencli --profile <profile> mercury check-login -f json

# 2. Validate the payload locally first
opencli mercury reimbursement-plan \
  --receipt /absolute/path/to/receipt.png \
  --amount 140.00 \
  --currency CNY \
  --date 2026-06-26 \
  --merchant "Example Merchant" \
  --category "Marketing & Advertising" \
  --notes "Example business purpose." \
  -f json

# 3. Create the draft and stop at Review
opencli --profile <profile> mercury reimbursement-draft \
  --receipt /absolute/path/to/receipt.png \
  --amount 140.00 \
  --currency CNY \
  --date 2026-06-26 \
  --merchant "Example Merchant" \
  --category "Marketing & Advertising" \
  --notes "Example business purpose." \
  -f json

Expected Results

For check-login:

  • status: "ready" means the profile reached Mercury reimbursements.
  • status: "needs_login" means Mercury redirected to login; sign into Mercury
    in that Chrome/OpenCLI profile and rerun.

For reimbursement-plan:

  • status: "ready" means the local receipt exists and amount/date formats are
    valid.
  • Missing receipt files, non-positive amount strings, malformed currency codes,
    invalid calendar dates, or invalid wait/boolean flags fail before Mercury is
    opened.
  • Output uses the receipt basename, not the absolute local path.

For reimbursement-draft:

  • uploaded: true
  • reviewReady: true
  • submitBlocked: true
  • warnings includes final Submit expense was intentionally not clicked
  • Mercury shows the Review step with the expected receipt, amount, currency,
    date, merchant, category, and notes.

If upload confirmation, required field correction, or the Review postcondition
fails, the command throws a typed error instead of returning a partial success
row. Keep the browser open and inspect Mercury for validation errors.

Testing

Run repository-level checks:

bash
npm run dev -- validate mercury
npm run typecheck
npm run docs:build

Run a local input smoke test:

bash
npm run dev -- mercury reimbursement-plan \
  --receipt /tmp/example-receipt.png \
  --amount 1.00 \
  --currency USD \
  --date 2026-06-30 \
  --merchant "OpenCLI Test Merchant" \
  --category "Office Supplies & Equipment" \
  --notes "OpenCLI adapter smoke test; do not submit." \
  -f json

Run a real UI smoke test only in a test Mercury workspace/profile or with a
harmless test receipt:

bash
npm run dev -- --profile <profile> mercury reimbursement-draft \
  --receipt /absolute/path/to/test-receipt.png \
  --amount 1.00 \
  --currency USD \
  --date 2026-06-30 \
  --merchant "OpenCLI Test Merchant" \
  --category "Office Supplies & Equipment" \
  --notes "OpenCLI adapter smoke test; do not submit." \
  -f json

Pass condition: Mercury stops at Review and the returned row has
submitBlocked: true. Do not click final Submit during smoke tests.

Notes

  • Login is required. This adapter uses the selected OpenCLI browser profile;
    it does not store Mercury credentials or run an OAuth/login flow.
  • Receipt upload targets Mercury's attachment input:
    [data-testid="expense-attachment-upload"]. If Mercury changes that selector,
    upload can fail while the rest of the form remains visible.
  • OCR happens before correction. Mercury OCR can misread currency (for
    example CNY as JPY) or overwrite merchant/amount. The command uploads the
    receipt first, waits, then re-fills fields from the CLI arguments.
  • Review is not submission. reimbursement-draft never presses the final
    Submit expense button. It prepares a draft for inspection.
  • Use original currency. Enter the currency shown on the source receipt
    when Mercury supports it, then verify Mercury's converted reimbursement amount
    on the Review page.
  • Output is intentionally compact. The returned row is a control-plane
    status summary; Mercury remains the source of truth for final visual review.

Troubleshooting

  • needs_login: open Mercury in the same Chrome/OpenCLI profile, finish login,
    then rerun check-login.
  • Upload failure: verify the file exists locally and that Mercury still uses the
    receipt input selector above. The command requires Browser Bridge
    uploadFiles support so it can verify the intended file input.
  • Review failure: inspect Mercury for validation errors; the command may have
    uploaded the receipt and filled fields but failed to reach Review.
  • Category did not commit: custom Mercury dropdowns can be sensitive to UI
    changes. Retry with the exact category label visible in Mercury.

Adapters Browser Midjourney (`docs/adapters/browser/midjourney.md`)

Midjourney

Mode: 🔐 Browser · Domain: www.midjourney.com

Generate, inspect, transform, monitor, and download Midjourney creations through the logged-in Chrome session. Paid commands use the website UI or its same-origin API; they do not require a Discord bot token or a private API key.

Commands

Command Description
opencli midjourney login Open a foreground login flow, or report already_logged_in
opencli midjourney whoami Check login, plan, and subscription state without exposing account identity
opencli midjourney settings Read selected image/video defaults from Create
opencli midjourney quota Show live Fast GPU minutes, conservative batch estimates, and local trend data
opencli midjourney generate Generate images with model routing, references, cost guards, and optional download
opencli midjourney describe Upload one local image and return four Describe suggestions
opencli midjourney history List and filter recent image, video, and derived jobs
opencli midjourney status <job> Read one job's lifecycle and metadata
opencli midjourney action <job> <operation> Rerun, vary, upscale, edit, animate, loop, extend, or cancel
opencli midjourney download <job> Download image originals, raw video, social MP4, or GIF

Start safely

bash
opencli midjourney login
opencli midjourney whoami -f json
opencli midjourney settings -f yaml
opencli midjourney quota -f yaml

# Validate routing and cost without uploading or submitting
opencli midjourney generate "a blue ceramic teapot --ar 1:1" --dry-run -f yaml

generate and paid action operations have two independent cost guards:

  • --max-minutes: reject a command whose conservative estimate is too high.
  • --reserve-minutes: reject a command that would cross the requested remaining-credit floor.

These are safety estimates, not a billing promise. Use quota for the account's live values and compare estimated_minutes with observed_minutes after real jobs.
Eligible Relax-mode image jobs report 0 estimated Fast GPU minutes because they do not draw down that balance; queue availability and plan rules still apply.

Generate images

bash
# V8.2 Standard/SD; downloads all four candidates by default
opencli midjourney generate \
  "a cobalt glass fox, studio product photography --ar 1:1" \
  --model v8.2 --resolution sd --speed fast

# Submit and return the exact job id without waiting
opencli midjourney generate "minimalist lighthouse --ar 3:2" \
  --wait false --skip-download

# Higher-resolution V8.2 batch
opencli midjourney generate "coastal observatory at dusk --ar 16:9" \
  --model v8.2 --resolution hd --max-minutes 1.5

Supported structured models are v8.2, v8.1, v7, v6.1, v6, niji7, and niji6. --model auto respects the selected website version unless a compatibility rule requires a route:

  • Omni Reference routes auto to V7. An explicit incompatible model fails instead of being silently changed.
  • Character Reference (--cref) and multi-prompt weights remain available through native prompt parameters on V6/V6.1/Niji 6.
  • HD image generation is limited to V8.1/V8.2.
  • V8.1/V8.2 Turbo and legacy-only parameters fail before submission.

The positional prompt accepts native Midjourney parameters such as --ar, --seed, --stylize, --weird, --no, --tile, and supported version-specific parameters. The adapter validates combinations it can prove unsafe and leaves the remaining prompt grammar to Midjourney.

References and personalization

Reference options accept a local PNG/JPEG/WEBP/GIF (up to 10 MB), an HTTPS image URL, or a Midjourney /jobs/?index=N URL. Local files are uploaded through the logged-in web composer and correlated with the exact upload response.

bash
# Content/composition reference; repeat the option as a JSON array for multiple files
opencli midjourney generate "a small robot crossing a salt flat" \
  --image-ref '["./pose.png","https://example.com/light.png"]' \
  --image-weight 1.2

# Style image or numeric Style Reference code
opencli midjourney generate "botanical field guide" \
  --style-ref ./ink-style.png --style-weight 250

# V7 Omni Reference; auto routing is explicit in routing_reason
opencli midjourney generate "the same character in a winter station" \
  --omni-ref ./character.png --omni-weight 200 --model auto

# Existing Personalization profile or Moodboard id
opencli midjourney generate "quiet reading room" --profile <profile-or-moodboard-id>

Every paid generation clears any manually pinned/stale web-composer references first. This prevents a no-reference CLI call from inheriting hidden browser state.

Creation Actions and video

Image jobs support:

rerun, rerun-hd, vary-subtle, vary-strong, upscale-subtle, upscale-creative, open-editor, animate-low, animate-high, loop-low, loop-high, and cancel while active.

Video jobs support rerun, extend-low, extend-high, and cancel while active.

bash
opencli midjourney action <image-job> vary-subtle --index 1
opencli midjourney action <image-job> upscale-creative --index 2
opencli midjourney action <image-job> open-editor --index 1

# Start a video and restore account-wide video defaults afterward
opencli midjourney action <image-job> animate-high --index 1 \
  --prompt "slow orbit, the subject turns toward the light" \
  --end-frame ./ending.png --video-resolution sd --batch-size 1

opencli midjourney action <image-job> loop-low --index 1 --batch-size 1
opencli midjourney action <video-job> extend-high --prompt "the camera rises above the skyline"

# Async submit/cancel lifecycle
opencli midjourney action <image-job> animate-low --wait false --batch-size 1
opencli midjourney action <returned-video-job> cancel

Video resolution and batch size are account-wide website settings. The adapter requires a readable baseline, applies requested temporary values, and restores the original values even when preparation, submission, or job correlation fails.

History, status, and downloads

bash
opencli midjourney history --limit 20 --type video --status completed
opencli midjourney history --query "glass fox" -f json
opencli midjourney status <job> -f yaml

# All image candidates, with validated cache reuse
opencli midjourney download <image-job> --kind image --index all --output ./midjourney

# Video exports
opencli midjourney download <video-job> --kind video-raw --index 1
opencli midjourney download <video-job> --kind video-social --index 1
opencli midjourney download <video-job> --kind gif --index 1

Downloads use atomic writes and validate media bytes before accepting a file. Existing non-empty files are reused only when their magic bytes match the expected format (for images, only the .png original counts); use --force to redownload.

Image originals are PNG. A lower-quality JPEG or WebP is saved only when the PNG is confirmed missing (HTTP 404/410/422), and the command warns when that happens. The CDN sits behind a Cloudflare challenge, so download fetches from a tab on cdn.midjourney.com and retries a blocked request (HTTP 403, 429, or 5xx) after 2, 5, and 10 seconds. If it is still blocked, the command fails with the HTTP status and the download command to re-run; it never falls back to a lower-quality file. Because generate downloads after the paid job completes, re-run download, not generate, after such a failure.

Quota interpretation

Midjourney subscription quota is measured in Fast GPU minutes, not a fixed image count. A normal image job returns a grid of four candidates, so sd_batches_remaining is a batch count, not a single-image count.

The adapter intentionally rounds its guards upward from observed jobs:

Work Conservative estimate
Standard/SD image batch 1 Fast GPU minute
HD image batch 1.5 Fast GPU minutes
V7 Omni Reference batch 2 Fast GPU minutes
Subtle/strong variation up to 1 Fast GPU minute
2× upscale 2 Fast GPU minutes
SD video, batch 1/2/4 2 / 4 / 8 Fast GPU minutes
HD video, batch 1/2/4 7 / 13 / 26 Fast GPU minutes

For a fresh 200-minute Basic allocation, the conservative upper bounds are about 200 Standard/SD batches (about 800 candidates), 133 HD batches, or 100 Omni batches if the whole allocation were spent on only that operation. Actual consumption varies; reruns, variations, upscales, video, and failed/blocked jobs change the practical total.

Boundaries

  • open-editor opens the correct image in Midjourney's editor; inpainting, outpainting, pan, zoom, and canvas edits remain