跳转到内容

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>,
}

commandNone 时(用户直接输入 goose),启动默认交互会话。

完整子命令列表

命令别名用途
sessions启动/恢复交互式会话
run从指令文件或文本执行
configure交互式配置向导
info显示当前配置信息
doctor检查 Goose 环境健康状况
mcp运行内置 MCP 服务器
acp作为 ACP Agent 在 stdio 上运行
serve启动 HTTP/WebSocket ACP 服务器
schedulesched管理定时任务
gatewaygw管理外部平台网关(如 Telegram)
recipeRecipe 工具(验证、deeplink、打开、列表)
plugin插件管理(安装、更新)
skills列出可用技能
term终端集成会话
tui启动终端 UI
review本地代码审查
projectp打开上次项目目录
projectsps列出最近的项目目录
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 可恢复特定会话:

Terminal window
# 恢复最近使用的会话
goose session --resume
# 恢复指定名称的会话
goose session --resume --name project-x
# 分叉会话(复制历史到新会话)
goose session --resume --fork --name project-x

分叉(fork)创建新会话但复制全部消息历史,适用于在同一上下文基础上探索不同分支。

会话导出与导入

支持将完整会话导出为 Markdown、JSON 或 YAML 格式:

Terminal window
# 导出为 Markdown
goose session export --format markdown --name project-x
# 导出为 JSON 并发布到 Nostr
goose session export --format json --nostr --name project-x
# 从 JSON 导入
goose session import session-export.json
# 从 Nostr 分享链接导入
goose session import "goose://sessions/nostr?..." --nostr

诊断包

Terminal window
goose session diagnostics --name project-x --output ./diagnostics.zip

生成包含会话日志、配置、环境信息的诊断 ZIP 包,用于问题排查。

交互式配置向导

goose configure 提供交互式配置流程,引导用户设置:

  1. 选择 AI 提供商(OpenAI、Anthropic、Ollama 等)
  2. 输入 API Key(存储到系统 Keyring)
  3. 选择默认模型
  4. 配置遥测同意

首次运行 goose(无子命令)时,若检测到无配置,自动进入配置向导。

Recipe 系统

Recipe 是 Goose 的核心抽象——将 AI 指令、扩展配置、参数定义、工作流编排打包到一个 YAML 文件中。

Recipe YAML 格式

version: 1.0.0
title: Daily Standup Report Generator
description: 从 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 操作

Terminal window
# 列出所有可用 Recipe
goose recipe list
# 验证 Recipe 文件
goose recipe validate my-recipe.yaml
# 生成 deeplink(可在桌面端打开)
goose recipe deeplink my-recipe.yaml -p github_repo=owner/repo
# 在桌面端打开 Recipe
goose recipe open my-recipe.yaml
# 运行 Recipe
goose run --recipe my-recipe.yaml
# 解释 Recipe(查看标题、描述、参数)
goose run --recipe my-recipe.yaml --explain
# 打印渲染后的 Recipe
goose run --recipe my-recipe.yaml --render-recipe

Run 命令的输入模式

goose run 支持三种输入方式:

Terminal window
# 从文件读取指令
goose run --instructions task.txt
# 直接提供文本
goose run --text "分析这个目录的文件结构"
# 从 stdin 读取
goose run --instructions -
# 使用 Recipe
goose run --recipe daily-standup

Cron 定时调度器

goose schedule 提供基于 cron 表达式的定时调度能力:

Terminal window
# 添加定时任务
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 会话:

Terminal window
# 初始化终端集成(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)"

初始化后,在终端中:

Terminal window
# 直接发送消息给 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 中的检查器并执行代码审查:

Terminal window
# 审查工作树 vs HEAD 的差异
goose review
# 审查指定范围
goose review main...HEAD
# 仅运行检查子 Agent
goose 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 服务模式

Terminal window
# 在 stdio 上运行 ACP Agent
goose acp --with-builtin developer,memory
# 启动 HTTP/WebSocket ACP 服务器
goose serve --host 127.0.0.1 --port 3284
# 带内置扩展的 HTTP 服务器
goose serve --with-builtin developer,github

goose serve 自动生成随机密钥(或读取 GOOSE_SERVER__SECRET_KEY 环境变量),在指定地址启动 WebSocket 服务。

Shell 补全

Terminal window
# 为 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> 深度嵌套)。虽然 sessionschedulegatewayrecipe 等命令有二级子命令,但整体结构保持浅层次。

这个选择的原因:

  • 可发现性goose --help 一次列出所有能力,用户不需要逐层深入探索
  • 记忆效率:常用命令(session、run、configure)都在顶层,减少击键
  • 别名友好spschedgw 等短别名覆盖高频命令

代价是顶层命令数量较多(20+),但通过功能分组(核心会话、配置诊断、配方系统、调度系统、平台集成、工具命令)保持了可读性。

Recipe 系统的设计动机

Recipe 不是简单的”指令文件”,而是一个完整的 Agent 配置规范。它的设计动机来自三个观察:

  1. 配置与代码分离:团队非工程师(PM、设计师)可以通过 YAML 定义 Agent 行为,不需要碰 Rust 代码。
  2. 可复用性:一个 Recipe 可以在不同环境、不同参数下反复执行,类似函数调用。
  3. 组合性:子配方(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 — 代码审查命令