Go CLI 工具开发实践
用 Go 构建零依赖的 Agent 友好 CLI 工具 — 从项目结构到自动发布
Go CLI 工具开发实践
我用 Go 构建了 4 个 CLI 工具(gcli、imgcli、jina-cli、md2wechat-lite)。这篇文章总结构建过程中的工程选择和踩过的坑。
为什么选 Go
三个理由:
- 单二进制分发 — 编译后一个文件,
curl | bash就能安装。不需要运行时。 - 零 CGO — 交叉编译简单,一条命令出 linux/darwin/windows 三个平台。
- 性能够用 — CLI 工具不需要极致性能,但 Go 的启动速度和内存占用都很克制。
项目结构
以 gcli(Gmail CLI)为例:
gcli/
├── cmd/ # cobra 命令定义
│ ├── root.go # 根命令 + 全局 flag
│ ├── auth.go # gmail auth 子命令
│ ├── list.go # gmail list 子命令
│ └── read.go # gmail read 子命令
├── internal/ # 内部实现(不导出)
│ ├── gmail/ # Gmail API 封装
│ ├── auth/ # OAuth + PKCE 流程
│ └── output/ # JSON/Table 输出格式化
├── scripts/
│ └── install.sh # 一键安装脚本
├── main.go
├── go.mod
└── .goreleaser.yaml # 自动发布配置关键选择
- cobra 做命令行框架 — 成熟稳定,子命令模式适合 CLI 工具
- internal/ 放所有业务逻辑 — 强制不导出,避免被意外依赖
- scripts/install.sh — 检测平台 + 下载对应二进制 + 放到 PATH
Agent 友好设计
CLI 工具的真正用户不只是人,还有 AI Agent。Agent 友好意味着:
1. 结构化输出
# 人类友好
gcli list --limit 5
# Agent 友好
gcli list --limit 5 --output json永远提供 --output json 选项。Agent 解析 JSON 比解析表格容易 100 倍。
2. 明确的退出码
// 成功 = 0,用户错误 = 1,系统错误 = 2
os.Exit(0) // 一切正常
os.Exit(1) // 参数错误、认证失败等
os.Exit(2) // 网络错误、文件系统错误等3. 静默模式
gcli auth --quiet # 只输出结果,不输出过程Agent 不需要看 spinner 和进度条。--quiet 模式只输出最终结果。
跨平台发布
使用 GoReleaser 自动化:
# .goreleaser.yaml 核心配置
builds:
- env: [CGO_ENABLED=0]
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
release:
github:
owner: geekjourneyx
name: gcli每次打 tag,GitHub Actions 自动编译 6 个平台二进制,发布到 GitHub Releases。
安装脚本设计
一键安装脚本的核心逻辑:
# 1. 检测平台
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
# 2. 下载对应二进制
curl -fsSL "$DOWNLOAD_URL" -o /tmp/gcli.tar.gz
# 3. 解压到 PATH
tar -xzf /tmp/gcli.tar.gz -C /usr/local/bin/关键:脚本要幂等。多次执行不会出错。
踩过的坑
CGO 和图片处理
imgcli 处理图片但不用 CGO。怎么做到的?
- 用
golang.org/x/image替代需要 CGO 的图片库 - PNG/JPEG 编解码用纯 Go 实现
- 牺牲少量性能,换来零依赖的交叉编译
OAuth PKCE 在 CLI 中的实现
gcli 需要 OAuth 认证。在无浏览器的服务器上怎么办?
- 生成 PKCE code_verifier + code_challenge
- 打印授权 URL,让用户在别的设备打开
- 启动本地 HTTP server 等待回调
- 用 authorization_code + code_verifier 换 token
安装脚本在 CI 中失败
CI 环境可能没有 /usr/local/bin 写权限。解决:
INSTALL_DIR="${HOME}/.local/bin"
mkdir -p "$INSTALL_DIR"
# 安装到用户目录,不需要 sudo总结
Go CLI 工具的核心优势是分发简单。一个二进制文件,什么环境都能跑。
对于 Agent 工具,最重要的不是功能多丰富,而是接口多清晰。JSON 输出、明确退出码、静默模式 — 这三件事做好,Agent 就能顺畅使用你的工具。
极客杰尼知识库