CLI 工具开发指南

基于 WinClaw CLI工具市场的 CLI 工具开发规范,涵盖渐进式披露、daemon 模式、会话管理等核心模式。

本指南基于 WinClaw CLI工具市场 的实际实现,总结了面向 AI Agent 的 CLI 工具开发规范与最佳实践。所有工具遵循统一的架构模式,确保可组合性和一致的用户体验。

三种工具类型

根据运行特征和状态需求,CLI 工具分为三种类型:

类型特征典型场景示例工具
普通 CLI无状态,执行即退出发消息、导出数据、文件转换agent_feishu, agent_excel, markdown2word
Daemon CLI后台常驻,维持外部连接消息代理、定时调度、长连接服务wechat_agent, agent_cron
Session CLI跨调用保持上下文多轮对话、增量操作agent_cursor

选择哪种类型取决于你的工具是否需要后台持续运行跨调用记住状态。大多数工具属于普通 CLI —— 简单、无副作用、易于组合。

通用规范

以下规范适用于所有三种类型的 CLI 工具。

项目结构

每个 CLI 工具遵循以下标准目录布局:

my_tool/
├── main.go
├── go.mod
├── go.sum
├── cmd/
│   ├── root.go          # 根命令、--help / --skill
│   ├── skill.go         # skill 子命令与 skillSpec 常量
│   ├── version.go       # 版本信息
│   └── <command>.go     # 各子命令实现
└── internal/
    ├── output/          # 统一 JSON 输出
    │   └── output.go
    ├── session/         # 会话管理(Session CLI 需要)
    │   └── session.go
    └── daemon/          # 守护进程(Daemon CLI 需要)
        ├── manager.go
        └── server.go

认证与敏感配置处理(账号密码 / API Key)

如果你的工具需要账号、密码、Token、API Key 等敏感参数,不要要求用户每次手动拼接到命令行中。推荐通过配置文件注入。

参考 execute_external_tool_resolver.py 的行为,工具执行时会按以下顺序查找配置:

  1. 工具同目录下的 <tool_basename>.key
  2. 工具同目录下的 <tool_filename>.key(兼容旧命名)
  3. ~/.<tool_basename>/config.key
  4. ~/.<tool_basename>/config.json

其中第 3/4 条就是用户最常用方式:在用户主目录下创建 ~/.<name>/ 并放入 config.keyconfig.json

推荐目录

~/.<name>/
├── config.key
└── config.json

config.keyconfig.json 二选一即可;如果同时存在,优先使用 config.key

config.key 示例(YAML)

global:
  group-id: "1764789583133814932"
  api-key: "your_api_key"

config.json 示例(JSON)

{
  "global": {
    "group-id": "1764789583133814932",
    "api-key": "your_api_key"
  }
}

高级用法:按子命令注入参数

