| name | opencli-universal-cli-hub |
| description | Convert websites, Electron apps, and local tools into standardized CLIs for AI agents and humans using OpenCLI's browser automation and adapter framework. |
| triggers | ["help me use OpenCLI to automate this website","create a CLI adapter for this site","drive my browser with OpenCLI commands","convert this website into a command-line tool","write an OpenCLI adapter for scraping data","automate browser actions with OpenCLI","register a local CLI tool with OpenCLI","control my Chrome browser from the terminal"] |
OpenCLI Universal CLI Hub
Skill by ara.so — Devtools Skills collection.
OpenCLI transforms any website, Electron app, or local binary into a standardized command-line interface. It provides AI agents with the ability to operate websites through a logged-in browser, execute built-in adapters for 100+ sites, and create new adapters using browser automation primitives.
Installation
Prerequisites
- Node.js >= 21.0.0
- Chrome or Chromium browser
- Logged-in browser session for target sites
Install OpenCLI CLI
node --version
npm install -g @jackwener/opencli
opencli doctor
Install Browser Bridge Extension
Chrome Web Store (recommended):
Install from Chrome Web Store
Manual Installation:
- Download
opencli-extension-v{version}.zip from GitHub Releases
- Unzip and navigate to
chrome://extensions
- Enable Developer mode
- Click Load unpacked and select the folder
Verify Setup
opencli doctor
Core Concepts
Three Automation Modes
- Built-in Adapters: Pre-built commands for popular sites (Bilibili, Twitter, Reddit, etc.)
- Browser Automation: AI agents operate any website via
opencli browser primitives
- CLI Hub: Expose local tools and Electron apps through unified interface
Browser Sessions
Browser commands require an explicit <session> identifier:
opencli browser work open https://example.com
opencli browser work state
opencli browser work click "button.submit"
opencli browser work close
Multi-Profile Support
opencli profile list
opencli profile rename <contextId> work
opencli profile use work
opencli --profile work browser mysession open https://example.com
Using Built-in Adapters
List Available Commands
opencli list
opencli list bilibili
Common Built-in Commands
opencli hackernews top --limit 5
opencli bilibili hot --limit 10
opencli reddit hot --subreddit programming --limit 20
opencli twitter trending
opencli xiaohongshu hot --limit 15
opencli zhihu hot --limit 10
Browser Automation Primitives
Navigation Commands
opencli browser mysession open https://github.com/trending
opencli browser mysession state
opencli browser mysession back
opencli browser mysession close
Tab Management
opencli browser mysession tab list
opencli browser mysession tab new https://example.com
opencli browser mysession tab select <targetId>
opencli browser mysession tab close <targetId>
opencli browser mysession state --tab <targetId>
Interaction Commands
opencli browser mysession click "button.login"
opencli browser mysession type "input[name='username']" "myuser"
opencli browser mysession fill "input[name='password']" "mypass"
opencli browser mysession select "select#country" "US"
opencli browser mysession keys "Enter"
opencli browser mysession keys "Control+a"
Waiting and Extraction
opencli browser mysession wait "div.content"
opencli browser mysession wait --text "Loading complete"
opencli browser mysession extract "h1.title"
opencli browser mysession get "a.link" --attribute href
opencli browser mysession find "article"
Advanced Commands
opencli browser mysession screenshot output.png
opencli browser mysession scroll --distance 500
opencli browser mysession eval "document.title"
opencli browser mysession network --pattern "api/v1/*"
opencli browser mysession frames
Creating New Adapters
Manual Adapter Creation
opencli browser init mysite/trending
Example Adapter Structure (~/.opencli/clis/mysite/trending/index.js):
import { executeAdapter } from '@jackwener/opencli-core';
export default async function handler(args, context) {
const { limit = 10 } = args;
const session = context.session || 'adapter';
try {
await executeAdapter('browser', [session, 'open', 'https://mysite.com/trending']);
await executeAdapter('browser', [session, 'wait', 'article.post']);
const posts = await executeAdapter('browser', [session, 'extract', 'article.post', '--limit', limit]);
return {
success: true,
data: posts.map(post => ({
title: post.querySelector('h2')?.textContent,
author: post.querySelector()?.,
: post.()?.
}))
};
} {
(, [session, ]);
}
}
Schema Definition (~/.opencli/clis/mysite/trending/schema.json):
{
"name": "trending",
"description": "Get trending posts from mysite",
"arguments": {
"limit": {
"type": "number",
"description": "Number of posts to fetch",
"default": 10
}
},
"output": {
"columns": ["title", "author", "url"]
}
}
Using Recon Workflow
opencli browser recon analyze https://mysite.com/trending
opencli browser recon init mysite/trending
opencli browser recon verify mysite/trending
Site Knowledge Persistence
Store common patterns for reuse:
Plugin Management
Create and Install Plugins
opencli plugin create my-adapters
opencli plugin install file://./my-adapters
opencli plugin install github:username/opencli-adapters
opencli plugin install @myorg/opencli-adapters
opencli plugin list
opencli plugin uninstall my-adapters
Eject and Customize Built-in Adapters
opencli adapter eject zhihu
opencli adapter reset zhihu
External CLI Integration
Register Local Tools
opencli external register gh
opencli external register docker
opencli external register kubectl
opencli gh repo list
opencli docker ps
opencli kubectl get pods
Configuration
External CLIs are registered in ~/.opencli/external.json:
{
"gh": {
"command": "gh",
"description": "GitHub CLI"
},
"docker": {
"command": "docker",
"description": "Docker CLI"
}
}
Environment Variables
export OPENCLI_DAEMON_PORT=19825
export OPENCLI_PROFILE=work
export OPENCLI_WINDOW=foreground
export OPENCLI_BROWSER_CONNECT_TIMEOUT=30
export OPENCLI_BROWSER_COMMAND_TIMEOUT=60
export OPENCLI_CDP_ENDPOINT=ws://localhost:9222
export OPENCLI_CDP_TARGET=detail.1688.com
export OPENCLI_VERBOSE=true
export DEBUG_SNAPSHOT=1
Configuration Files
Global Config (~/.opencli/config.json)
{
"defaultProfile": "work",
"daemonPort": 19825,
"browserTimeout": 60,
"windowMode": "background"
}
Per-Site Config (~/.opencli/sites/mysite/config.json)
{
"auth": "COOKIE",
"baseUrl": "https://mysite.com",
"pattern": "SPA",
"endpoints": {
"trending": "/api/v1/trending"
}
}
Common Patterns
Pattern 1: Simple Data Extraction
export default async function handler(args, context) {
const session = 'extract-session';
await executeAdapter('browser', [session, 'open', args.url]);
await executeAdapter('browser', [session, 'wait', args.selector]);
const data = await executeAdapter('browser', [
session, 'extract', args.selector
]);
await executeAdapter('browser', [session, 'close']);
return { success: true, data };
}
Pattern 2: Form Automation
export default async function handler(args, context) {
const session = 'form-session';
await executeAdapter('browser', [session, 'open', args.url]);
await executeAdapter('browser', [
session, 'fill', 'input[name="email"]', args.email
]);
await executeAdapter('browser', [
session, 'fill', 'input[name="password"]', args.password
]);
await executeAdapter('browser', [session, 'click', 'button[type="submit"]']);
await executeAdapter('browser', [session, 'wait', '.success-message']);
await executeAdapter('browser', [session, 'close']);
return { success: true };
}
Pattern 3: Multi-Tab Workflow
export default async function handler(args, context) {
const session = 'multi-tab';
await executeAdapter('browser', [session, 'open', args.url1]);
const { targetId } = await executeAdapter('browser', [
session, 'tab', 'new', args.url2
]);
const data1 = await executeAdapter('browser', [
session, 'extract', '.content'
]);
const data2 = await executeAdapter('browser', [
session, 'extract', '.content', '--tab', targetId
]);
await executeAdapter('browser', [session, 'close']);
return { success: true, data: { tab1: data1, tab2: data2 } };
}
Pattern 4: Network Interception
export default async function handler(args, context) {
const session = 'network-session';
const networkPromise = executeAdapter('browser', [
session, 'network', '--pattern', 'api/data'
]);
await executeAdapter('browser', [session, 'open', args.url]);
const networkData = await networkPromise;
await executeAdapter('browser', [session, 'close']);
return { success: true, data: networkData };
}
Pattern 5: Authenticated Session
export default async function handler(args, context) {
const session = 'auth-session';
await executeAdapter('browser', [session, 'open', args.url]);
const state = await executeAdapter('browser', [session, 'state']);
if (state.url.includes('/login')) {
throw new Error('Not authenticated. Please log in to Chrome.');
}
const data = await executeAdapter('browser', [
session, 'extract', '.user-content'
]);
await executeAdapter('browser', [session, 'close']);
return { success: true, data };
}
Troubleshooting
Browser Not Connecting
opencli doctor
lsof -i :19825
pkill -f opencli-daemon
Multiple Chrome Profiles
opencli profile list
opencli profile use <alias>
opencli --profile work browser mysession open https://example.com
Empty or Permission Errors
Issue: Commands return empty data or permission errors
Solution: Ensure you're logged in to the target site in Chrome
opencli bilibili hot --limit 5
Adapter Not Found
opencli list | grep mysite
ls ~/.opencli/clis/mysite/
opencli plugin install file://path/to/plugin
Timeout Issues
export OPENCLI_BROWSER_COMMAND_TIMEOUT=120
opencli browser mysession wait "slow-element" --timeout 120000
CDP Connection Issues
export OPENCLI_CDP_ENDPOINT=ws://localhost:9222
export OPENCLI_CDP_TARGET=myapp.com
opencli doctor
Debug Mode
opencli -v browser mysession open https://example.com
export OPENCLI_VERBOSE=true
export DEBUG_SNAPSHOT=1
opencli browser mysession state
Adapter Verification
opencli browser recon init mysite/command
opencli browser recon verify mysite/command
opencli mysite command --limit 5
Best Practices
- Use explicit session names: Helps track browser automation flows
- Always close sessions: Prevents resource leaks (
opencli browser <session> close)
- Handle authentication: Verify login state before executing commands
- Use --tab for multi-tab: Specify
--tab <targetId> when working with multiple tabs
- Store credentials in browser: Let Chrome manage logins, don't hardcode credentials
- Profile separation: Use Chrome profiles for different accounts/contexts
- Error handling: Wrap browser commands in try-finally to ensure cleanup
- Rate limiting: Be respectful of site resources when creating adapters
- Recon first: Use
opencli browser recon analyze before building adapters
- Persist site knowledge: Save patterns to
~/.opencli/sites/<site>/ for reuse