07. CLI 工程实践
学习目标
- 理解 Goose CLI 基于 clap 的子命令架构设计
- 掌握 20+ 子命令的分类与用途
- 学习会话管理(resume、fork、export、import、diagnostics)的完整工作流
- 了解 Recipe YAML 格式与执行流程
- 掌握 Cron 定时调度器的使用方法
- 理解终端集成会话(Term)的设计动机与实现
项目实践
Clap 子命令体系
Goose CLI 使用 clap crate 构建命令体系,采用 #[derive(Parser)] 派生宏声明:
#[derive(Parser)]#[command(name = "goose", author, version)]pub struct Cli { #[command(subcommand)] command: Option<Command>,}当 command 为 None 时(用户直接输入 goose),启动默认交互会话。
完整子命令列表
| 命令 | 别名 | 用途 |
|---|---|---|
session | s | 启动/恢复交互式会话 |
run | — | 从指令文件或文本执行 |
configure | — | 交互式配置向导 |
info | — | 显示当前配置信息 |
doctor | — | 检查 Goose 环境健康状况 |
mcp | — | 运行内置 MCP 服务器 |
acp | — | 作为 ACP Agent 在 stdio 上运行 |
serve | — | 启动 HTTP/WebSocket ACP 服务器 |
schedule | sched | 管理定时任务 |
gateway | gw | 管理外部平台网关(如 Telegram) |
recipe | — | Recipe 工具(验证、deeplink、打开、列表) |
plugin | — | 插件管理(安装、更新) |
skills | — | 列出可用技能 |
term | — | 终端集成会话 |
tui | — | 启动终端 UI |
review | — | 本地代码审查 |
project | p | 打开上次项目目录 |
projects | ps | 列出最近的项目目录 |
completion | — | 生成 Shell 补全脚本 |
update | — | 更新 goose CLI 版本 |
会话管理
Session 子命令
goose session 是最核心的命令,支持多种子操作:
enum SessionCommand { List { format, ascending, working_dir, limit }, Remove { identifier, regex }, Export { identifier, output, format, nostr, relays }, Import { input, nostr }, Diagnostics { identifier, output },}会话恢复与分叉
goose session --resume 恢复最近使用的会话。通过 --name 或 --session-id 可恢复特定会话:
# 恢复最近使用的会话goose session --resume
# 恢复指定名称的会话goose session --resume --name project-x
# 分叉会话(复制历史到新会话)goose session --resume --fork --name project-x分叉(fork)创建新会话但复制全部消息历史,适用于在同一上下文基础上探索不同分支。
会话导出与导入
支持将完整会话导出为 Markdown、JSON 或 YAML 格式:
# 导出为 Markdowngoose session export --format markdown --name project-x
# 导出为 JSON 并发布到 Nostrgoose session export --format json --nostr --name project-x
# 从 JSON 导入goose session import session-export.json
# 从 Nostr 分享链接导入goose session import "goose://sessions/nostr?..." --nostr诊断包
goose session diagnostics --name project-x --output ./diagnostics.zip生成包含会话日志、配置、环境信息的诊断 ZIP 包,用于问题排查。
交互式配置向导
goose configure 提供交互式配置流程,引导用户设置:
- 选择 AI 提供商(OpenAI、Anthropic、Ollama 等)
- 输入 API Key(存储到系统 Keyring)
- 选择默认模型
- 配置遥测同意
首次运行 goose(无子命令)时,若检测到无配置,自动进入配置向导。
Recipe 系统
Recipe 是 Goose 的核心抽象——将 AI 指令、扩展配置、参数定义、工作流编排打包到一个 YAML 文件中。
Recipe YAML 格式
version: 1.0.0title: Daily Standup Report Generatordescription: 从 GitHub 活动生成每日站会报告
# 运行时参数parameters: - key: github_repo input_type: string requirement: required description: "GitHub 仓库 (如 'owner/repo')"
- key: time_period input_type: select requirement: optional default: "24h" options: ["24h", "48h", "week"] description: "分析的时间段"
# 系统指令instructions: | 你是站会报告生成器。从 GitHub 获取 PR 和 Issue 数据, 分析活动并生成格式化的报告。
始终将报告保存到 ./standup/standup-{date}.md
# 需要的扩展extensions: - type: builtin name: developer description: 文件操作 - type: stdio name: github cmd: uvx args: ["github-mcp-server"] description: GitHub API 访问
# UI 中的快速启动提示activities: - "生成今天的站会报告" - "总结本周的 PR"
# 初始提示词(参数替换)prompt: | 为 {{ github_repo }} 生成过去 {{ time_period }} 的站会报告。Recipe CLI 操作
# 列出所有可用 Recipegoose recipe list
# 验证 Recipe 文件goose recipe validate my-recipe.yaml
# 生成 deeplink(可在桌面端打开)goose recipe deeplink my-recipe.yaml -p github_repo=owner/repo
# 在桌面端打开 Recipegoose recipe open my-recipe.yaml
# 运行 Recipegoose run --recipe my-recipe.yaml
# 解释 Recipe(查看标题、描述、参数)goose run --recipe my-recipe.yaml --explain
# 打印渲染后的 Recipegoose run --recipe my-recipe.yaml --render-recipeRun 命令的输入模式
goose run 支持三种输入方式:
# 从文件读取指令goose run --instructions task.txt
# 直接提供文本goose run --text "分析这个目录的文件结构"
# 从 stdin 读取goose run --instructions -
# 使用 Recipegoose run --recipe daily-standupCron 定时调度器
goose schedule 提供基于 cron 表达式的定时调度能力:
# 添加定时任务goose schedule add \ --schedule-id daily-standup \ --cron "0 9 * * 1-5" \ --recipe-source standup.yaml
# 添加带参数的定时任务goose schedule add \ --schedule-id weekly-report \ --cron "0 17 * * 5" \ --recipe-source weekly-report.yaml \ --params time_period=week
# 列出所有定时任务goose schedule list
# 查看某定时任务创建的会话goose schedule sessions --schedule-id daily-standup
# 立即执行一次定时任务goose schedule run-now --schedule-id daily-standup
# 删除定时任务goose schedule remove --schedule-id daily-standup
# 查看 cron 表达式帮助goose schedule cron-help常用 cron 表达式:
| 表达式 | 含义 |
|---|---|
0 * * * * | 每小时整点执行 |
0 */2 * * * | 每 2 小时执行 |
@hourly | 每小时(简写) |
0 9 * * * | 每天 9:00 AM |
0 9 * * 1-5 | 工作日 9:00 AM |
0 0 1 * * | 每月 1 日午夜 |
终端集成会话(Term)
Term 是 Goose 最具创新性的 CLI 功能之一——每个终端窗口拥有一个独立的、持久的 Goose 会话:
# 初始化终端集成(zsh/bash)eval "$(goose term init zsh)"
# Nushell 初始化let init = ($nu.cache-dir | path join "goose-term-init.nu")^goose term init nu | save --force $init; source $init
# 设置 goose 为默认命令处理器eval "$(goose term init zsh --default)"初始化后,在终端中:
# 直接发送消息给 goose(--default 模式下)create a python script
# 使用 run 子命令显式发送goose term run "list files in this directory"
# 查看会话信息(集成到 shell 提示符)goose term info# 输出示例: ●○○○○ sonnet每个终端维护自己的会话,关闭终端后再打开同名终端会自动恢复会话。这使得 AI 助手像 shell 历史一样自然地融入工作流。
代码审查命令
goose review 发现 **/.agents/checks/*.md 中的检查器并执行代码审查:
# 审查工作树 vs HEAD 的差异goose review
# 审查指定范围goose review main...HEAD
# 仅运行检查子 Agentgoose review --checks-only
# 自定义审查提示词goose review --prompt ./custom-review.md
# 指定模型和提供商goose review --model claude-sonnet-4 --provider anthropic
# 并行调度(默认)vs 单提示词模式goose review --no-orchestrate
# 仅输出 diff 摘要goose review --summary-only默认使用 Rust 驱动的并行编排器,最多 4 个并发 goose run 子进程执行检查,墙钟时间等于最慢的单个检查。
ACP 服务模式
# 在 stdio 上运行 ACP Agentgoose acp --with-builtin developer,memory
# 启动 HTTP/WebSocket ACP 服务器goose serve --host 127.0.0.1 --port 3284
# 带内置扩展的 HTTP 服务器goose serve --with-builtin developer,githubgoose serve 自动生成随机密钥(或读取 GOOSE_SERVER__SECRET_KEY 环境变量),在指定地址启动 WebSocket 服务。
Shell 补全
# 为 zsh 生成补全goose completion zsh
# 为 bash 生成补全goose completion bash
# 为 Nushell 生成补全模块goose completion nu
# 为 fish 生成补全goose completion fish支持 bash、zsh、fish、powershell(别名 pwsh)、elvish、nu(别名 nushell)六种 shell。
问题与规避
| 问题 | 规避方法 |
|---|---|
--session-id 无 --resume 时报错 | CLI 校验要求 --session-id 只能与 --resume 配合使用 |
| Recipe 参数缺失导致运行失败 | 使用 --explain 先查看所需参数,或 --render-recipe 预览渲染结果 |
| 定时任务的 cron 表达式写错 | 使用 goose schedule cron-help 查看常用表达式示例 |
| 多个终端会话并发操作同一文件 | Term 会话绑定单个终端,天然隔离;不同终端的会话互不干扰 |
| Recipe 中子配方路径不正确 | 子配方路径相对于主配方所在目录,或使用绝对路径 |
goose run 不创建会话文件 | 添加 --no-session 明确指定,否则默认创建 |
| Shell 补全不生效 | 生成后需将补全脚本加入 shell 配置(如 ~/.zshrc) |
| Term init 后 shell 报错 | 确认 shell 类型参数正确(zsh/bash/fish/nu),不同 shell 的初始化脚本语法不同 |
设计取舍
20+ 扁平子命令 vs 嵌套子命令树
Goose 选择了扁平的一级子命令体系(所有命令都是 goose <verb> 而非 goose session <subcommand> 深度嵌套)。虽然 session、schedule、gateway、recipe 等命令有二级子命令,但整体结构保持浅层次。
这个选择的原因:
- 可发现性:
goose --help一次列出所有能力,用户不需要逐层深入探索 - 记忆效率:常用命令(session、run、configure)都在顶层,减少击键
- 别名友好:
s、p、sched、gw等短别名覆盖高频命令
代价是顶层命令数量较多(20+),但通过功能分组(核心会话、配置诊断、配方系统、调度系统、平台集成、工具命令)保持了可读性。
Recipe 系统的设计动机
Recipe 不是简单的”指令文件”,而是一个完整的 Agent 配置规范。它的设计动机来自三个观察:
- 配置与代码分离:团队非工程师(PM、设计师)可以通过 YAML 定义 Agent 行为,不需要碰 Rust 代码。
- 可复用性:一个 Recipe 可以在不同环境、不同参数下反复执行,类似函数调用。
- 组合性:子配方(sub_recipes)和子 Agent(subagent)支持多层嵌套编排,将复杂工作流分解为可测试的组件。
与简单的 --text 输入相比,Recipe 提供了版本控制(version 字段)、参数校验(requirement + input_type)、扩展绑定(extensions)、快速启动提示(activities)等企业级特性。
参考来源
crates/goose-cli/src/cli.rs— CLI 入口与子命令定义crates/goose-cli/src/commands/configure.rs— 交互式配置向导crates/goose-cli/src/commands/recipe.rs— Recipe CLI 操作crates/goose-cli/src/commands/schedule.rs— 定时调度器实现crates/goose-cli/src/commands/term.rs— 终端集成会话crates/goose-cli/src/commands/session.rs— 会话管理crates/goose/src/recipe/mod.rs— Recipe 数据模型crates/goose-cli/src/commands/review.rs— 代码审查命令