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-browserskill 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 viaopencli browserprimitives. - Write new adapters end-to-end with
opencli browser+ theopencli-adapter-authorskill, which guides from first recon through field decoding, code, andopencli 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.
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/searchlist 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.
node --version
npm install @jackwener/opencli2. 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:
- Download the latest
opencli-extension-v{version}.zipfrom the GitHub Releases page. - Unzip it, open
chrome://extensions, and enable Developer mode. - Click Load unpacked and select the unzipped folder.
3. Verify the setup
opencli doctor4. 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:
opencli profile list
opencli profile rename <contextId> work
opencli profile use work
opencli --profile work browser main stateWith 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
opencli list
opencli hackernews top --limit 5
opencli bilibili hot --limit 5For Humans
Use OpenCLI directly when you want a reliable command instead of a live browser session:
opencli listshows every registered command.opencli <site> <command>runs a built-in or generated adapter.opencli doctorhelps 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:
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 researchThis 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)
npx skills add jackwener/opencliOr install only what you need:
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-usageWhich 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:
- Navigate to any URL using your logged-in browser
- Read page content via structured DOM snapshots (not screenshots)
- Interact — click buttons, fill forms, select options, press keys
- Extract data from the page or intercept network API responses
- 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:
skills/opencli-browser/SKILL.md— drive Chrome ad-hoc (navigate, fill forms, click, extract)skills/opencli-adapter-author/SKILL.md— write a new adapter end-to-endskills/opencli-autofix/SKILL.md— repair broken adaptersskills/opencli-usage/SKILL.md— command and site reference
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:
- Recon the site and pick a pattern (SPA / SSR / JSONP / Token / Streaming).
- Discover the right endpoint — network inspection, initial state, bundle search, token trace, or interceptor fallback.
- Pick auth —
PUBLIC/COOKIE/INTERCEPT/UI/LOCAL. - Decode response fields and design output columns.
opencli browser recon analyze→opencli browser recon init <site>/<name>→ write adapter →opencli browser recon verify <site>/<name>.- 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 |
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 |
|
hot frontpage popular search subreddit read user user-posts user-comments upvote upvoted save saved comment subscribe |
|
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 |
| 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
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-transcriptsopencli 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.
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 stepsExit 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:
opencli plugin install github:user/opencli-plugin-my-tool
opencli plugin list
opencli plugin update --all
opencli plugin uninstall my-toolAlbato, 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. Runnode --version, upgrade Node if needed, then retry. - Daemon issues — Check status:
curl localhost:19825/status· View logs:curl localhost:19825/logs
Star History
License
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 toopencli 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.downloadsto 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 |
|---|---|---|
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 | |
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 |
🌐 / 🔐 |
hot search feed user user-posts me post favorites publish delete comments |
🔐 Browser | |
| toutiao | articles hot recommend |
🌐 / 🔐 |
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 |
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 |
explore profile search user followers following follow unfollow like unlike comment save unsave saved |
🔐 Browser | |
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 |
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 —
browsergives 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-authorskill. - Account-safe — Reuses Chrome's logged-in state; your credentials never leave the browser.
- AI Agent ready —
opencli browser *primitives (open/network/state/eval) andadapter init|check|testdrive 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
npm install @jackwener/opencliBrowse without a site adapter
Set up Browser Bridge, then run:
opencli doctor
opencli browser --session work open https://example.com
opencli browser --session work state
opencli browser --session work extract
opencli browser --session work closeInstall the opencli-browser skill so your AI agent can use the same browser primitives:
npx skills add jackwener/opencli --skill opencli-browserBasic Usage
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 outputOutput Formats
All built-in commands support --format / -f:
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 debugTab Completion
OpenCLI supports intelligent tab completion to speed up command input:
# 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
- Installation details
- Browser Bridge setup
- Extending OpenCLI — custom commands and plugins
- Plugins — extend with community adapters
- All available adapters
- For developers / AI agents
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 用于可复用的站点命令。参见 迁移指南。
安装
npm install @jackwener/opencli直接操作网页(无需 adapter)
先完成 Browser Bridge 设置,然后运行:
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:
npx skills add jackwener/opencli --skill opencli-browser基本使用
opencli list # 查看所有命令
opencli hackernews top --limit 5 # 公开 API,无需浏览器
opencli bilibili hot --limit 5 # 浏览器命令
opencli zhihu hot -f json # JSON 输出输出格式
所有命令支持 --format / -f:
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 自动补全,加快命令输入:
# 把自动补全加入 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 browserprimitives 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
.jsadapter into theclis/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 browseron 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:
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 adapterFurther 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.
OpenCLI (CDPBridge)
│ WebSocket (CDP)
▼
localhost:9222 ← ADB forward
│ adb forward
▼
Android device
chrome_devtools_remote ← Chrome's Unix debug socketNo Chrome extension, no daemon process — just a direct CDP WebSocket connection.
Prerequisites
On the Android device:
- Settings → About Phone → tap Build Number 7 times to enable Developer Options
- Settings → Developer Options → enable USB Debugging
- In Chrome for Android, open
chrome://flags, search forDevTools remote debugging, and enable it (Chrome 119+). On older versions this is on by default when USB debugging is active.
On your machine:
- Android Debug Bridge (ADB) installed and on
$PATH - OpenCLI installed (
npm install opencli)
Step-by-Step Setup
1. Connect the device
adb devicesExpected output:
List of devices attached
R5CT443TRDM deviceIf the device shows as unauthorized, check for a "Allow USB Debugging?" prompt on the phone and tap Allow.
2. Forward the CDP port
adb forward tcp:9222 localabstract:chrome_devtools_remote3. Verify the connection
curl http://localhost:9222/jsonA successful response lists the open tabs:
[
{
"id": "3941",
"title": "Hacker News",
"type": "page",
"url": "https://news.ycombinator.com",
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/page/3941"
}
]4. Run any OpenCLI command
export OPENCLI_CDP_ENDPOINT=http://localhost:9222
opencli hackernews top --limit 5Targeting 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:
OPENCLI_CDP_TARGET="twitter" opencli twitter trendingYou can also connect directly to a specific tab's WebSocket URL (from /json):
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:
opencli zhihu hot --help
# Strategy: cookie | Browser: yes | Domain: www.zhihu.comIf you see Strategy: cookie, log into the site on the phone first, then run the command.
Teardown
Remove the port forward when done:
adb forward --remove tcp:9222
# or remove all forwards:
adb forward --remove-allDifferences 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:
# 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 trendingTroubleshooting
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://flagsmay 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
--verboseto 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:
- Preparation: Start Chrome with CDP enabled locally.
- Network Tunnels: Expose that CDP port to your remote server using either SSH Tunnels or Reverse Proxies.
- 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:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/chrome-debug-profile" \
--remote-allow-origins="*"Linux:
google-chrome \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/chrome-debug-profile" \
--remote-allow-origins="*"Windows:
"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.
Method A: SSH Tunnel (Recommended)
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:
ssh -R 9222:localhost:9222 your-server-user@your-server-ipLeave 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:
ngrok http 9222This 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):
export OPENCLI_CDP_ENDPOINT="http://localhost:9222"
opencli doctor # Verify connection
opencli bilibili hot --limit 5 # Test a commandIf you used Method B (Reverse Proxy like ngrok):
# 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 commandTip: If you provide a standard HTTP/HTTPS CDP endpoint, OpenCLI requests the
/jsontarget list and picks the most likely inspectable page target automatically. If multiple page targets exist, you can further narrow selection withOPENCLI_CDP_TARGET(for exampleexample.comorlocalhost:3000).
Tip: Set
OPENCLI_CDP_INIT_SCRIPTto 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 |
| 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:
# Install yt-dlp
pip install yt-dlp
# or
brew install yt-dlpUsage Examples
/* 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
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
opencli plugin install github:jackwener/opencli-plugin-rate-limiterOr 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) |
# 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 BV1WtAGzYEBmLocal installation (without GitHub)
Create the plugin directory:
bashmkdir -p ~/.opencli/plugins/rate-limiterCreate
~/.opencli/plugins/rate-limiter/package.json:json{ "type": "module" }Create
~/.opencli/plugins/rate-limiter/index.js:jsimport { 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)) })Verify it loaded:
bashOPENCLI_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.
// ~/.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
# On the remote machine (or your Mac)
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=92222. SSH Tunnel (If Needed)
If the remote Chrome is on a different machine, create an SSH tunnel:
# 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
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"4. Verify
# Test the connection
curl http://127.0.0.1:9222/json/version
# Run a diagnostic
opencli doctorCI/CD Integration
For CI/CD environments, use a real Chrome instance with xvfb:
::: v-pre
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
opencli convention-audit
opencli convention-audit --site twitter
opencli convention-audit twitter/search
opencli convention-audit --site pixiv -f yaml
opencli convention-audit --strictFormats:
tableprints a grouped human-readable report.yamlis the recommended agent-facing format.jsonis 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 incolumns.camelCase-in-columns: output columns should use stable snake_case keys.missing-access-metadata: every adapter command must declareaccess: 'read' | 'write'.silent-clamp:Math.min(...limit...)can silently change user input instead of throwingArgumentError.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 aslike,save,follow,create, orpostshould 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 isscripts/silent-column-drop-baseline.json.
npm run check:typed-error-lint enforces the silent failure rules in baseline
mode:
silent-clampsilent-empty-fallbacksilent-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:
npm run build
node scripts/check-silent-column-drop.mjs --update-baselineWhen a sweep fixes existing typed-error findings, update the baseline:
npm run build
node scripts/check-typed-error-lint.mjs --update-baselineConventions 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:
- Re-search by title — fragile, may hit a different post for ambiguous
titles, costs an extra round-trip plus quota. - Parse the URL — assumes URL shape stays stable and is regex-able,
often breaks across A/B buckets or after a site redesign. - 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
_idorId(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 exampleread,article, or help
text such asPost 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'sat://did:.../app.bsky.feed.post/...).
If the natural id for your site is a different shape, add the pattern toID_COLUMN_PATTERNS in the script.
How to add an id column to a listing
Find the source field. Most listing endpoints already include the
id in their raw response — they're just dropped before the row is
shaped. Checkfunc's mapper before adding new fetch logic.Pick the column position. Convention is
[rank, id, ...rest, url]
so identifiers stay near the front and the URL stays last.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.Optional: run the advisory script to confirm the manifest reflects
the new column.bashnpm run advise:listing-id-pairing
Advisory script usage
# 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-pairingThe script reads cli-manifest.json, so always rebuild the manifest
(npx tsx src/build-manifest.ts) after touching adapter columns.
Related principles
docs/developer/ts-adapter.md— adapter
authoring conventions, including the requiredaccess: 'read' | 'write'
metadata.- "Output design" reference inside the bundled
opencli-adapter-authorskill — 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:clickresolves the target center and sends
CDPInput.dispatchMouseEventasmouseMoved,mousePressed,mouseReleased. It does not run Playwright's full visible/stable/enabled/
receives-events pipeline.cli/src/native/interaction.rs:select_optiononly handles native<select>by mutating selected options and dispatchingchange.cli/src/native/snapshot.rs: snapshots come fromAccessibility.getFullAXTree, not a DOM walk. Refs carry accessibility
role/name and backend node id.cli/src/native/element.rs: ref resolution first tries the cachedbackendDOMNodeId; if stale, it re-queries the AX tree by role/name/nth.
This is the important stale-ref recovery mechanism.cli/src/native/snapshot.rsandcli/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 asgetbyroleare
simple JS queries that mark an element withdata-agent-browser-located,
then delegate to the same action path.skill-data/core/SKILL.md: the intended agent loop remainssnapshot -> 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.tsandsrc/browser/target-resolver.ts: genericbrowser clickcurrently resolves an element and calls DOMel.click()
first. CDP native click is only a fallback when JS click fails. Radix/MUI/
shadcn controls often open/select onpointerdown,mousedown,mouseup,
orpointerup, soel.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 includingAccessibility.getFullAXTree. - Extension CDP passthrough already allows
Input.dispatchMouseEvent,Accessibility.getFullAXTree, andDOM.getBoxModel. It does not currently
allowDOM.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, andwait downloadare not a consistent first-class CLI surface. browser findis currently CSS-oriented; role/name/label/text locators are
not first-class for agents.
Product Position
OpenCLI has two browser jobs:
- deterministic adapters for known sites,
- 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
actas 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:
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:
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:
- cached
backendNodeId, - AX re-query by role/name/nth in the same frame,
- existing CSS/DOM resolver fallback when the target is not a ref.
The first rollout should be additive:
- keep current
browser stateoutput stable, - Phase 0: add an internal or opt-in AX prototype; do not change the default
browser statetext 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
frameIdparams where CDP supports
them, - cross-origin iframe: dedicated attached target session when available,
- if unsupported: typed
frame_unreachablewith 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:
- resolve target/ref,
- scroll into view when CDP supports it,
- measure a non-zero bounding box,
- 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:
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:
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-totalFor 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:
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 returnnot_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.mdpass.
Phase 1: Ref And Observation Upgrade
Scope:
- decide AX default versus opt-in based on Phase 0 metrics,
- AX-backed
browser stateorbrowser snapshotoption, - 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.getFullAXTreeframeIdparams, - cross-origin iframe AX routing is best-effort. Real Chrome extension smoke
verified thatchrome.debuggermay not expose attachable OOPIF iframe
targets to extensions even afterTarget.setDiscoverTargets,Target.getTargets, andTarget.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 viabrowser 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, andwait 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 withouteval. - Agents can usually avoid inventing CSS selectors.
Phase 3: High-Level Deterministic Helpers
Only after Phase 0/1 metrics justify it:
browser choosefor common custom select/combobox/listbox/menu controls,- optional
browser form inspectandbrowser 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 leastN-1/Nafter recording baseline; - Phase 3 target, only if warranted: deterministic 1-step
chooseafter
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-sourcesso 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:
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-dropBefore 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 untilchooseexists.- Browser command help: explain that
selectis native<select>only. - Troubleshooting: explain
zero_rect,not_visible,disabled,frame_unreachable,stale_ref_unresolved, andnative_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 axfirst? 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 choosematerially 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:
snapshot
click trigger
snapshot
click option
snapshot or get valueIt 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 avoidDOM.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:
- resolve target,
- scroll into view and measure a non-zero target box,
- send CDP
Input.dispatchMouseEventsequence:mouseMoved -> mousePressed -> mouseReleased, - 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 laterbrowser 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
pointerupormousedown, - menu is rendered in a portal.
- trigger opens on
- Material UI-like autocomplete:
- combobox input opens popup,
- option list is outside the trigger subtree.
- Native
<select>remains covered by existingbrowser select.
Pass condition:
- Before PR 1, run and record baseline pass rate. At least one custom fixture
case must fail on the DOMel.click()path. - After PR 1, custom fixture pass rate must be at least
N-1/N, whereNis
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:
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
backendDOMNodeIdas 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.insertTextfor printable text, - keep
fillexact-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 choosein 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.describeNodeto CDP passthrough allowlist, - add
DOM.resolveNodeonly 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
BrowserRefmap, - 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-sourcesso 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
frameIdand cross-origin session id when available,route click/fill/type by ref frame context,
return typed
frame_unreachablewhen 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
chooseuntil it exists.
Quantitative gates:
- Custom dropdown fixtures: record baseline before PR 1, then pass at least
N-1/Ncustom 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-sourceson the form
page and recordsources.dom.refs,sources.ax.refs,frame_sections,approx_tokens,elapsed_ms, and any per-sourceerror. - 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
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-dropBefore merging a default behavior change:
npm test -- --runIf 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
opencli list search --site example
opencli example search --help -f jsonlist 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
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 researchPage 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
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:
- command discovery and registry
- execution and formatting
- browser / daemon / CDP connectivity
- adapter and plugin integration
Runtime Shape
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 loadingCore Modules
CLI Surface
src/main.ts— process entrypointsrc/cli.ts— top-level command tree and built-in command groupssrc/completion.ts/src/completion-fast.ts— shell completion
Discovery, Registry, Execution
src/discovery.ts— discovers built-in adapters, generated adapters, plugins, and manifestssrc/registry.ts— central command registrysrc/registry-api.ts— adapter-facing registration helperssrc/execution.ts— argument validation, lazy loading, and command executionsrc/commanderAdapter.ts— bridges registry metadata into Commander subcommandssrc/output.ts—table,json,yaml,md,csvformattingsrc/serialization.ts— registry and manifest serialization helpers
Browser and Runtime
src/runtime.ts— shared command runtime and target resolutionsrc/daemon.ts— lifecycle and bridge behavior for the local daemonsrc/doctor.ts— browser bridge diagnosticssrc/observation/— trace artifacts, redaction, and structured runtime evidencesrc/interceptor.ts— interception helpers for browser-backed strategiessrc/browser/— Browser Bridge connection and browser-side primitives
Pipeline Engine
src/pipeline/executor.ts— pipeline executionsrc/pipeline/template.ts— template expansionsrc/pipeline/transform.ts— transform helperssrc/pipeline/steps/— concrete steps such as:fetchdownloadbrowserintercepttaptransform
Adapter and Extension Surfaces
clis/— built-in site adapterssrc/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:
opencli process
↔ local daemon
↔ Browser Bridge extension
↔ logged-in Chrome / ChromiumThis 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:
publicfavors direct network accesscookie,intercept,uidepend on a live browser surface
High-Risk Change Zones
Changes in these files usually affect broad command behavior:
src/cli.tssrc/commanderAdapter.tssrc/discovery.tssrc/execution.tssrc/runtime.tssrc/daemon.tssrc/plugin.tssrc/pipeline/**
These areas deserve targeted tests first, then broader validation when the change crosses module boundaries.
Mental Model
The simplest accurate model is:
- OpenCLI discovers command definitions.
- It registers them into one command registry.
- It resolves each invocation through execution + runtime.
- It reaches the target through one of:
- network fetch
- Browser Bridge
- direct CDP
- 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
# 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 linkAdding 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
CliErrorsubclasses instead of rawErrorwhenever possible. PreferAuthRequiredError,EmptyResultError,CommandExecutionError,TimeoutError, andArgumentErrorso 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:
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
opencli <site> <command> --limit 3 -f json # Test your command
opencli <site> <command> -v # Verbose mode for debuggingCode Style
- TypeScript strict mode — avoid
anywhere possible. - ES Modules — use
.jsextensions in imports (TypeScript output). - Naming:
kebab-casefor files,camelCasefor variables/functions,PascalCasefor types/classes. - No default exports — use named exports.
- Errors — throw
CliErrorsubclasses for expected adapter failures; avoid rawErrorfor normal adapter control flow.
Commit Convention
We use Conventional Commits:
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 v4Submitting a Pull Request
- Create a feature branch:
git checkout -b feat/mysite-trending - Make your changes and add tests when relevant
- 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 - Commit using conventional commit format
- 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.mdis updated for new adapters- VitePress sidebar includes the new doc page
README.md/README.zh-CN.mdstay 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.mdREADME.zh-CN.mddocs/skills/references that are linked from user-facing docs
Executive View
The docs are usable, but they are drifting in four visible ways:
- Hard-coded counts and feature claims are stale.
- Developer docs describe an older architecture and older test layout.
- English and Chinese docs are no longer updated with the same rigor.
- Some pages still describe deleted concepts or old workflows.
The highest-value work is:
- Fix the stale facts in
README*,docs/index.md,docs/zh/index.md, anddocs/guide/getting-started.md. - Rewrite
docs/developer/testing.mdanddocs/developer/architecture.mdagainst currentmain. - Make English and Chinese entry docs derive from the same source-of-truth checklist.
- 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.mdREADME.zh-CN.mddocs/guide/getting-started.mddocs/comparison.md
Current problems:
README.mdandREADME.zh-CN.mdstill say90+adapters.docs/guide/getting-started.mdstill says87+pre-built adapters.docs/comparison.mdstill says87+sites.
Current reality:
node dist/src/main.js list --format json | jq 'map(.site) | unique | length'returns106.
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+ sitesover 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.tsclis/twitter/timeline.test.tsclis/reddit/read.test.tsclis/bilibili/dynamic.test.ts
- Those files do not exist.
- It says E2E coverage is
5files. - Current reality is
11E2E files. - It presents
npm testas 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→60find clis -iregex '.*\\.test\\.(ts|js)$' | wc -l→0find tests/e2e -name '*.test.ts' | wc -l→11find 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 checkstargeted validationfull 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-levelclis/. - The architecture diagram is too simplified for the current system and omits important pieces such as:
daemon.tsplugin.ts- update check / diagnostics / runtime detection paths
- It says “3-tier authentication strategy” but lists
5strategies.
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.mddocs/zh/index.md
Current problems:
- Both home pages say:
exploresynthesizecascade
docs/developer/ai-workflow.mdexplicitly 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 primitivesadapter-authoring skillverify 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... exploreis 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:
listvalidateverifybrowserdoctorpluginadapter
Priority 1 — Inconsistent or incomplete
6. Installation pages are inconsistent about runtime support and update flow
Affected files:
README.mdREADME.zh-CN.mddocs/guide/installation.mddocs/zh/guide/installation.md
Current problems:
README.mdsays Node>= 21or Bun>= 1.0.docs/guide/installation.mdanddocs/zh/guide/installation.mdonly mention Node.README.mddocuments skill refresh on update.docs/zh/guide/installation.mdonly 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.mdREADME.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 listanddocs/adapters/index.mdas 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.mdanddocs/zh/index.mdboth kept the deletedexplore / synthesize / cascadelanguage.docs/zh/guide/getting-started.mdcontains a stale built-in command example that should have been caught by parity review.README.mdandREADME.zh-CN.mdboth 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.mdREADME.zh-CN.mddocs/index.mddocs/zh/index.mddocs/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
README.mdREADME.zh-CN.mddocs/index.mddocs/zh/index.mddocs/guide/getting-started.mddocs/zh/guide/getting-started.mddocs/comparison.md
Pass 2 — Rebuild the technical source-of-truth pages
docs/developer/testing.mddocs/developer/architecture.mddocs/guide/installation.mddocs/zh/guide/installation.md
Pass 3 — Prevent the next round of drift
- Add a docs parity checklist to PR workflow.
- Remove exact counts from hand-written copy unless generated.
- 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 with100+. - Remove
explore / synthesize / cascadefrom both home pages. - Remove
explorefromdocs/zh/guide/getting-started.md. - Align install docs on Node/Bun support and skill refresh.
Medium rewrites
- Rewrite
docs/developer/testing.mdfrom current filesystem state. - Rewrite
docs/developer/architecture.mdfrom 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 |
本地验证
先跑改动对应的测试;共享逻辑或跨模块改动再扩大范围。
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:allnpm 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。
可选测试通过环境变量启用:
# 手动运行真实站点、文章下载与 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
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:
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 addsContent-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:
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
readwhen the command only retrieves data from the target product or account. - Use
writewhen 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. downloadandexportcommands arereadwhen 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:
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 withOPENCLI_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 URLpage.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 elementpage.click(selector)— Click an elementpage.type(selector, text)— Type text into an input
The `kwargs` Object
Contains parsed CLI arguments as key-value pairs. Always destructure with defaults:
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:
AuthRequiredErrorfor missing login / cookiesEmptyResultErrorfor empty but valid responsesCommandExecutionErrorfor unexpected API or browser failuresTimeoutErrorfor site timeoutsArgumentErrorfor 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:
# 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/trendingSee 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 |
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_REQUIREDmeans 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 --fulloropencli ctrip whoamifor 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
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=devThe 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.jsclis/1688/auth.jsclis/1point3acres/auth.jsclis/amazon/auth.jsclis/band/auth.jsclis/bilibili/auth.jsclis/boss/auth.jsclis/chaoxing/auth.jsclis/chatgpt/auth.jsclis/claude/auth.jsclis/coupang/auth.jsclis/ctrip/auth.jsclis/deepseek/auth.jsclis/dianping/auth.jsclis/douban/auth.jsclis/doubao/auth.jsclis/douyin/auth.jsclis/dribbble/auth.jsclis/facebook/auth.jsclis/flomo/auth.jsclis/gemini/auth.jsclis/gitee/auth.jsclis/github/auth.jsclis/gmail/auth.jsclis/grok/auth.jsclis/hf/auth.jsclis/hupu/auth.jsclis/instagram/auth.jsclis/jd/auth.jsclis/jianyu/auth.jsclis/jike/auth.jsclis/jimeng/auth.jsclis/ke/auth.jsclis/kimi/auth.jsclis/linkedin/auth.jsclis/linkedin-learning/auth.jsclis/linux-do/auth.jsclis/maimai/auth.jsclis/manus/auth.jsclis/midjourney/whoami.jsclis/notebooklm/auth.jsclis/nowcoder/auth.jsclis/pixiv/auth.jsclis/powerchina/auth.jsclis/quark/auth.jsclis/qwen/auth.jsclis/reddit/auth.jsclis/reddit/whoami.jsclis/rednote/auth.jsclis/reuters/auth.jsclis/slock/whoami.jsclis/suno/auth.jsclis/taobao/auth.jsclis/tiktok/auth.jsclis/toutiao/auth.jsclis/twitter/auth.jsclis/upwork/auth.jsclis/v2ex/auth.jsclis/wechat-channels/auth.jsclis/weibo/auth.jsclis/weread/auth.jsclis/xianyu/auth.jsclis/xiaoe/auth.jsclis/xiaohongshu/auth.jsclis/xiaoyuzhou/auth.jsclis/xueqiu/auth.jsclis/youtube/auth.jsclis/yuanbao/auth.jsclis/zhihu/auth.jsclis/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:
npm install @jackwener/opencli
opencli doctor
npx skills add jackwener/opencli --skill opencli-browserRun the browser loop with a named session:
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 closeReuse 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:
opencli browser --session work click 12
opencli browser --session work state12 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
Method 1: Chrome Web Store (Recommended)
Install OpenCLI from the Chrome Web Store.
Method 2: Download Pre-built Release
- Go to the GitHub Releases page and download the latest
opencli-extension-v{version}.zip. - Unzip the file and open
chrome://extensions, enable Developer mode (top-right toggle). - Click Load unpacked and select the unzipped folder.
Method 3: Load Unpacked Source (For Developers)
- Open
chrome://extensionsand enable Developer mode. - 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.
opencli doctor # Check extension + daemon connectivityTab 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.
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> openandopencli browser --session <session> tab new [url]return atargetId.opencli browser --session <session> tab listprints thetargetIdvalues of tabs that already exist.--tab <targetId>routes a single browser command to that specific tab.tab newcreates a new tab but does not change the default browser target.tab select <targetId>makes that tab the default target for later untargetedopencli 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:
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:
opencli browser --session my-session closeUse 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:
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
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:
OPENCLI_P0_E2E=1 CHROME_PATH=/path/to/chrome npx vitest run tests/e2e/browser-p0-chrome.test.tsThe 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
┌─────────────┐ 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.
opencli daemon stop # Graceful shutdownThe 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
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 inGuide 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.
opencli plugin create my-cnn
cd my-cnn
git init
opencli plugin install file://$(pwd)
opencli my-cnn helloplugin 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.
opencli adapter init cnn/top
# edit ~/.opencli/clis/cnn/top.js
opencli adapter test cnn/top
opencli cnn topUser adapters are loaded from:
~/.opencli/clis/<site>/<command>.jsThis 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:
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.
opencli adapter eject twitter
# edit ~/.opencli/clis/twitter/*.js
opencli adapter reset twitterFiles 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.
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-toolEach 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:
{
"plugins": {
"cnn": { "path": "packages/cnn" },
"reuters": { "path": "packages/reuters" }
}
}opencli plugin install github:user/opencli-plugins
opencli plugin install github:user/opencli-plugins/cnnFor local development, install each sub-plugin directory directly:
opencli plugin install file:///absolute/path/opencli-plugins/packages/cnn
opencli plugin install file:///absolute/path/opencli-plugins/packages/reutersLocal 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)
Install via npm (Recommended)
npm install @jackwener/opencliInstall 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
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
npm install @jackwener/opencli@latest
# If you use the packaged OpenCLI skills, refresh them too
npx skills add jackwener/opencliOr refresh only the skills you actually use:
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-searchVerify Installation
opencli --version # Check version
opencli list # List all commands
opencli doctor # Diagnose connectivityGuide 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
# 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-trendingHow 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
# 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/pluginThe 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:
{
"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:
{
"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
# 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/polymarketHow 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
openclicompatibility range
Updating
Updating any sub-plugin from a monorepo pulls the entire repo and refreshes all sub-plugins:
opencli plugin update polymarket # updates the monorepo, refreshes allUninstalling
opencli plugin uninstall polymarket # removes just this sub-plugin's symlinkWhen 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
my-plugin/
├── package.json
├── my-command.ts
└── README.mdpackage.json:
{
"name": "opencli-plugin-my-plugin",
"version": "0.1.0",
"type": "module",
"peerDependencies": {
"@jackwener/opencli": ">=1.0.0"
}
}my-command.ts:
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:
- Clone —
git clone --depth 1from GitHub - npm install — Resolves regular dependencies
- Host symlink — Links the running
@jackwener/opencliinto the plugin'snode_modules/soimport from '@jackwener/opencli/registry'always resolves against the host - Transpile — Compiles
.ts→.jsviaesbuild(productionnodecannot load.tsdirectly)
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:
git clone https://github.com/vecyang1/opencli-plugin-taobao.git
opencli plugin install ./opencli-plugin-taobao/clis/taobaoFor 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:
opencli plugin uninstall my-plugin
opencli plugin install github:user/opencli-plugin-my-pluginGuide 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.
┌─ 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.
Option A — SSH reverse port forward (recommended)
From your local machine, SSH to the remote with -R to expose your local daemon to the remote's loopback:
ssh -R 19825:127.0.0.1:19825 user@remote-serverWhile 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:
# 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:
autossh -M 0 -N -R 19825:127.0.0.1:19825 user@remote-serverOr as a systemd unit / launchd plist on the local side.
Why this is safe
- The daemon stays bound to
127.0.0.1on your machine. - The tunnel rides on SSH's authenticated transport — no new auth surface.
- If the SSH session drops, the tunnel drops; the remote
openclisimply 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.
Run frps on a public relay you control.
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 = 19825On the remote server, run a second frpc that maps the relay's exposed port back to the remote's
localhost:19825(astcpvisitor or a plaintcpclient+visitor pair). This wayopenclion the remote keeps talking to its own loopback.
::: warning
- Always set a strong
auth.tokenon 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:
# On the remote server
curl -sf http://127.0.0.1:19825/ping && echo "daemon reachable"
opencli doctoropencli 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
openclicalls 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 doctorto 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 itemmay fail withdid not expose product contextif the target is too broad. - Retry on a real item page, refresh the page in Chrome, and if needed narrow the target, for example:
OPENCLI_CDP_TARGET=detail.1688.com opencli 1688 item 841141931191 -f jsonNode API errors
- Make sure you are using Node.js >= 20. Run
node --versionto verify.
Daemon issues
# View extension logs
curl localhost:19825/logs
# Stop the daemon
opencli daemon stop
# Full diagnostics
opencli doctorThe 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 toSIGKILLif the daemon does not release the port within 3 seconds. Manualopencli daemon stopis only needed if SIGKILL itself is rejected (cross-user owner / cross-machine PID file).
Build errors
# Clean rebuild
rm -rf dist/
npm run build
# Type check
npx tsc --noEmitGetting Help
- GitHub Issues — Bug reports and feature requests
- Run
opencli doctorfor 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
# 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 jsonStation Resolution
The <from> and <to> arguments on trains, train, and price accept
any of the following forms; lookup is anchored against the publicstation_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 thanpage.getCookies({url}), because 12306 sets the auth cookies withPath=/otn and CDP Network.getCookies filters by URL path - a barehttps://kyfw.12306.cn URL filter would otherwise hide them. If tk orJSESSIONID 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/initis 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-handshakesecrettoken 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
# 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 jsonPrerequisites
- Chrome running and logged into
1688.com - Browser Bridge extension installed
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/downloadcurrently 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, andshop_idfor follow-up workflows. search --limitdefaults to20and is capped at100.searchdeduplicates with key priority:offer_idfirst, then canonicalitem_url.itemcan be more sensitive to the active browser target thansearchorstore.
Troubleshooting
- If
opencli 1688 itemreportsdid not expose product context, first make sure the open page is a realdetail.1688.comitem 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
# 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 20Common 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
searchandnotifications:- Chrome is running
- You are already logged in to
www.1point3acres.com - Browser Bridge extension is installed
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 intothreadfor 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/lateststart returning empty rows - Listing
--limitvalues are validated upfront and rejected withArgumentErrorif non-positive or above 50 (the page yields ~50 rows max) — no silent clamp thread --page,thread --limit,thread --contentLimit, andnotifications --limitalso 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
# 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 jsonNotes
newsuses the public RSS feed and works without Browser Bridge.hot,search, andarticleuse Browser Bridge and are best run with Chrome open.hot --typeacceptscatalog,renqi,zonghe, andshoucang.
Prerequisites
news: No browser required — uses public RSS feedhot,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
# 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 jsonNotes
searchandhotrun behind Aliyun WAF. The adapter uses a real browser session and browser-contextfetchfor the JSON API onwe.51job.com.detailandcompanyread SSR HTML pages onjobs.51job.com.areaaccepts a known city name or a 6-digit city code. Unknown non-empty values fail fast.companyreturns the fullcompanyIntrotext. 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
# Latest AIbase daily news
opencli aibase news --limit 20
# JSON output
opencli aibase news --limit 10 -f jsonNotes
- Returns
rank,title, and stable articleurl. - Invalid
--limitvalues 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
# 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 jsonPrerequisites
- Chrome running with an active
amazon.comsession in the shared profile - Browser Bridge extension installed
Notes
- This adapter only returns fields visible on public Amazon pages.
bestsellers,movers-shakers,new-releases, andsearchare for candidate discovery;product,offer, anddiscussionare the validation surfaces.offeris the right surface forsold_by,ships_from, and Amazon-retail exclusion.discussionmay 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 toamazon.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
# Quick start
opencli apple-podcasts search --limit 5
# JSON output
opencli apple-podcasts search -f json
# Verbose mode
opencli apple-podcasts search -vPrerequisites
- 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
# 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
# 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 jsonOutput 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 ahttps://k.autohome.com.cn/ URL.
Usage Examples
# 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 jsonOutput 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, usedongchedi search. brandaccepts 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.scoreis the aggregate rating only. The per-review owner-text list loads
from a separate signed XHR and is intentionally not scraped (usedongchedi koubeifor 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. Usedongchedi specsfor 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
opencli baidu-scholar search "大语言模型"
opencli baidu-scholar search "检索增强生成" --limit 5Notes
- 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
# 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
- Chrome running and logged into band.us
- Browser Bridge extension installed
Notes
band_nois the numeric ID in the Band URL:band.us/band/{band_no}/postband bandslists all your bands with theirband_novaluesband postoutput 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
# 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 jsonPrerequisites
- Chrome running and able to open
barchart.com - Browser Bridge extension installed
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
# 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 jsonTopics
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
/* Detailed source-code truncated for AI context efficiency. */Prerequisites
- Chrome running and logged into bilibili.com
- Browser Bridge extension installed
Notes
subtitleincludes the selected track'slanguageandtrack_typeon every row.track_typeisaifor an AI-marked track,ccfor an explicitly non-AI track, andunknownwhen the source does not identify the track type.opencli bilibili feedwithoutuidreads your following feedopencli bilibili feedreads a specific user's dynamicsuser-videosfillslikesfrom one extra medialist request per page (arc/search'svlist[]carries no like count at all, so the column used to read0for every row).likes_knownsays 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 reportlikes: 0, likes_known: falserather than a fake zero. With--order click/stowmost rows fall outside that order and stay unknownfeed,search,user-videosandvideoalso 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), plusbvid,cover,midandface. The display columns (time,date,publish_time,duration,score,author) keep their old meaning and formatopencli bilibili favoritedefaults to the first favorite folder when--fidis omittedfeed-detailexpects the dynamic ID from ahttps://t.bilibili.com/URLcommentsemitsrpid; pass a top-level row'srpidtocomments --parentto read its reply threadcomments --limitaccepts1..50; empty comment lists raiseEmptyResultErrorcomments --topreturns only pinned comments (from the API'stop_replies); it cannot be combined with--parent, and a video with no pinned comment raisesEmptyResultErrorcommentis a write command and refuses to post unless--executeis passedcomment --parentexpects the top-level/rootrpid; nested reply-to-reply targeting is not inferredfollowandunfolloware write commands; they no-op when the current relation already matches the requested state and otherwise re-read/x/relationafter modify before reporting successfollowandunfollowaccept numeric UID, exactspace.bilibili.com/profile URL, or a name that resolves through Bilibili searchcreator-statsuses 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 usecount, duration usesseconds, and documented basis-point rates are normalized topercentin the 0–100 range. Anullvalue 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
# 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 jsonPrerequisites
- No browser required — uses Binance public market-data endpoints
Notes
- Symbols use Binance market format such as
BTCUSDTorETHUSDT - 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:
mainmarketseconomicsindustriestechpoliticsopinionsgreencryptopursuitsfeeds
bloomberg businessweekreads the live Businessweek section page through Browser Bridge because Bloomberg's legacy Businessweek RSS feed is currently empty.bloomberg newsworks 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
# 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/examplePrerequisites
- RSS commands do not require Chrome.
bloomberg businessweekrequires Chrome and the Browser Bridge extension because it reads the section page.bloomberg newsrequires:- Chrome running
- a Chrome session that can already access the target Bloomberg article page
- the Browser Bridge extension
Notes
- Listing commands support
--limitwith a maximum of 20 items. bloomberg feedslists RSS-backed aliases only;businessweekis intentionally absent because it is section-page backed.- If
bloomberg newsfails 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
# 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 jsonPrerequisites
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
# 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 jsonOutput
`search`
| 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/--checkoutmust beYYYY-MM-DD; checkout must be strictly after checkin.--adults1..30,--rooms1..30,--children0..10— out-of-range throwsArgumentError(no silent clamp).--limit1..100,--offset0..1000— out-of-range throwsArgumentError.--langmust be one of the supported Booking locales (e.g.en-us,zh-cn,ja,ko,de,fr,es); anything else throwsArgumentError.--currencymust be a 3-letter ISO 4217 code (USD,JPY,CNY, …); symbols likeUS$throwArgumentError.
Locale handling
The URL path encodes the requested locale (searchresults.<lang>.html) andselected_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 raisesCommandExecutionError 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 viapage.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-parsing8.6as8.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
# Quick start
opencli boss search --limit 5
# JSON output
opencli boss search -f json
# Verbose mode
opencli boss search -vPrerequisites
- Chrome running and logged into zhipin.com
- Browser Bridge extension installed
Adapters Browser Brave (`docs/adapters/browser/brave.md`)
Brave Search
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.comand extract ranked results via DOM queries. - Supports
--offsetfor GET-based pagination. Brave returns approximately 18 results per page. - Results include rank, title, URL, and snippet.
--limitmust be between 1 and 18;--offsetmust 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
# 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 jsonPrerequisites
- Requires Chrome running (Standalone mode will auto-launch) or the Browser Bridge extension.
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
.standaloneclass 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
# 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 jsonOptions
| 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
- Chrome running and logged into mooc2-ans.chaoxing.com
- Browser Bridge extension installed
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
/* 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/detailcommands continue in the same ChatGPT tab. Use--site-session ephemeralfor one-shot isolated tabs. askwaits for the first stable assistant response after sending.sendsubmits only and returns immediately.ask-filetargets 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.historyreads visible/c/links from the ChatGPT sidebar; it does not use private backend APIs.deep-research-resultopens the requested conversation and extracts completed Deep Research output from that conversation's/backend-api/conversation/payload, especiallymetadata.chatgpt_sdk.widget_state.report_message. It does not return a success row when no completed report is present.modelswitches 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, andvery-highselect 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.
imageopens a freshchatgpt.com/newpage before sending the image prompt.- When
--imageis provided, local images are uploaded first and the prompt is sent as an image edit request. imageoutput is plainstatus / file / link, not a markdown table.- When
--sdis 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
- Chrome is running
- You are already logged into
chatgpt.com - Browser Bridge extension is installed
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
# 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/168842570216Columns
`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 engineadapter.
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
# 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 jsonOptions (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
- Chrome running with Browser Bridge extension installed
- Logged in to claude.ai
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 detailinvocations continue in the same Claude page. Pass--site-session ephemeralfor a one-shot tab. --model opusrequires 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;
--thinkis 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 withECONNRESET - 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
# Search CNKI papers
opencli cnki search "large language model"
# Limit returned results
opencli cnki search "retrieval augmented generation" --limit 5Prerequisites
- Chrome running
- Browser Bridge extension installed
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
# 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 jsonOptions
`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) |
`trending`
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 429responses - All numeric values are denominated in the selected
--currency;coinfails fast if CoinGecko returns no market fields for that currency change24hPctis a raw percent (e.g.2.34means+2.34%), not a fraction--limitis validated upfront and rejected withArgumentErrorif non-positive or above 250 (the CoinGeckoper_pageupper 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
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:
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
# 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" --executeWrite 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:
opencli confluence create --space 987654 --title "Runbook" --file runbook.md --executeTo provide Confluence storage XHTML directly:
opencli confluence update 123456 --file page.storage.html --representation storage --executeNotes
updatereads the current page version first and submitsversion.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
CliErrorsubclasses.
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
# 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 7654321Output
`search`
| 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 throwsArgumentError rather than being silently dropped during DOM lookup.
Prerequisites
- Chrome running and logged into coupang.com
- Browser Bridge extension installed
Notes
searchandproductuse the logged-in browser session because Coupang's/np/searchJSON 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
raiseEmptyResultErrorwith 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
# 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 jsonOutput 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
`search`
| 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-Agentper the data-access policy. The adapter sets one automatically. licenseis sourced from the latest version row in the package's version index — crate-level metadata does not carry a license field.recentDownloadsis the rolling 90-day count exposed by the API;downloadsis the lifetime total.keywordsandcategoriesare 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 them.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
# 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 jsonSuggest 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 raiseArgumentError (no silent clamp).
Hotel Listing Columns (`hotel-search`)
| 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 viactrip search/ctrip hotel-suggest).--checkin,--checkout(required) —YYYY-MM-DD, validated as real calendar dates withcheckin < 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 URLpageSizeparam.
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/SHAmetro codes work alongside single-airport codes likePEK/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 oftennull) 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 theround-<from>-<to> results page.
Args:
<from>,<to>(positional, required): 3-letter IATA codes (BJS/SHAmetro codes work alongside single-airport codes likePEK/PVG).--depart,--return(required):YYYY-MM-DD, withreturnon or afterdepart.--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, soflightNo 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 thegetShipLineV2 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 assv.--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 viactrip search; e.g.1for 北京,2for 上海).--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) vssearchType=H
(hotel-suggest). Hotel and BusinessArea rows only appear in theHflavour. - Mainland China suggest rows ship
gdLat/gdLon(gaode). International rows
shipgLat/gLon(wgs84). The adapter picks the first non-zero pair. - Suggest in-band
Result: falseenvelopes are surfaced asCOMMAND_EXEC
typed errors; HTTP non-2xx becomesFETCH_ERROR.
Caveats (browser-mode commands)
- Cookie required:
hotel-search/flightuseStrategy.COOKIEagainsthotels.ctrip.com/flights.ctrip.com. If Ctrip serves a captcha redirect
(suspected bot), anAuthRequiredErroris 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-flightbookingIdsurfaces, all
rows share the search URL. - Round-trip + airline-filter unsupported:
flightis one-way only and
passescabin=Y_S_C_F(all cabins) in v1. Round-trip + advanced filters
tracked in the#1481follow-up. - Hotel SSR page size is server-fixed: passing
&pageSize=Nis 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
# 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 jsonOutput 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 intoarxiv 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 cleanAuthor, Authorstrings. - Search results include CoRR / arXiv mirror entries. These have keys like
journals/corr/abs-2509-05821and round-trip cleanly intopaper. - 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.organd allows up to 15 seconds for normal page verification to settle. If verification remains, it returnsSECURITY_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
# 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
- Chrome running with Browser Bridge extension installed
- Logged in to chat.deepseek.com
usagealso requires access to platform.deepseek.com
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 detailinvocations continue in the same DeepSeek page. Pass--site-session ephemeralfor a one-shot tab. usagenavigates 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,askuses DeepSeek's current default and does not require a model selector, including with--new. Explicit--modelrequires 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--modelto use DeepSeek's default for web search sendrequires an explicit conversation ID; usehistoryto 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
# 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 aaveOutput 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.
tvlandmcapare scalar floats; consumers should format as money. - Parent vs child protocols. "Parent" entries (
isParent=true, e.g.aavecoversaave-v3,aave-v2, etc.) are present onprotocolbut not onprotocols. The adapter aggregates child chains so parents still surface a usefulchainsvalue. change_1d/change_7dare percentages (already as percent, e.g.0.84= +0.84%).- No API key required. DefiLlama throttles unauthenticated traffic; an
HTTP 429surfaces asCommandExecutionError. - Errors. Bad slug →
ArgumentError; unknown slug →EmptyResultError(DefiLlama returnsHTTP 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
# 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 jsonPrerequisites
- 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
# 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/GxJZ4urc9TnKE3kYPrerequisites
- 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 --limitis between 1 and 15 (dianping fixed page size). Default is 15.--cityaccepts a Chinese name (北京/上海), pinyin (beijing/shanghai),
or a numericcityId. When omitted, the cookie's currently-selected city is
used.searchcolumns:rank, shop_id, name, rating, reviews, price, cuisine, district, url.shop_idround-trips intodianping shop.shopreturns afield, valuesheet so missing fields surface asnull
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 throwAUTH_REQUIREDwith the captcha URL. Open the URL
manually in the same Chrome profile, solve the captcha, then retry. - If
dianping shopfails withEMPTY_RESULT, the shop may have been removed
or relocated; verify the id by visitinghttps://www.dianping.com/shop/
in the browser. - If
dianping searchreturns 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
# Look up a complex term
opencli dictionary search serendipity
# Discover phonetics
opencli dictionary search ephemeralPrerequisites
- 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
# 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 jsonOutput 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
`dockerhub search`
| 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 raisesArgumentError. - Anonymous traffic is throttled.
HTTP 429surfaces as a typedCommandExecutionErrorwith a retry hint. - Timestamp columns (
lastUpdated,lastModified,registered) are normalized to second-precisionYYYY-MM-DDTHH:MM:SSZ.
Prerequisites
- No browser required — uses
hub.docker.com/v2/search/repositories/andhub.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 ahttps://www.dongchedi.com/auto/series/ URL.
Usage Examples
# 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 jsonOutput 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. specsis the overview, not the full parameter sheet. The complete
per-trim parameter table lives behind a signed XHR; rather than fabricate it,specsreturns the unsigned SSR overview (dimensions, powertrain, drivetrain,
suspension, airbags). For per-trim names/prices usemodels.koubeiis 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
# 搜索电影
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 jsonPrerequisites
- 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
opencli doubao status
opencli doubao new
opencli doubao send "帮我总结这段文档"
opencli doubao read
opencli doubao ask "请写一个 Python 快速排序示例" --timeout 90Notes
- 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 detailinvocations continue in the same Doubao page. Pass--site-session ephemeralfor a one-shot tab. newfirst tries the visible "New Chat / 新对话" button, then falls back to the new-thread routeaskuses 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
# 账号与作品
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 jsonPrerequisites
- 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
publishrequires--scheduleto be at least 2 hours later and no more than 14 days laterdraftandpublishupload the video through Douyin/ByteDance browser-authenticated APIs, so cookies in the active browser session must be validhashtag suggestexpects a validcover/cover_urivalue produced during the publish pipeline; for normal manual use,hashtag searchandhashtag hotare 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
# 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 jsonshot-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, andshot --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 searchuses browser mode to searchhtml.duckduckgo.comand extract ranked results.duckduckgo suggestuses the public JSON API atduckduckgo.com/ac/— no browser needed.searchsupports--region(e.g.jp-jp,us-en,cn-zh) and--time(d,w,m,y) filters.searchsupports--offsetfor pagination via XHR POST (avoids page navigation issues withform.submit()).
Current limitations
duckduckgo searchrequires browser mode due to anti-bot protections on DuckDuckGo.- The HTML version returns a maximum of 10 results per page;
--limitmust 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
# 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 5Prerequisites
suggestdoes not require Chrome.searchrequires 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
# 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 jsonOptions
| 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.comonce 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
# 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 ubuntuOutput 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
eolStatusis 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
truefor "ongoing support" /falsefor "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`)
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
# 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 jsonOutput
`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
- Chrome running and logged into facebook.com
- Browser Bridge extension installed
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
# 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.BlenderOutput 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
`search`
| 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
appIdis 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 thesearch → appround-trip works without translation.updatedAtnormalisation: Flathub's/searchendpoint emitsupdated_atas unix-seconds (integer);/appstream/emits it as ISO date strings. The adapter normalises/searchto ISO date (YYYY-MM-DD) so both surfaces look consistent.releases[].timestampis a numeric string, not an int — quirk of the appstream layer. The adapter coerces both shapes when picking the latest release.isEolistruefor end-of-life apps (no longer maintained).isFreeLicenseuses Flathub's classification ofproject_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;nullwhen not yet aggregated.mainCategoriesis a single string in/search(e.g.'network'); on/appstream/the broadercategorieslist 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
--limitfrom 1 to 200. Invalid values fail instead of being silently clamped. - Supports
--sinceto filter by update time. - Supports
--slug <cursor>for pagination from a previous memo page. - Returns stable
id/urlfields 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.
--slugpagination 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
# 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 jsonPrerequisites
- 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 fromlocalStoragein 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
--sinceparameter expects a Unix timestamp in seconds (e.g.1735689600= 2025-01-01 00:00:00 UTC). idis the memo slug returned by Flomo andurlopens 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
# 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 jsonOptions
`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. |
modelsdiscovers 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 askmodel 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 trueis combined with--modeland/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 likeproorflashare rejected—use canonical model IDs fromopencli gemini models.When
--modelis omitted,askdoes not change the current model.All other Gemini commands (
image,deep-research, etc.) are unaffected and do not accept--model.askuses plain minimal output and returns only the assistant response text prefixed with💬.imagealso uses plain output and printsstatus / file / linkinstead of a table.imagealways starts from a fresh Gemini chat before sending the prompt.When
--sdis enabled,imagekeeps the generation in Gemini and only prints the conversation link.
Prerequisites
Chrome is running
You are already logged into
gemini.google.comBrowser 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-resultinvocations continue in the same Gemini page. Pass--site-session ephemeralfor 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.
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, andhexagonare self-contained and work on a blank Geometry canvas.add-line,add-circle,add-polygon,list, andinfoneed an already-populated canvas or a bound tab workflow.- For multi-step constructions, prefer one
evalcall with semicolon-separated commands, or use a shape-specific helper liketriangle.
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.
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, andPolygon. ggbApplet.evalCommandGetLabels(...)can return multiple labels for commands likePolygon(...); that is expected.- The source of truth is the page's
ggbAppletAPI. 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). Usegeogebra evalfor advanced GeoGebra syntax that needs broader command text.
Agent Notes
- Start with
opencli doctorif 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 ...oropencli geogebra triangle. - Use unique temporary labels like
OCLIA,OCLIB,OCLICin bound tabs to avoid colliding with the user's existing objects.
Prerequisites
- Chrome running
- Browser Bridge extension installed
- A
www.geogebra.org/geometrypage that has fully loaded
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
# 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 jsonPrerequisites
- Chrome running with Browser Bridge extension installed
- No login required for these public commands
Adapters Browser Github Trending (`docs/adapters/browser/github-trending.md`)
GitHub Trending
Mode: 🌐 Public · Domain: github.com
Commands
| Command | Description |
|---|---|
opencli github-trending repos |
List repositories from GitHub Trending |
Usage Examples
# 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 jsonArguments
| 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/trendingpage. 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
# 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 jsonPrerequisites
- Chrome running and logged into github.com
- Browser Bridge extension installed
Notes
whoamiverifies the current browser cookie session and does not open the login page.loginopenshttps://github.com/loginin 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
# 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 jsonAll 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 whoamito 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
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 5Notes
- 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`)
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 searchsuggest— JSON API, no auth neededtrends— RSS feed, supports different regions
google searchuses browser mode to extract results from google.com.google imagesuses browser mode to extract visible Google Images results. By default it opens image previews and decodes Google'simgurlvalue soimageUrlis the original file URL when Google exposes it. Use--resolve falseto skip preview clicks and return faster thumbnail-only rows.
Current limitations
google searchmay trigger CAPTCHA in Standalone browser mode. Extension mode (with an established Chrome session) is more reliable.google imagesuses the same browser-backed Google session assearch, so it can hit the same CAPTCHA or consent-page limitations.- Google frequently changes its DOM structure. If
searchstops 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
imgurlvalue after the preview opens. - Snippet extraction may return empty for some results depending on Google's layout.
Usage Examples
# 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 10Prerequisites
suggest,news,trendsdo not require Chrome.searchandimagesrequire:- Chrome running (or Standalone mode will auto-launch)
- For best results, use the Browser Bridge extension with an established Google session
Notes
suggestdefaults to--lang zh-CN; other commands default to--lang en.newssupports--langand--regionparameters for localized results.trendstraffic values are raw strings (e.g. "500K+", "1,000,000+"), not numeric.searchoutput includes three result types:result(standard),snippet(featured answer box), andpaa(People Also Ask).imagesoutput includesrank,title,imageUrl,thumbnailUrl,sourceUrl,source,width, andheight. With default preview resolution,imageUrlis the original image URL when Google provides one; otherwise it falls back to the visible thumbnail URL.images --resolve falseskips preview clicks, so it is faster but more likely to return thumbnail URLs inimageUrl.
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
# 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-timeOutput 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). publishedAtisnullby default forversionsto keep the request count at 1. Use--with-timeonly when you actually need the dates.modulereturns 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
opencli gov-law search "人工智能"
opencli gov-law recent --limit 10Notes
- 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_CHANGEDerror
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
opencli gov-policy search "科技创新"
opencli gov-policy recent --limit 10Notes
- Both commands run in browser mode over public pages
searchuses the gov.cn policy search endpoint withdataTypeId=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
# 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 trueOptions
`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
- Chrome is running
- You are already signed into grok.com
- Browser Bridge extension is installed
Notes
readworks in the current tab even without an explicit ID; pair it withstatusto discover the active session ID first.- Grok commands default to persistent site sessions, so consecutive
grok ask/grok read/grok detailinvocations continue in the same Grok page. Pass--site-session ephemeralfor a one-shot tab. askwaits for the streaming reply to stabilize;sendreturns immediately after submission.historyreads the visible sidebar — if Grok lazy-loads older conversations, scroll the sidebar in your browser before re-running, or usedetaildirectly.exportopens the full history dialog and scrolls it to collect realhttps://grok.com/c/conversation URLs. Malformed history rows are treated as selector drift, not silently dropped.export-allvisits each conversation URL and records per-conversationstatus. A page with no visible transcript produces anemptyrow with anerrormessage; malformed transcript rows produce afailedrow; malformed history or manifest identity fails before export.pin,unpin, anddeleteoperate on conversations visible in the sidebar.pin/unpinverify the post-action context-menu state;delete --yesverifies the sidebar entry disappears before returning success.statusreturnsModel/SessionIdasnullwhen they cannot be detected (e.g. page still loading) rather than a string sentinel — branch onnullin agent code.- DOM or product changes on Grok can break composer detection —
opencli grok statusis the quickest sanity check. limitis validated and rejected withArgumentErrorif non-positive or above the documented max (historymax 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
# 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 jsonOutput 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 signedmapi.guazi.comAPI, sobrowsereturns 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
# 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 2Prerequisites
- 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
# 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
# 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 10Common 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/:slugURLs, and stats URLs with anevent=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 truewhen debugging HLTV page structure
or Cloudflare interruptions. - Primary subjects use positional arguments; filters such as
--limit,--period,--ranking,--map, and--versionremain 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
# 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 jsonOutput 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) |
`homebrew popular`
| 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 raisesArgumentError. --typeand--windoware validated against the only values Homebrew analytics actually publishes. Anything else raisesArgumentError.- 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, andformulae.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
# 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 jsonFilters
--tagmaps to Huodongxingtag--citymaps to Huodongxingcity--datemaps to Huodongxingdate--dateTomaps to HuodongxingdateTo--eventType 1filters offline events--eventType 2filters online events--qsfilters 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
# 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 jsonNotes
reply --topic_idmaps to Hupu's APItopicId, for example502for Basketball Newsreply --quote_idis the quoted replypidmentionsreadsmy.hupu.comnotification APIs from the logged-in browser sessionlike/unlike --fiduses the forum ID from thread metadatadetail --replies trueappends top hot replies to the content fieldhot --limitis validated upfront: must be a positive integer in[1, 100]. Out-of-range or non-integer values raiseArgumentError— 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.comandmy.hupu.com - Browser Bridge extension installed
- For
mentions,reply,like, andunlike, 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
# 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 jsonPrerequisites
- 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
# 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 jsonOutput 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
`search`
| 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:
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`)
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
# 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 jsonProfile 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 savedwithout--collectionreturns 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>callsPOST /api/v1/collections/create/with a multipartnamefield. Instagram silently accepts duplicate names — the API just returns a newcollection_ideach time, so dedupe client-side if you care.instagram collection-delete <name-or-id>callsPOST /api/v1/collections/{id}/delete/. Pass either a case-insensitive collection name or a numericcollection_id. If the name resolves to multiple collections (e.g. duplicates fromcollection-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"). Useinstagram savefirst, then move the post in the UI, or extend with the/api/v1/collections/{id}/edit/mutation.
Prerequisites
- Chrome running and logged into instagram.com
- Browser Bridge extension installed
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
# 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 jsonPrerequisites
- Chrome running and logged into jd.com
- Browser Bridge extension installed
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
# 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 jsonPrerequisites
- Chrome running with an active
jianyu360.cnsession - Browser Bridge extension installed
Notes
searchreturns accessible procurement rows withpublished_at,detail_status,project_code,budget_or_limit,url, plus compatiblepublish_time/date.searchkeeps all reachable rows by default.--since_daysenables an explicit recency filter.detailreturns the same structured fields and addsdetail_text+evidence_blocks.- Date fields are normalized to
YYYY-MM-DDwhen date text is detectable. - Results are deduplicated by stable notice id when it is available.
--limitdefaults to20and is capped at50.
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
# 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 jsonListing Columns
feed, search, and user expose id for each post row. Pass that value
directly to opencli jike post for the detail view.
Prerequisites
- Chrome running and logged into web.okjike.com
- Browser Bridge extension installed
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
# 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 10Options (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
- Chrome running and logged into jimeng.jianying.com
- Browser Bridge extension installed
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
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 theissue command. The list replaces the default field list:
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:
opencli jira issue PROJ-123 --fields autoFor Data Center, use a personal access token when available:
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
# 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 jsonOutput Notes
issuereturns an agent-friendly object withkey,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:
export ATLASSIAN_JIRA_ACCEPTANCE_FIELD=customfield_12345
export ATLASSIAN_JIRA_SPRINT_FIELD=customfield_10020
export ATLASSIAN_JIRA_STORY_POINTS_FIELD=customfield_10016Notes
- 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
CliErrorsubclasses.
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
# 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
# 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 10Prerequisites
- Chrome running and logged into
ke.com - Browser Bridge extension installed
Notes
cityuses short city codes such asbj,sh,gz,szdistrictexpects the district slug used in Beike URLs, for examplechaoyangorhaidian
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
# 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 trueOptions
| 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.comUI. usagenavigates 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, orhttps://kimi.com/chat//https://www.kimi.com/chat/URLs only. send/askverify that a new user turn containing the prompt appears after clicking Send.askwaits 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-buttonwrites to the local clipboard, so the command is marked as write access.
Prerequisites
- Chrome is running
- You are already signed into
kimi.com - Browser Bridge extension is installed
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
# 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 jsonPrerequisites
- 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
# 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 chess960Output 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/topPerfGamespicks the perf with the most games played, excluding non-game perfs (puzzle,storm,racer,streak). For most active accounts this isbulletorblitz. For inactive accounts the field surfaces whatever the account played most before going quiet.- Closed accounts →
EmptyResultError. Lichess marks deleted/closed accounts withdisabled: trueand strips most fields; surfacing a row of nulls would be silent-fallback. We surface asEmptyResultErrorinstead so the agent knows the account is gone. tosViolationistruewhen 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).nullwhen not enough recent games to compute.fideRating/country/bioare user-supplied profile fields; commonlynullfor 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
# 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 jsonColumns
`search`
| 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> |
`trending`
| 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
- Chrome running with Browser Bridge extension installed
- Logged in to linkedin.com; Learning shares the cookie session
Caveats
- The course-detail endpoint (
/learning-api/courses?q=slug) does not always includerating/rating_counteven when thesearchendpoint reports them for the same slug. Usesearch "<slug words>"to get ratings if needed; a future revision may make a second call to/learning-api/reviews?contentUrn=...&q=findByContentto fill these in. trendingreturns personalized recommendations (carouselannotation: TOP_PICKSand 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/searchjobs adapter andlinkedin/people-search) do not serve Learning data;learning-api/*is the dedicated REST surface.
Limit Validation
searchandtrendingcap--limitat 50 with strict-integer validation (no silent clamp).coursereturns exactly one row by definition.
Adapters Browser Linkedin (`docs/adapters/browser/linkedin.md`)
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
/* Detailed source-code truncated for AI context efficiency. */Output
`search`
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.
`people-search`
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
- Chrome running and logged into linkedin.com
- Browser Bridge extension installed
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 --tagaccepts tag name, slug, or ID--categoryaccepts category name, slug, ID, orParent / Childpath for sub-categories- Use
--viewto switch between latest / hot / top
Basic
# 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 jsonFilter by tag
# 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 monthlyFilter by category
Supports both top-level and sub-categories. Sub-categories auto-resolve their parent path.
# 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 weeklyCategory + tag
Combine --category and --tag to narrow results within a category.
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 monthlyParameters
| 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.
opencli linux-do categories
opencli linux-do categories --subcategories
opencli linux-do categories --limit 50When --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.
opencli linux-do tags
opencli linux-do tags --limit 50Output columns: rank, name, count, url
search
Search topics by keyword.
opencli linux-do search "NixOS"
opencli linux-do search "Docker" --limit 10
opencli linux-do search "Claude" -f jsonOutput columns: rank, title, views, likes, replies, url
topic
View summarized first-page posts within a topic.
opencli linux-do topic 1234
opencli linux-do topic 1234 --limit 50Notes:
contentis a plain-text summary extracted from each first-page post- Each summary is truncated to 200 characters
- Use
opencli linux-do topic-contentfor the full main post body in Markdown
Output columns: author, content, likes, created_at
topic-content
Read the main topic body as Markdown.
opencli linux-do topic-content 1234
opencli linux-do topic-content 1234 -f jsonNotes:
- Default output prints the Markdown body directly for copy/paste or piping into LLMs
- Use
-f jsonif you want a machine-readable wrapper
Output columns: content
user-topics
List topics created by a user.
opencli linux-do user-topics neo
opencli linux-do user-topics neo --limit 10Output columns: rank, title, replies, created_at, likes, views, url
user-posts
List replies posted by a user.
opencli linux-do user-posts neo
opencli linux-do user-posts neo --limit 10Output columns: index, topic_user, topic, reply, time, url
Prerequisites
- Chrome running and logged into linux.do
- Browser Bridge extension installed
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
# 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 jsonOutput 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
# 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 jsonKey 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 as01=互联网,02=金融--is_211/--is_985: set to1to require those school tiers--sortby:0=relevance,1=activity,2=work_years,3=education--is_direct_chat: set to1to 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
pageis zero-based, so the first page is--page 0- Output includes current company plus a deduplicated
historical_companiesfield 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
$ 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: 4564Notes
- Implementation is API-first: every command issues exactly one Connect-RPC POST against
api.manus.iminstead 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
/approute 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 readcallsListSessionswithpageSize=100and filters in-process. If the matching session lives beyond the first 100 most-recent sessions, the command will report it as not found.StatusandModeare returned as the raw RPC enum strings (SESSION_STATUS_STOPPED,AGENT_TASK_MODE_HIGH_EFFORT, …).Membership Tieris 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
# 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 jsonOutput 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
`maven search`
| 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 —
groupIdandartifactIdmust be[A-Za-z0-9][A-Za-z0-9._-]*(max 200 chars each). Bad input raisesArgumentError. lastPublished/publishedAtare derived from Solr's epoch-mstimestampand rendered as second-precisionYYYY-MM-DDTHH:MM:SSZ.- Maven Central throttles bursts;
HTTP 429surfaces as a typedCommandExecutionErrorwith a retry hint. versions(insearch) 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
# 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 jsonOutput 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
summaryfield is MDN's pre-computed search excerpt with whitespace collapsed; it is not the full document body. - MDN throttles aggressive bursts;
HTTP 429surfaces as a typedCommandExecutionErrorwith 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
# 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
descriptionis the full RSS<description>(no silent truncation; pipe throughheadif you want a preview).categoriesis comma-joined Medium tags from each item's<category>blocks.publishedis the originalpubDateISO string when available.
Prerequisites
opencli medium searchandopencli medium tagcan run without a browser (the latter parsesmedium.com/feed/tag/<tag>RSS)opencli medium feedandopencli medium userrequire Browser Bridge access tomedium.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
# 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 jsonExpected 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: truereviewReady: truesubmitBlocked: truewarningsincludesfinal 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:
npm run dev -- validate mercury
npm run typecheck
npm run docs:buildRun a local input smoke test:
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 jsonRun a real UI smoke test only in a test Mercury workspace/profile or with a
harmless test receipt:
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 jsonPass condition: Mercury stops at Review and the returned row hassubmitBlocked: 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
exampleCNYasJPY) or overwrite merchant/amount. The command uploads the
receipt first, waits, then re-fills fields from the CLI arguments. - Review is not submission.
reimbursement-draftnever presses the finalSubmit expensebutton. 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 reruncheck-login.- Upload failure: verify the file exists locally and that Mercury still uses the
receipt input selector above. The command requires Browser BridgeuploadFilessupport 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
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 yamlgenerate 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
# 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.5Supported 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
autoto 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.
# 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.
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> cancelVideo 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
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 1Downloads 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-editoropens the correct image in Midjourney's editor; inpainting, outpainting, pan, zoom, and canvas edits remain