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 相关项目

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 和传统软件的桥梁。通过本教程,你学会了:

  1. 核心概念: Agent-Native、HARNESS.md、ReplSkin、SKILL.md
  2. 7 阶段流水线: 从分析到发布的完整流程
  3. 实战技能: 使用和创建 Agent Harness
  4. 最佳实践: 错误处理、性能优化、调试技巧

下一步行动: - [ ] 克隆仓库,运行示例 CLI - [ ] 阅读 HARNESS.md 理解方法论 - [ ] 为你常用的软件创建 Agent Harness - [ ] 在 AI Agent 中测试集成

Happy Coding! 🚀