Standardized process for batch migrating commands from external CLI projects (Python/Node/Go, etc.) to opencli.
When to Use
- User says "migrate the commands from xxx-cli"
- User says "see what can be borrowed from the xxx project"
- User says "align with the functionality of xxx-cli"
- When extending opencli for a new platform, an existing third-party CLI tool is discovered
Prerequisites
- Familiar with CLI-EXPLORER.md(adapter development decision tree)
- Familiar with SKILL.md(command reference & templates)
Phase 1: Source Project Analysis
1.1 Clone & Understand the Source Project
# 克隆源项目到 /tmp 做分析
git clone <source_repo_url> /tmp/<source-cli>
Analysis focus:
- Command list: Find all available commands (check the CLI entry file, help output, or README)
- Authentication method: Cookie? API Key? OAuth? Browser automation?
- Data source: Public API? GraphQL? Page scraping?
- Output fields: Which data fields each command returns
1.2 Generate Command Inventory
List all commands in the source project, including:
| Command | Type | API/Method | Output fields |
|---|---|---|---|
xxx feed |
Read | GET /api/feed |
title, author, time |
xxx post |
Write | POST /api/tweet |
status, id |
Phase 2: Feature Comparison Matrix
2.1 Check Existing opencli Commands
ls src/clis/<site>/ # 查看已有适配器
opencli list | grep <site> # 确认已注册命令
2.2 Generate Comparison Matrix
For each source project command, mark one of three statuses:
| Feature | Source project | Existing in opencli | Action |
|---|---|---|---|
| feed | ✅ xxx feed |
❌ None | ✅ Add |
| search | ✅ xxx search |
✅ search.ts |
❌ Already exists, skip |
| hot | ✅ xxx hot |
⚠️ hot.yaml(incomplete) |
✅ Enhance |
| like | ✅ xxx like |
✅ like.ts |
❌ Already exists, skip |
2.3 Filter Migration Targets
Remove existing and low-value ones, keep high-value missing commands, and classify by Read/Write:
Filtering principles:
- ✅ Prioritize high-usage-frequency commands
- ✅ Mark existing but incomplete commands as "Enhance"
- ❌ Skip features unique to the source project but unsupported by the opencli architecture (e.g., those requiring persistent storage)
- ❌ Skip those completely duplicating existing functionality
Phase 3: Batch Implementation
[!IMPORTANT] Before implementation, you must consult CLI-EXPLORER.md to confirm the strategy selection.
3.1 Choose the Implementation Approach
Based on the decision tree classification:
| Category | Approach | Applicable conditions |
|---|---|---|
| Read + simple API | YAML pipeline | Pure fetch/select/map, no complex JS |
| Read + GraphQL/pagination/signing | TypeScript adapter | Requires JS logic |
| Write operations | TypeScript + Strategy.UI |
DOM operations such as click/input |
| Write + API | TypeScript + Strategy.COOKIE/HEADER |
Direct POST API |
3.2 Implementation Order
Read first, then Write; YAML first, then TS:
- Phase A: YAML Read adapters (fastest, usually 10-20 lines each)
- Phase B: TS Read adapters (those requiring evaluate/intercept)
- Phase C: TS Write adapters (requiring UI automation or POST API)
3.3 Implementation Templates
YAML Read adapter template (Cookie strategy)
site: <site>
name: <command>
description: <描述>
domain: www.<site>.com
strategy: cookie
browser: true
args:
limit:
type: int
default: 20
pipeline:
- navigate: https://www.<site>.com
- evaluate: |
(async () => {
const res = await fetch('<api_endpoint>', { credentials: 'include' });
const d = await res.json();
return (d.data?.items || []).map(item => ({
title: item.title,
// ... map source fields
}));
})()
- map:
rank: ${{ index + 1 }}
title: ${{ item.title }}
- limit: ${{ args.limit }}
columns: [rank, title]
TS Write adapter template (UI strategy)
import { cli, Strategy } from '../../registry.js';
cli({
site: '<site>',
name: '<command>',
description: '<描述>',
strategy: Strategy.UI,
args: [{ name: 'target', required: true, help: '<参数说明>' }],
columns: ['status', 'message'],
func: async (page, kwargs) => {
await page.goto(`https://www.<site>.com/${kwargs.target}`);
await page.wait({ text: '<expected_text>', timeout: 10 });
// 获取 snapshot 找到目标按钮
const snapshot = await page.accessibility.snapshot();
// 点击按钮 ...
return [{ status: 'success', message: '<action> completed' }];
},
});
3.4 Reuse Common Patterns
During migration, if you find that multiple adapters share logic, consider extracting it into a src/clis/<site>/utils.ts utility file:
// src/clis/<site>/utils.ts
export async function fetchWithAuth(page, url) { ... }
export function parseItem(raw) { ... }
Phase 4: Verification & Release
4.1 Build verification
npx tsc --noEmit # TypeScript 编译检查
opencli list | grep <site> # 确认所有命令已注册
4.2 Runtime verification (critical!)
Each new command must actually be run:
# Read 命令
opencli <site> <command> --limit 3 -f json
opencli <site> <command> --limit 3 -v # verbose 查看 pipeline
# Write 命令(谨慎!会实际操作)
opencli <site> <command> <test_target>
4.3 Update documentation
After migration is complete, the following files must be updated:
- README.md — Add new command examples in the corresponding platform section
- SKILL.md — Add new commands in the Commands Reference
4.4 Commit & push
git add -A
git commit -m "feat(<site>): migrate <N> commands from <source-cli>
- Phase A: <N> YAML adapters (read operations)
- Phase B: <N> TS adapters (write operations)
- Source: <source_repo_url>"
git push
Checklist
- Source project command inventory generated
- Comparison matrix confirmed, high-value missing commands filtered
- User confirmed migration scope
- Phase A: YAML Read adapters completed
- Phase B: TS Read adapters completed
- Phase C: TS Write adapters completed
-
npx tsc --noEmitCompilation passed - All new commands have been actually run and verified
- README.md updated
- SKILL.md updated
- Committed + pushed
Real-world case reference
rdt-cli → opencli Reddit(2026-03-16)
- Source project:
rdt-cli(25 Python commands) - Filtering result: 13 high-value commands
- Implementation: 7 YAML (read) + 6 TS (write)
- Output: +11 files, +767 lines of code, Reddit adapters from 4 → 15 (+275%)
twitter-cli → opencli Twitter(2026-03-16)
- Source project:
twitter-cli(20+ Python commands) - Filtering result: 11 to be implemented
- Strategy: Read uses
Strategy.COOKIE+ GraphQL fetch, Write usesStrategy.UI