你可以通过 subcommands + _params 为不同子命令路径注入不同凭据,同时支持:

  • param_style: "space"(默认,生成 --key value
  • param_style: "equals"(生成 --key=value
  • param_prefix(默认 --,可改为 -

注意事项

  • 帮助命令(--help / -h / help / --skill)不会自动注入敏感参数。
  • 执行日志会对敏感值做掩码显示,避免明文泄露。

渐进式披露:--help 与 --skill

渐进式披露是本工具体系的核心设计模式。用户(或 AI Agent)可以按需获取不同深度的信息:

三层信息架构

第一层: tool --help         → 功能概览、命令列表、快速入门
第二层: tool <cmd> --help   → 某个子命令的参数详情和用法
第三层: tool --skill        → 完整最佳实践、典型场景、工作流指南

--help:功能与参数描述

--help 负责回答「这个工具能做什么」和「参数怎么用」。

根命令 --help 应包含:

  • 工具的功能简述
  • 可用命令列表及简要说明
  • 快速入门示例
  • 引导用户查看 --skill 获取更多信息

agent_feishu 为例,使用 Cobra 框架实现根命令:

rootCmd = &cobra.Command{
    Use:   "agent_feishu",
    Short: "A CLI tool for Feishu bot operations, designed for AI agents",
    Long: `agent_feishu is a command-line tool that provides Feishu (Lark) bot operations
through a set of composable commands, designed for AI agent workflows.

Key Features:
  - Send text, image, and file messages to Feishu chats
  - User management with local caching for fast lookups

Quick Start:
  agent_feishu initapi --app-id "cli_xxx" --app-secret "xxx"
  agent_feishu send-text --receive-id "ou_xxx" --receive-type "open_id" --text "Hello!"

Use 'agent_feishu --skill' or 'agent_feishu skill' for detailed command specifications.

For more information about a specific command, use:
  agent_feishu [command] --help`,
    Version: version,
    Run: func(cmd *cobra.Command, args []string) {
        if showSkill {
            fmt.Print(skillSpec)
            return
        }
        cmd.Help()
    },
}

子命令 --help 应包含:

  • 子命令的功能说明
  • 所有参数(必选/可选)的详细描述
  • 使用示例
  • 引导到更深层子命令的 --help
var tableCmd = &cobra.Command{
    Use:   "table",
    Short: "Table operations (add, delete)",
    Long: `Manage tables in a Feishu Bitable app.

Use 'agent_bitable table <subcommand> --help' for more information.`,
}

多级子命令的信息披露路径:

agent_bitable --help              → 所有顶级命令概览
agent_bitable record --help       → record 命令组概览
agent_bitable record list --help  → list 子命令参数详情
agent_bitable --skill             → 完整工作流和场景指南

--skill:最佳实践与工作流

--skill 负责回答「我应该如何使用这个工具完成特定任务」。这是面向 AI Agent 的核心接口,提供完整的操作指南。

--skill 应包含:

  1. 概述 — 工具定位与核心能力
  2. 前置条件 — 认证、环境变量、依赖
  3. 最佳实践流程 — 推荐的操作步骤
  4. 典型场景 — 针对不同目标的完整操作路径
  5. 命令参考 — 所有命令的详细参数
  6. 输出格式 — JSON 结构说明
  7. 错误处理 — 常见错误及应对策略
  8. 与其他工具的组合 — 如何与其他 agent_* 工具配合

--skill 通过两种方式提供,确保访问便利性:

方式一:根命令的 --skill 标志

func init() {
    rootCmd.Flags().BoolVar(&showSkill, "skill", false,
        "Show the detailed command specification for agent_feishu")
}

方式二:skill 子命令

var skillCmd = &cobra.Command{
    Use:   "skill",
    Short: "Show detailed command specification",
    Long:  `Display the complete skill specification, designed for AI agents.`,
    Run: func(cmd *cobra.Command, args []string) {
        cmd.Print(skillSpec)
    },
}

func init() {
    rootCmd.AddCommand(skillCmd)
}

两种方式输出同一个 skillSpec 常量:

const skillSpec = `# agent_feishu Skill Specification

A CLI tool for Feishu bot operations, designed for AI agent workflows.

================================================================================
AI Agent Important Notes
================================================================================

First-time Setup:
  Before using any other commands, you MUST initialize API credentials:
  agent_feishu initapi --app-id "cli_xxx" --app-secret "xxx"

User Management Workflow:
  1. Search local cache first (fast): agent_feishu search-users --query "name"
  2. If not found, sync from Feishu: agent_feishu sync-users --force
  3. Retry search after sync

================================================================================
Available Commands
================================================================================
...

================================================================================
Common Scenarios
================================================================================
...
`

非 Cobra 工具 可以手动解析 --skill

func Execute() {
    args := os.Args[1:]
    if len(args) == 0 {
        printUsage(os.Stdout)
        return
    }

    switch args[0] {
    case "help", "-h", "--help":
        printUsage(os.Stdout)
    case "skill", "--skill":
        fmt.Print(skillSpec)
    case "version", "-v", "--version":
        fmt.Println(version)
    // ... 其他子命令
    default:
        fmt.Fprintf(os.Stderr, "未知命令: %s\n\n", args[0])
        printUsage(os.Stderr)
        os.Exit(1)
    }
}

统一 JSON 输出

所有工具使用统一的 JSON 输出格式,确保可组合性和 AI 可解析性。

输出结构

type Result struct {
    Success bool        `json:"success"`
    Data    interface{} `json:"data,omitempty"`
    Error   string      `json:"error,omitempty"`
}

成功时:

{
  "success": true,
  "data": {
    "message": "Text message sent successfully",
    "message_id": "om_xxx"
  }
}

失败时:

{
  "success": false,
  "error": "API credentials not configured. Run 'agent_feishu initapi' first"
}

全局 --json 标志

通过 PersistentFlags 注册全局 --json 标志,使所有子命令均可输出 JSON:

func init() {
    rootCmd.PersistentFlags().BoolVar(&jsonOutput, "json", false,
        "Output in JSON format: {success, data, error}")
}

输出工具函数

建议在 internal/output/ 中统一封装输出逻辑:

func Print(jsonMode bool, data interface{}, err error) {
    if jsonMode {
        PrintJSON(data, err)
    } else {
        PrintText(data, err)
    }
}

func Success(jsonMode bool, message string) {
    Print(jsonMode, map[string]string{"message": message}, nil)
}

func Error(jsonMode bool, err error) {
    Print(jsonMode, nil, err)
    if !jsonMode {
        os.Exit(1)
    }
}

工具组合与互操作

工具之间的组合不依赖代码级别的 import,而是通过以下约定实现:

统一输出格式 — 所有工具使用相同的 {success, data, error} JSON 结构,支持管道串联:

agent_feishu search-users --query "张三" --json | jq '.data[0].open_id'

skill 文档中的跨工具引用 — 在 --skill 输出中说明与其他工具的配合方式:

agent_cursor wraps Cursor CLI's print mode (agent -p) to provide:
  - Structured JSON output compatible with agent_excel and other tools

错误信息中的命令引导 — 当操作失败时,提示相关的修复命令:

output.Error(cmd, fmt.Errorf(
    "API credentials not configured. Run 'agent_feishu initapi' first"))

如何选择工具类型

你的工具需要后台持续运行吗?
  ├── 是 → 需要维持外部连接 / 定时执行 / 共享状态?
  │         └── 是 → Daemon CLI
  └── 否 → 多次调用之间需要保持上下文吗?
            ├── 是 → Session CLI
            └── 否 → 普通 CLI ✓(大多数情况)

优先选择普通 CLI —— 它最简单、最容易测试、最容易组合。只有当普通 CLI 无法满足需求时,才考虑 Daemon 或 Session。

深入了解

下一步