CLI-Anything 学习教程
CLI-Anything 学习教程
一、环境准备
1.1 前置知识
学习 CLI-Anything 前,建议掌握以下知识:
| 知识领域 | 要求程度 | 说明 |
|---|---|---|
| Python | 中级 | 理解类、模块、装饰器 |
| Click 框架 | 基础 | 了解命令行开发 |
| CLI 基础 | 基础 | 熟悉命令行操作 |
| AI Agent 概念 | 基础 | 理解 Agent 工作原理 |
1.2 环境要求
# 系统要求
- Python 3.8+
- pip 包管理器
- Git
# 可选(用于特定应用)
- GIMP 2.10+ (使用 GIMP CLI)
- Blender 3.0+ (使用 Blender CLI)
- LibreOffice 7.0+ (使用 LibreOffice CLI)
1.3 安装步骤
# Step 1: 克隆仓库
git clone https://github.com/HKUDS/CLI-Anything.git
cd CLI-Anything
# Step 2: 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/macOS
# 或 venv\Scripts\activate # Windows
# Step 3: 安装依赖
pip install -r requirements.txt
# Step 4: 验证安装
python -c "import click; print('Click 版本:', click.__version__)"
1.4 项目结构概览
CLI-Anything/
├── cli-anything-plugin/ # Claude Code 插件
│ ├── HARNESS.md # 方法论文档 ⭐
│ ├── repl_skin.py # REPL 接口 ⭐
│ └── commands/
│
├── gimp/agent-harness/ # GIMP CLI 示例
├── blender/agent-harness/ # Blender CLI 示例
├── libreoffice/agent-harness/ # LibreOffice CLI 示例
├── inkscape/agent-harness/ # Inkscape CLI 示例
├── audacity/agent-harness/ # Audacity CLI 示例
└── ... (其他应用)
二、快速开始
2.1 Hello World:使用已有 CLI
让我们先体验一下已有的 GIMP CLI:
# 进入 GIMP CLI 目录
cd gimp/agent-harness
# 查看帮助
python cli.py --help
# 输出示例:
# Usage: cli.py [OPTIONS] COMMAND [ARGS]...
#
# Commands:
# open 打开图像文件
# save 保存图像
# resize 调整图像大小
# crop 裁剪图像
# filter 应用滤镜
# ...
2.2 第一个命令
# 打开并处理图像
python cli.py open /path/to/image.png --resize 800x600 --save output.png
# 批量处理
python cli.py batch /path/to/images/ --filter grayscale --output /path/to/output/
2.3 进入 REPL 模式
# 启动交互式 REPL
python cli.py repl
# REPL 中执行命令
>>> open /path/to/image.png
>>> resize 800x600
>>> filter blur --radius 5
>>> save output.png
>>> exit
三、核心概念
3.1 概念图谱
┌─────────────────────────────────────────────────────────────────┐
│ CLI-Anything 核心概念 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Agent-Native │ │
│ │ 软件设计理念:优先考虑 AI Agent 的控制需求 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ HARNESS.md │ │ ReplSkin │ │ SKILL.md │ │
│ │ 方法论 │ │ 统一接口 │ │ 技能定义 │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 7-Phase Pipeline │ │
│ │ Analyze → Design → Implement → Test → Document → Pub │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
3.2 核心概念详解
Agent-Native Software(Agent 原生软件)
定义: 专为 AI Agent 控制设计的软件架构
特点: - CLI 优先的接口设计 - 结构化的输入/输出 - 完整的错误处理 - 可预测的行为
# Agent-Native 设计示例
# ❌ 传统设计(面向人类)
def process_image():
"""打开图像,用户手动操作"""
# 弹出 GUI 窗口
# 用户点击按钮
pass
# ✅ Agent-Native 设计(面向 AI)
@click.command()
@click.argument('input_path')
@click.option('--output', '-o', required=True)
@click.option('--filter', type=click.Choice(['blur', 'sharpen']))
def process_image(input_path, output, filter):
"""
处理图像
INPUT_PATH: 输入图像路径
"""
# 结构化参数
# 明确的返回值
# 可预测的错误
return {"status": "success", "output": output}
HARNESS.md
定义: 将软件 Agent 化的标准操作流程文档
作用: - 指导 CLI 设计 - 保证一致性 - 作为开发规范
核心内容:
# HARNESS.md 核心规范
## 1. CLI 结构
- 使用 Click 框架
- 遵循命令分组规范
- 统一的参数命名
## 2. 测试要求
- 每个命令至少 3 个测试用例
- 覆盖正常、边界、错误场景
- 100% 通过率
## 3. 文档规范
- 生成 SKILL.md
- 包含使用示例
- 明确错误码
ReplSkin
定义: 跨所有生成 CLI 的统一 REPL 接口
核心功能:
class ReplSkin:
"""统一 REPL 接口"""
def start(self):
"""启动交互式会话"""
def execute(self, command: str) -> dict:
"""执行命令并返回结果"""
def autocomplete(self, partial: str) -> list:
"""命令自动补全"""
def help(self, command: str = None) -> str:
"""显示帮助信息"""
SKILL.md
定义: AI Agent 技能发现和使用的定义文件
结构:
# SKILL.md - [软件名] 技能定义
## 触发条件
当用户需要:
- 编辑图像/照片
- 批量处理图片
- 应用图像滤镜
## 可用命令
### open
打开图像文件
```bash
{app} open <path> [--format <fmt>]
resize
调整图像大小
{app} resize <width> <height> [--keep-aspect]
使用示例
- "帮我调整这张图片到 800x600"
- "批量将所有 PNG 转为 JPG"
### 3.3 术语表
| 术语 | 英文 | 定义 |
|------|------|------|
| **Agent-Native** | Agent Native | 专为 AI Agent 控制设计 |
| **HARNESS** | Harness | 标准化操作流程 |
| **ReplSkin** | REPL Skin | 统一 REPL 接口层 |
| **Agent Harness** | Agent Harness | 为特定应用生成的 CLI 包 |
| **Pipeline** | Pipeline | 7 阶段自动化流程 |
| **SKILL.md** | Skill Definition | Agent 技能定义文件 |
---
## 四、7阶段流水线详解
### 4.1 Phase 1: Analyze(分析)
**目标**: 深度理解目标软件的代码库
**输入**: 源代码
**输出**: 代码结构分析报告
**关键任务**:
```bash
# 分析任务
1. 识别核心模块
2. 理解 API 结构
3. 分析依赖关系
4. 评估可 CLI 化程度
示例输出:
{
"modules": ["core", "image", "filters", "export"],
"api_endpoints": 45,
"cli_candidates": ["open", "save", "resize", "filter"],
"complexity": "medium"
}
4.2 Phase 2: Design(设计)
目标: 设计 CLI 架构和命令结构
输入: 分析报告
输出: CLI 设计文档
设计原则:
1. 一致性 - 命令命名遵循统一规范
2. 可发现性 - 帮助信息清晰完整
3. 可组合性 - 命令可以组合使用
4. 可预测性 - 行为符合预期
CLI 结构设计:
{app}-cli/
├── cli.py # 入口点
├── commands/
│ ├── file.py # 文件操作命令组
│ ├── edit.py # 编辑命令组
│ └── export.py # 导出命令组
└── utils/
├── __init__.py
└── helpers.py
4.3 Phase 3: Implement(实现)
目标: 实现所有 CLI 命令
输入: 设计文档
输出: CLI 代码
实现模板:
# cli.py
import click
from commands import file, edit, export
@click.group()
def cli():
"""{App Name} CLI - Agent-Native Interface"""
pass
cli.add_command(file.file_group)
cli.add_command(edit.edit_group)
cli.add_command(export.export_group)
if __name__ == '__main__':
cli()
# commands/file.py
import click
@click.group(name='file')
def file_group():
"""文件操作命令"""
pass
@file_group.command()
@click.argument('path', type=click.Path(exists=True))
@click.option('--format', '-f', type=click.Choice(['png', 'jpg', 'svg']))
def open(path, format):
"""打开文件"""
# 实现逻辑
click.echo(f"Opened: {path}")
4.4 Phase 4: Plan Tests(规划测试)
目标: 规划测试策略和用例
输入: CLI 代码
输出: 测试计划
测试分类:
测试类型
├── 单元测试
│ └── 每个命令函数
├── 集成测试
│ └── 命令组合
├── 端到端测试
│ └── 完整工作流
└── 错误测试
└── 异常场景
测试计划示例:
## open 命令测试计划
### 正常场景
- TC001: 打开有效的 PNG 文件
- TC002: 打开有效的 JPG 文件
- TC003: 使用 --format 参数
### 边界场景
- TC004: 打开空文件
- TC005: 打开大文件 (>100MB)
### 错误场景
- TC006: 文件不存在
- TC007: 文件格式不支持
- TC008: 权限不足
4.5 Phase 5: Write Tests(编写测试)
目标: 实现所有测试用例
输入: 测试计划
输出: 测试代码
测试模板:
# tests/test_file_commands.py
import pytest
from click.testing import CliRunner
from cli import cli
class TestOpenCommand:
"""open 命令测试"""
@pytest.fixture
def runner(self):
return CliRunner()
def test_open_valid_png(self, runner, tmp_path):
"""TC001: 打开有效的 PNG 文件"""
# 创建测试文件
test_file = tmp_path / "test.png"
test_file.write_bytes(b"fake png content")
# 执行命令
result = runner.invoke(cli, ['file', 'open', str(test_file)])
# 验证
assert result.exit_code == 0
assert "Opened" in result.output
def test_open_nonexistent_file(self, runner):
"""TC006: 文件不存在"""
result = runner.invoke(cli, ['file', 'open', 'nonexistent.png'])
assert result.exit_code != 0
assert "Error" in result.output
4.6 Phase 6: Document(文档化)
目标: 生成完整文档和 SKILL.md
输入: CLI 代码和测试
输出: 文档文件
SKILL.md 模板:
# SKILL.md - {App Name} CLI
## 触发条件
当用户需要:
- {操作类型1}
- {操作类型2}
- {操作类型3}
## 安装
```bash
pip install {app}-cli
可用命令
文件操作
open
打开文件
{app} file open <path> [--format <fmt>]
参数:
- path: 文件路径(必需)
- --format, -f: 文件格式 (png/jpg/svg)
示例:
{app} file open image.png
{app} file open photo.jpg --format jpg
编辑操作
resize
调整大小
{app} edit resize <width> <height> [--keep-aspect]
使用示例
示例 1: 基本图像处理
用户: "帮我把 image.png 调整到 800x600"
执行: {app} file open image.png && {app} edit resize 800 600
示例 2: 批量转换格式
用户: "把所有 PNG 转成 JPG"
执行: {app} batch convert *.png --to jpg
### 4.7 Phase 7: Publish(发布)
**目标**: 发布到各 AI 平台
**输入**: 完整的 Agent Harness 包
**输出**: 发布版本
**发布清单**:
```bash
# 1. 运行所有测试
pytest tests/ -v --cov
# 2. 检查代码质量
flake8 .
mypy .
# 3. 构建分发包
python -m build
# 4. 发布到 PyPI(可选)
twine upload dist/*
# 5. 发布到 AI 平台
# - 复制到 Claude Code skills 目录
# - 上传到技能市场
五、实战案例
5.1 案例 1:使用 Blender CLI
# 进入 Blender CLI 目录
cd blender/agent-harness
# 查看帮助
python cli.py --help
# 创建简单场景
python cli.py scene create --name "MyScene"
# 添加立方体
python cli.py object add cube --position 0,0,0
# 设置材质
python cli.py material set --color "#FF5733" --metallic 0.8
# 渲染
python cli.py render --output render.png --resolution 1920x1080
5.2 案例 2:使用 LibreOffice CLI
# 进入 LibreOffice CLI 目录
cd libreoffice/agent-harness
# 转换文档格式
python cli.py convert document.docx --to pdf --output document.pdf
# 批量转换
python cli.py batch convert *.docx --to pdf --output-dir ./pdfs/
# 提取文本
python cli.py extract text document.pdf --output text.txt
# 合并文档
python cli.py merge doc1.docx doc2.docx --output merged.docx
5.3 案例 3:使用 GIMP CLI
# 进入 GIMP CLI 目录
cd gimp/agent-harness
# 批量调整图片大小
python cli.py batch resize ./images/ --size 800x600 --output ./resized/
# 应用滤镜
python cli.py filter apply blur --radius 5 --input photo.png --output blurred.png
# 转换格式
python cli.py convert image.png --to jpg --quality 90
# 添加水印
python cli.py watermark add logo.png --position bottom-right --opacity 0.5
5.4 案例 4:AI Agent 集成
在 Claude Code 中使用:
# 1. 安装 CLI-Anything 插件
cp cli-anything-plugin ~/.claude/skills/
# 2. 在对话中使用
用户: "帮我处理这张图片,调整到 800x600 并应用模糊滤镜"
Claude Code:
→ 识别任务需要 GIMP CLI
→ 执行命令序列:
1. gimp-cli open image.png
2. gimp-cli resize 800 600
3. gimp-cli filter blur --radius 5
4. gimp-cli save output.png
→ 返回处理结果
六、创建新的 Agent Harness
6.1 准备工作
# 1. 创建项目目录
mkdir my-app-agent-harness
cd my-app-agent-harness
# 2. 创建标准结构
mkdir -p commands tests utils
# 3. 创建必要文件
touch cli.py commands/__init__.py tests/__init__.py
touch SKILL.md HARNESS.md requirements.txt
6.2 实现核心文件
cli.py:
#!/usr/bin/env python3
"""
MyApp CLI - Agent-Native Interface
"""
import click
from commands import file_ops, edit, export
@click.group()
@click.version_option('1.0.0')
def cli():
"""MyApp CLI - Agent-Native Interface for MyApp"""
pass
# 注册命令组
cli.add_command(file_ops.file_group)
cli.add_command(edit.edit_group)
cli.add_command(export.export_group)
if __name__ == '__main__':
cli()
commands/file_ops.py:
"""文件操作命令"""
import click
@click.group(name='file')
def file_group():
"""文件操作命令"""
pass
@file_group.command()
@click.argument('path', type=click.Path(exists=True))
def open(path):
"""打开文件"""
# 调用 MyApp 的实际 API
click.echo(f"Opened: {path}")
@file_group.command()
@click.argument('path', type=click.Path())
@click.option('--format', '-f', default='default')
def save(path, format):
"""保存文件"""
click.echo(f"Saved: {path} as {format}")
6.3 编写测试
tests/test_cli.py:
"""CLI 测试"""
import pytest
from click.testing import CliRunner
from cli import cli
@pytest.fixture
def runner():
return CliRunner()
class TestCLI:
def test_help(self, runner):
"""测试帮助命令"""
result = runner.invoke(cli, ['--help'])
assert result.exit_code == 0
assert 'MyApp CLI' in result.output
def test_version(self, runner):
"""测试版本命令"""
result = runner.invoke(cli, ['--version'])
assert result.exit_code == 0
assert '1.0.0' in result.output
class TestFileCommands:
def test_file_open(self, runner, tmp_path):
"""测试打开文件"""
test_file = tmp_path / "test.txt"
test_file.write_text("test content")
result = runner.invoke(cli, ['file', 'open', str(test_file)])
assert result.exit_code == 0
6.4 生成 SKILL.md
# SKILL.md - MyApp CLI
## 触发条件
当用户需要:
- 操作 MyApp 文件
- 使用 MyApp 进行编辑
- 导出 MyApp 项目
## 安装
```bash
pip install myapp-cli
可用命令
file open
打开文件
myapp-cli file open <path>
file save
保存文件
myapp-cli file save <path> [--format <fmt>]
使用示例
用户: "用 MyApp 打开 project.myapp"
执行: myapp-cli file open project.myapp
### 6.5 运行测试
```bash
# 安装测试依赖
pip install pytest pytest-cov
# 运行测试
pytest tests/ -v
# 查看覆盖率
pytest tests/ --cov=commands --cov-report=html
七、进阶主题
7.1 ReplSkin 高级用法
# 自定义 REPL 行为
from repl_skin import ReplSkin
class MyAppReplSkin(ReplSkin):
"""MyApp 自定义 REPL"""
def __init__(self, cli):
super().__init__(cli)
self.history_file = ".myapp_history"
def pre_execute(self, command: str) -> str:
"""命令预处理"""
# 添加默认参数
if command.startswith("open"):
command += " --verbose"
return command
def post_execute(self, result: dict) -> dict:
"""结果后处理"""
# 添加时间戳
result['timestamp'] = datetime.now().isoformat()
return result
7.2 错误处理最佳实践
# commands/file_ops.py
import click
from typing import Optional
class FileError(Exception):
"""文件操作错误"""
def __init__(self, message: str, code: str):
self.message = message
self.code = code
super().__init__(message)
@file_group.command()
@click.argument('path', type=click.Path())
def open(path):
"""打开文件"""
try:
# 尝试打开文件
result = _do_open(path)
click.echo(click.style(f"✓ Opened: {path}", fg='green'))
except FileNotFoundError:
raise FileError(
f"File not found: {path}",
code="FILE_NOT_FOUND"
)
except PermissionError:
raise FileError(
f"Permission denied: {path}",
code="PERMISSION_DENIED"
)
except Exception as e:
raise FileError(
f"Unexpected error: {str(e)}",
code="INTERNAL_ERROR"
)
def _do_open(path: str) -> dict:
"""实际打开逻辑"""
# 实现细节
pass
7.3 性能优化
# 使用缓存优化
from functools import lru_cache
@lru_cache(maxsize=128)
def get_file_info(path: str) -> dict:
"""获取文件信息(带缓存)"""
# 文件信息通常不会频繁变化
return {
"path": path,
"size": os.path.getsize(path),
"modified": os.path.getmtime(path)
}
# 批量处理优化
import concurrent.futures
@file_group.command()
@click.argument('paths', nargs=-1)
def batch_open(paths):
"""批量打开文件"""
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(_do_open, paths))
click.echo(f"Opened {len(results)} files")
7.4 日志和调试
# utils/logger.py
import logging
import click
def setup_logger(verbose: bool = False):
"""设置日志"""
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
return logging.getLogger('myapp-cli')
# 在命令中使用
@file_group.command()
@click.option('--verbose', '-v', is_flag=True)
def open(path, verbose):
"""打开文件"""
logger = setup_logger(verbose)
logger.debug(f"Opening file: {path}")
# ... 实现
八、常见问题
Q1: 如何处理复杂的软件 API?
A: 使用分层抽象:
# 第一层:API 封装
class MyAppAPI:
def __init__(self):
self._connection = None
def connect(self):
"""建立连接"""
pass
def open_document(self, path):
"""打开文档"""
pass
# 第二层:命令实现
@file_group.command()
def open(path):
api = MyAppAPI()
api.connect()
result = api.open_document(path)
click.echo(result)
Q2: 如何支持异步操作?
A: 使用 asyncio 和 anyio:
import asyncio
import click
async def _async_open(path):
"""异步打开"""
await asyncio.sleep(0.1) # 模拟异步操作
return {"status": "opened", "path": path}
@file_group.command()
@click.argument('path')
def open(path):
"""打开文件"""
result = asyncio.run(_async_open(path))
click.echo(f"Result: {result}")
Q3: 如何实现命令组合?
A: 使用管道或工作流:
# 管道模式
@cli.command()
@click.argument('commands', nargs=-1)
def pipeline(commands):
"""执行命令管道"""
context = {}
for cmd in commands:
parts = cmd.split()
result = cli.main(args=parts, standalone_mode=False)
context.update(result)
return context
# 使用
# myapp-cli pipeline "file open doc.txt" "edit replace old new" "file save output.txt"
Q4: 如何处理大文件?
A: 使用流式处理:
@file_group.command()
@click.argument('path')
def process_large(path):
"""处理大文件"""
chunk_size = 1024 * 1024 # 1MB
with open(path, 'rb') as f:
while chunk := f.read(chunk_size):
# 流式处理
process_chunk(chunk)
click.echo(".", nl=False)
click.echo("\nDone!")
Q5: 如何与 AI Agent 调试?
A: 使用详细日志和 dry-run 模式:
@file_group.command()
@click.option('--dry-run', is_flag=True, help='模拟执行')
@click.option('--verbose', '-v', is_flag=True, help='详细输出')
def open(path, dry_run, verbose):
"""打开文件"""
if dry_run:
click.echo(f"[DRY-RUN] Would open: {path}")
return
if verbose:
click.echo(f"Opening: {path}")
# 实际执行
result = _do_open(path)
if verbose:
click.echo(f"Result: {result}")
九、参考资料
9.1 官方资源
9.2 相关项目
- Claude Code - Anthropic 官方 CLI
- MCP Protocol - Model Context Protocol
- OpenAI Function Calling
9.3 学习路径
┌─────────────────────────────────────────────────────────────────┐
│ CLI-Anything 学习路径 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Week 1: 基础 │
│ ├── 理解 Agent-Native 概念 │
│ ├── 体验已有 CLI(GIMP、Blender) │
│ └── 学习 Click 框架 │
│ │
│ Week 2: 实践 │
│ ├── 阅读 HARNESS.md │
│ ├── 分析现有 Agent Harness 结构 │
│ └── 实现简单命令 │
│ │
│ Week 3: 深入 │
│ ├── 编写测试用例 │
│ ├── 生成 SKILL.md │
│ └── AI Agent 集成测试 │
│ │
│ Week 4: 进阶 │
│ ├── 为新软件创建 Agent Harness │
│ ├── 优化性能 │
│ └── 发布到社区 │
│ │
└─────────────────────────────────────────────────────────────────┘
十、总结
CLI-Anything 是连接 AI Agent 和传统软件的桥梁。通过本教程,你学会了:
- 核心概念: Agent-Native、HARNESS.md、ReplSkin、SKILL.md
- 7 阶段流水线: 从分析到发布的完整流程
- 实战技能: 使用和创建 Agent Harness
- 最佳实践: 错误处理、性能优化、调试技巧
下一步行动: - [ ] 克隆仓库,运行示例 CLI - [ ] 阅读 HARNESS.md 理解方法论 - [ ] 为你常用的软件创建 Agent Harness - [ ] 在 AI Agent 中测试集成
Happy Coding! 🚀