Goose (Block)

一句话定位

Goose 最初由 Block(Square 母公司)开源,已迁移至 Linux Foundation 旗下的 Agentic AI Foundation(AAIF),是一个 Rust 编写、MCP(Model Context Protocol)原生贯穿工具体系的通用 agent harness;相比同类工具,其最突出的差异化能力是 toolshim(为弱 tool-calling 能力的开源模型提供本地二级”翻译”模型)与 summon 平台扩展delegate/load 两个工具驱动的递归子代理编排,支持同步/异步/跨 harness 委派)。

核心架构总览(目录结构关键路径 + 引用的 commit)

  • 仓库身份(已核实,与调研线索有出入):给定线索 https://github.com/block/goose 仍可正常 clone,但仓库已从 Block 迁移至 Agentic AI Foundation (AAIF)(Linux Foundation 旗下),当前权威仓库为 https://github.com/aaif-goose/goose。证据:block/goose 仓库自己的 README.md 第一行写明”goose has moved! This project has moved from block/goose to the Agentic AI Foundation (AAIF) at the Linux Foundation”;CloakBrowser 实地访问 aaif-goose/goose 确认是活跃仓库;且已交付的系统提示词本身写着 “created by AAIF (Agentic AI Foundation)“,说明改名已经上线到产品文本,不只是文档层面。License:Apache-2.0。
  • 分析 commit:8694a8d1040e40735a6ac3dd09a7f1d1ffe4ef8f(commit message: fix(server): return effective context limit from /model-info (#10165),提交于 2026-07-06 15:32:22 +0000),clone/分析日期 2026-07-07。
  • 技术栈:Rust workspace(多 crate)+ TypeScript/Electron 桌面 UI(ui/desktop)+ Docusaurus 文档站(documentation/)。非 submodule 结构。
  • 关键 crate/目录:
    • crates/goose/src/agents/ — 核心 agent 循环、工具分派、子代理、平台扩展(summon 等)
    • crates/goose/src/context_mgmt/ — 压缩与上下文管理
    • crates/goose/src/prompts/ — 系统提示模板(Jinja 风格)
    • crates/goose/src/permission/crates/goose/src/security/ — 权限与安全
    • crates/goose/src/skills/crates/goose/src/plugins/ — 技能与插件体系
    • crates/goose/src/session/ — SQLite 会话持久化、Nostr 分享、跨 harness 轨迹导入
    • crates/goose/src/providers/toolshim.rs — 弱模型 tool-calling 兼容层
    • crates/goose-provider-types/src/goose_mode.rs — 权限模式枚举
  • 需要指出一处文档与源码不一致:官方 sandbox.md 引用的源文件 ui/desktop/src/sandbox/index.ts 在本次分析的 commit 中不存在ui/desktop/srcsandbox/ 目录,全仓库 grep sandbox-exec/GOOSE_SANDBOX 零命中)。详见”沙箱与执行隔离”一节。

Agent Loop(主循环 / 何时继续何时停)

  • 入口:Agent::reply()crates/goose/src/agents/agent.rs:1534),先处理斜杠命令(execute_command),再转入 reply_internal()(第 1813 行),实际流式循环在一个 async_stream::try_stream! 块中展开,起于第 1896 行。
  • 循环计数器 turns_taken,受 max_turns 上限约束——默认 DEFAULT_MAX_TURNS = 1000(第 69 行),可通过 GOOSE_MAX_TURNS 配置或 session_config.max_turns 覆盖(子代理默认 25 turns)。触及上限时返回固定文案 MAX_TURNS_MESSAGE(第 72 行:“I’ve reached the maximum number of actions I can do without user input. Would you like me to continue?“)并跳出循环。
  • 循环内的停止判定(约第 2540 行 no_tools_called && !exit_chat 分支):
    • 若结构化”最终输出”工具(recipe response)尚未触发 → 注入继续提示,保持循环。
    • 若设置了 goal 且本轮尚未检查 → 注入”检查目标是否已完全达成”的提示继续(用 goal-check-pending 标志防止无限提示循环)。
    • 若设置了 grind(持续磨合模式)→ 总是重新注入”继续工作,尚未完成”提示。
    • 否则落入 handle_retry_logic()(recipe 级 success_check/on_failure shell 命令重试,见”自进化能力”一节)——若判定无需再重试,则 exit_chat = true
  • Stop hook:真正退出前会执行 emit_stop_hook_blocking()——一个 Stop 生命周期钩子可以 Deny 掉退出(携带理由注回上下文继续循环),受 stop_hook_block_cap() 限制以防止无限拒绝循环(用 consecutive_stop_hook_blocks 追踪)。
  • Steering(中途转向):可异步注入”steer”消息(self.steer() / drain_pending_steers())——允许用户/UI 在循环仍在运行时插入新指令,无需等本轮结束。
  • 自动压缩检查(check_if_compaction_needed)在每次 reply() 调用进入循环前执行一次,不是每轮都查——详见”记忆与上下文管理”。
  • 每轮的 turn-context 注入:super::moim::inject_moim()crates/goose/src/agents/moim.rs)在每轮对话中插入一个 <turn-context> 标签块,携带当前时间、工作目录,以及(若模型上下文窗口 ≥ 32,000 tokens,MIN_CONTEXT_FOR_MOIM)一个计算出的剩余 turn 预算信号,提示模型”随预算减少变得更直接”。注意:尽管模块名叫”moim”容易让人联想 multi-agent,但它其实只是单轮上下文注入器,不是多代理机制

记忆与上下文管理(压缩、长期记忆、会话持久化)

  • 自动压缩check_if_compaction_needed()context_mgmt/mod.rs:188)比较 current_tokens / context_limitGOOSE_AUTO_COMPACT_THRESHOLD(默认 0.8,即 DEFAULT_COMPACTION_THRESHOLD)。Token 计数优先取 session 追踪的 usage.total_tokens,否则退化为对模型可见消息的本地估算。若 provider.manages_own_context() 为真(部分 provider 自行管理上下文/服务端会话状态),则整套压缩逻辑被跳过。
  • 压缩机制compact_messages()(第 67 行)调用 do_compact(),让同一个/配置中的模型通过 crates/goose/src/prompts/compaction.md 渲染出的系统提示自己做摘要。若摘要调用本身触发 ContextLengthExceeded,则以”中间优先移除”策略逐级去除工具响应内容(filter_tool_responses,按 0/10/20/50/100% 比例移除),最多重试 5 次。
    • 可见性魔术:原始消息被打上 agent_invisible 元数据(对用户在 transcript 中仍可见,但后续不再发给模型),摘要消息则是 agent_only(模型可见、用户不可见)——这正是”压缩对人类不可见”的实现方式。
    • 最近一条用户消息会原样保留(重新追加),除非是手动 /compact
    • 三种不同的续接文案(CONVERSATION_CONTINUATION_TEXTTOOL_LOOP_CONTINUATION_TEXTMANUAL_COMPACT_CONTINUATION_TEXT)确保模型不会向用户”自曝”被压缩过。
  • 工具对摘要(区别于整体压缩的更细粒度机制):maybe_summarize_tool_pairs 在后台任务中批量(每批 10 条,TOOLCALL_SUMMARIZATION_BATCH_SIZE)摘要较旧的 tool-request/tool-response 对,触发条件是工具调用数超过一个计算出的截断值(compute_tool_call_cutoff3 * effective_limit / 20_000,限幅 10–500),且始终保护当前轮次的最近 N 次调用不被摘要。与下一次 provider 调用并发执行(不阻塞)。开关:GOOSE_TOOL_PAIR_SUMMARIZATION(默认 true)。
  • 会话持久化:本地 SQLite(WAL 模式)+ sqlx,由 SessionStorage 管理单一 DB 文件(Paths::data_dir())。表结构(session_manager.rs 约 L920–1000):schema_versionsessions(含 id/name/working_dir/token与cost统计列/goose_mode/recipe_json/parent_session_id(子代理谱系)/archived_at)、messages(role/content_json/metadata_json)、usage_ledger、以及后续迁移加入的 threads/thread_messages(约 L1361–1478)。没有 Postgres 后端——测试代码里出现的”postgres”字样只是测试内容文本,非数据库驱动(grep 验证只用到 sqlx::sqlite::* 类型)。
  • 长期/跨会话记忆:在 crates/goose 中未找到。存在一个 goose-mcp/src/memory 内置 MCP 扩展(本轮只列出未深读,可能只是简单笔记/日志式 MCP server,而非向量/语义记忆系统)——标记为二阶段待办。
  • 会话分享/导出nostr_share.rs 支持通过 Nostr 协议分享会话快照(NIP-44 加密,发布到 relay.damus.io 等公共 relay)——一种少见但真实存在的带外会话导出机制。
  • 跨 harness 轨迹导入session/import_formats/{claude_code,codex,pi}.rs — Goose 可以把 Claude Code、Codex、“Pi” harness 产生的会话轨迹导入自己的会话格式(互操作性,非训练用途)。

工具体系(定义/调用协议/注册/权限)

  • 协议:端到端使用 MCP(Model Context Protocol)——扩展即 MCP server(进程内内置、stdio 子进程或远程),工具是带 JSON-schema 参数与 ToolAnnotationsread_only_hintdestructiveidempotentopen_world)的 rmcp::model::Tool 对象,这些标注被权限系统直接消费。
  • 注册:ExtensionManagercrates/goose/src/agents/extension_manager.rs)为每种扩展配置变体构建 MCP 客户端——Builtin(进程内 duplex pipe 或 Docker exec)、Stdio(子进程或 Docker exec)、InlinePython(写临时 .py 文件执行)。Agent 上的 add_extension/add_extensions_bulk/remove_extension/list_extensions(agent.rs 约 L1313–1494)。
    • PermissionInspectorapply_tool_annotations 会缓存哪些工具是扩展自身声明为只读的(区别于 LLM 判定只读,见”安全与权限”一节)。
  • 分派:Agent::dispatch_tool_call()(agent.rs:1044)按名称把工具调用路由到前端工具(客户端处理,如桌面 UI 动作)、平台工具(内置于 agent 二进制,如 platform__manage_schedulesummon 扩展的 delegate/load),或真正的 MCP call_tool(发给拥有该工具的扩展客户端)。
    • 分类:categorize_tools() / categorize_tool_requests()(agent.rs:775)在权限检查与执行前,把一批模型工具调用拆成前端 vs. 其余请求。
  • 供应链安全(扩展启动时):extension_malware_check::deny_if_malicious_cmd_args()crates/goose/src/agents/extension_malware_check.rs)在扩展通过 npx(npm 生态)或 uvx(PyPI 生态)启动时查询 OSV.dev 漏洞数据库(endpoint 可经 OSV_ENDPOINT 环境变量配置)的 MAL-* 恶意包公告,命中即拒绝启动该扩展。未知启动命令则默认放行(fail open)。
  • 模型-工具调用兼容层(“toolshim”,见”与模型的协同设计”)位于工具定义与 provider 原生 tool-calling 之间,服务于对 tool-calling 支持较弱的模型。

Prompt 设计(系统提示结构、动态组装)

  • 主系统提示:crates/goose/src/prompts/system.md,通过类 Jinja2 模板引擎(render_templatecrate::prompt_template)渲染,变量包括 moim_system_prompt_blockcode_execution_modeextensions(含 .name/.instructions/.has_resources 的列表)、extension_tool_limits(当启用扩展过多时提示用户禁用部分扩展——把”工具选择准确率”的顾虑直接写进提示词本身)。
    • 提示词写道:“You are a general-purpose AI agent called goose, created by AAIF (Agentic AI Foundation).”——确认此 commit 已上线 AAIF 品牌。
    • 每个启用中的 MCP 扩展可以把自己的 ### Instructions 文本块动态追加进系统提示。
  • 项目级说明文件:.goosehints(原生格式)及可配置的替代文件名,包括 AGENTS.mdCLAUDE.md(见 crates/goose/src/hints/load_hints.rs,常量 GOOSE_HINTS_FILENAMEAGENTS_MD_FILENAME;L437–467 测试显式验证 CLAUDE.md.goosehints 会被合并)。Hints 按目录加载,包括会话中途才访问到的子目录——主循环每轮调用 load_subdirectory_hints(&working_dir),若发现新 hints 则重新执行 prepare_tools_and_prompt(agent.rs 约 L2524–2537),因此中途 cd 进新子项目也能拿到该子项目的 hints,无需重启会话。
  • 系统提示整体覆盖:override_system_prompt() / clear_system_prompt_override()——用于子代理(recipe 的 instructions 字段完全替换默认模板)以及推测通用于自定义 agent/recipe。
  • 子代理提示:独立模板 subagent_system.md,明确声明子代理”Cannot spawn additional subagents”,并事先声明其 turn 预算与工具列表(SubagentPromptContextmax_turnssubagent_idtask_instructionstool_countavailable_tools)。
  • 压缩提示:compaction.md 模板,专供摘要子调用使用的独立系统提示。
  • 其他存在但未深读的提示模板:plan.md(规划模式)、permission_judge.md(只读工具判定,简短)、tiny_model_system.md(面向小型/本地模型的精简系统提示,在 goose-local-inference/src/prompts/tiny_model_system.md 中也有一份镜像)、recipe.mdsession_name.mdapps_create.md/apps_iterate.md(“goose apps”功能)。

Router / 编排(任务分解、多 agent、子 agent)

  • summon 平台扩展crates/goose/src/agents/platform_extensions/summon.rs,3021 行)是具体的路由/编排层,暴露两个工具:
    • delegate:生成子代理(完整的嵌套 Agent::with_config() 实例,见 subagent_handler.rs),可以是临时的(自由文本 instructions)或来自命名 source(recipe/subrecipe/agent 文件)。支持 sync(阻塞等待返回)或 async: true(返回 task_id,作为 tokio::spawnBackgroundTask 在后台运行,带自己的 CancellationToken、轮次计数器、空闲活动追踪)。可按次覆盖 provider/model/temperature/max_turns/extensions/working_dir
    • load:发现可用来源(文件系统中或 discover_filesystem_sources 找到的 subrecipe/recipe/agent),将其加载进上下文;同名重载还可用于轮询/等待后台任务load(source: "<task_id>") 阻塞直到完成并返回结果;load(source, peek: true) 不阻塞查看进度;load(source, cancel: true) 取消并返回部分输出)。
    • 工具描述文本本身就向模型灌输编排策略:“Research (read-only): parallelize freely… Work (writes): partition files strictly — no two delegates touch the same file… Decompose → async delegates → load(taskId) for each → synthesize.”——即任务分解的启发式规则是直接写在工具 docstring 里让模型读到的,而不是一个独立的 planner 组件。
  • 子代理运行为独立的 Agent 实例,拥有自己的对话、provider、扩展与系统提示(subagent_handler.rsget_agent_messages() 构造一个新的 Agent::with_config(config),可选覆盖 provider/model,添加扩展,调用其 agent.reply()——递归复用”Agent Loop”一节描述的同一套循环)。
  • 硬性递归防护:子代理系统提示明确声明”Cannot spawn additional subagents”;官方文档(subagents.mdx)确认这一约束被强制执行(“Subagent spawning: Cannot create additional subagents to prevent infinite recursion”)——本轮未追溯到具体的强制执行代码路径(推测是 summon 扩展本身未被包含在子代理继承的扩展列表中/被过滤掉),标记为二阶段待办。
  • 自主性门控:据官方文档,子代理仅能在 GooseMode::Auto(默认模式)下被模型自主创建——在 ApproveSmartApproveChat 模式下被禁用。
  • 外部代理委派:Goose 可以通过标准协议把其他CLI agent harness 当作子代理/provider 来委派:
    • 作为 MCP server:官方示例配置把 codex mcp-server 配置为 subagent 扩展(stdio 类型),使 delegate/工具调用路由到 Codex。
    • 作为 ACP(Agent Client Protocol,agentclientprotocol.com)provider:goose acp 让 Goose 自身作为 ACP server 供编辑器(JetBrains、Zed)使用;反过来,Goose 也可以把外部 ACP agent(如 Claude Code、Codex)作为 provider 使用——“The ACP agent handles tool execution internally. goose passes configured extensions through as MCP servers.”(goose-architecture.md)。ACP server 代码位于 crates/goose/src/acp/(本轮只列出未读)。
  • 跨时间的调度/编排:platform__manage_schedule 工具(agents/platform_tools.rs)暴露基于 cron 的 recipe 调度能力(list/create/run_now/pause/unpause/delete/kill/inspect/sessions/session_content),后端为 crates/goose/src/scheduler.rs(本轮未读)。
  • 需特别澄清:moim.rs 尽管名字容易让人误以为是 multi-agent 相关模块,实际是”Agent Loop”一节描述的单轮上下文注入 helper,不是多代理机制

Skill / 插件体系

  • Goose 直接实现了 agentskills.io 的 SKILL.md 开放规范crates/goose/src/skills/mod.rs,doc-comment 引用 https://agentskills.io/specification#frontmatter)。
    • 技能目录:全局 ~/.agents/skillsglobal_skills_dir())与项目级 <project>/.agents/skillsproject_skills_dir())。SkillFrontmatter = name(可选)、description,外加一个自由格式 metadata 字段承载规范定义的任意字段。
    • skills/client.rs(320 行)——把技能暴露为可加载内容的运行时 MCP 客户端封装(本轮未深读)。
    • skills/arguments.rs——技能调用的参数模板/替换(本轮未深读)。
    • skills/builtins/goose_doc_guide.md——一份内置技能(Goose 自己的文档写作指南)。
  • 插件体系是独立且更广的一层(crates/goose/src/plugins/mod.rs,567 行):从 git 源安装第三方插件包(可以内含 skills、hooks、扩展)。
    • 支持两种插件格式PluginFormat::Gemini(兼容 Google Gemini CLI 的扩展格式,plugins/formats/gemini.rs)与 PluginFormat::OpenPlugins(跨 agent 的”Open Plugins”规范,也定义了”安全与权限”一节提到的 hooks 规范)。
    • 自动更新:已安装插件每 24 小时检查一次更新(AUTO_UPDATE_INTERVAL_HOURS = 24),通过每次安装对应的 .goose-plugin-install.json 元数据文件追踪。
    • plugins/discovery.rs(438 行)——枚举已启用插件供 hook/skill 发现使用(discover_enabled_plugins,被 hooks/mod.rs 调用)。
    • plugins/mcp_servers.rs(335 行)——插件也可以捆绑 MCP server 定义(本轮未深读)。
    • Hooks 规范(crates/goose/src/hooks/mod.rs,头部已读):Open Plugins 定义的生命周期钩子包括 PreToolUse/PostToolUse/SessionStart/SessionEnd/UserPromptSubmit/BeforeReadFile/AfterFileEdit/BeforeShellExecution/AfterShellExecution/Stop;钩子脚本类型为 type: command,通过 stdin 接收 JSON 运行,从 <plugin-root>/hooks/hooks.json 发现。

自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)

  • 未发现运行时自我改进/学习型记忆机制。 实际存在的是:
    • Recipe 级带成功检查的重试crates/goose/src/agents/retry.rs——RetryManager 在模型认为完成后重新执行配置好的 shell 命令 SuccessCheck;若检查失败,on_failure 消息/超时配置驱动下一轮循环(受最大尝试次数限制)。这是确定性的 shell 脚本验证,不是学习型/RL 纠错信号。
    • 重复检测RetryManager::with_repetition_inspector 接入了 tool_monitor::RepetitionInspector(本轮只列出未深读)——推测用于检测模型在同一失败工具调用上打转,用来重置/中断重试状态。二阶段需确认具体启发式。
    • Toolshim 微调研究(与”模型协同设计”/“轨迹利用”重叠):2025-04-11-finetuning-toolshim 官方博客描述了一个开发期(非运行时)流水线,提取历史 Goose 会话轨迹(用户消息 + 真实 Anthropic/OpenAI 工具调用)来构建小型开源”toolshim”模型的微调数据——这是真实的 eval/轨迹驱动的模型改进,但改进的是后续版本中随附的独立小型解释器模型,不是正在运行的 agent 自我纠正。
    • evals/harbor/:一个 terminal-bench 风格的基准测试工具,对比 Goose(以及 opencode、pi、aider、claude-code 等其他 CLI)在不同模型下的表现,配有 compare_bench_run.yaml/analyze_bench_failure.yaml recipe,让agent 自己读取两份轨迹 + 任务规格 + 验证器输出,解释为何一次运行通过而另一次失败。这是帮助开发者理解基准测试结果的工具,不是自动的循环内自我纠正机制。
    • 结论:该维度”未实现为自动化的运行时自进化循环”。最接近的两个真实机制是 (a) 确定性的成功检查重试(recipe 功能),(b) 离线/开发侧的、eval 驱动的辅助 toolshim 模型微调,两者均有源码/文档实证,非推测。

可观测性(日志 / trace 格式)

  • 结构化 tracing spantracing::info_span! 包裹整个 reply 循环(reply_stream,agent.rs 约 L1887),字段包括 trace_inputtrace_outputsession.idsession.usersession.hostsession.agent_type = "goose"——即 Goose 输出的是语义化的、面向 LLM 可观测性的 span 字段,而非普通 Rust tracing
  • OTLP 导出crates/goose/src/otel/otlp.rs(981 行,本轮未深读)——真实的 OpenTelemetry Protocol 导出器,由 otel cargo feature 控制启用(main.rs 中可见 #[cfg(feature = "otel")])。
  • Langfuse 集成crates/goose/src/tracing/langfuse_layer.rs——一个专门的 tracing_subscriber Layer,批量收集 span 并 POST 到 Langfuse 接收端点(默认 http://localhost:3000),完整定义了请求/响应结构(LangfuseIngestionResponse/Success/Error)。这是直接嵌入 harness 的一等 LLM 可观测性工具,而非外挂。
    • tracing/observation_layer.rs——ObservationLayer/SpanTracker/BatchManager/SpanData 通用抽象,Langfuse(及推测的其他后端)基于此构建(本轮未深读)。
    • tracing/rate_limiter.rs——对遥测事件发送做限流(RateLimitedTelemetrySender),与 OTLP/Langfuse 是独立关注点。
  • 用量分析遥测(与 trace/可观测性分离的另一条线):crates/goose/src/posthog.rs——PostHog 事件采集(us.i.posthog.com),源码中硬编码公开 API key(phc_RyX5CaY01...),可通过 GOOSE_TELEMETRY_ENABLED 配置项或 GOOSE_TELEMETRY_OFF=1 环境变量退出。这是产品分析遥测,不是调试/trace 机制——在 dossier 中应与 OTLP/Langfuse 的 trace 栈区分开。
  • 标准日志文件位置见 documentation/docs/guides/logs.md(本轮未打开)。

安全与权限(审批门、密钥管理)

  • GooseMode 枚举crates/goose-provider-types/src/goose_mode.rs)——四种模式:Auto(默认,自动批准所有工具调用)、Approve(每次工具调用前询问)、SmartApprove(仅对敏感调用询问)、Chat(完全不允许工具调用,纯聊天)。这是控制下述所有机制的顶层开关。
  • 工具审查流水线PermissionInspectorcrates/goose/src/permission/permission_inspector.rs)是若干 ToolInspector 实现(crate::tool_inspection::ToolInspector trait)之一,其结果合并进 PermissionCheckResult { approved, needs_approval, denied }。权限审查的判定是基础值;非权限类审查(安全扫描器)可以在之后覆盖它(apply_inspection_results_to_permissions)——即一次安全命中可以把原本已批准的调用升级为”需要审批”或”拒绝”。
  • 只读检测的 LLM-as-judgedetect_read_only_tools()permission_judge.rs)——在 SmartApprove 模式下,Goose 可以让同一个 LLM(通过一个带明确读写判定规则的专用工具 platform__tool_by_tool_permission)对一批待执行的工具调用做只读性分类,并自动批准判定为只读的调用。这是真正由 LLM 介导的权限决策,而不只是静态白名单。
  • 基于静态标注的只读检测PermissionInspector::apply_tool_annotations() 同时信任每个工具自身的 ToolAnnotations.read_only_hint(由 MCP 扩展自我声明)作为另一个更廉价的信号。
  • 人工审批门的机制ToolConfirmationRouteragents/tool_confirmation_router.rs)是一个 HashMap<request_id, oneshot::Sender<PermissionConfirmation>>——当工具需要审批时,循环注册一个 receiver 并阻塞等待;UI/CLI 通过 deliver() 异步送达 PermissionConfirmationAllowOnce/DenyOnce等,PrincipalType::Tool)。失效的 receiver(任务已取消)在下次 register() 时被清理。有完整单元测试覆盖,包括乱序并发送达场景。
  • Prompt 注入/对抗输入安全crates/goose/src/security/):
    • SecurityManager::analyze_tool_requests()——受 SECURITY_PROMPT_ENABLED 开关控制(默认关闭,opt-in)。
    • 两级检测,均可独立开关:模式/正则式(patterns.rs——ThreatPattern 结构体,含 RiskLevel Low/Medium/High/Critical 与 ThreatCategory:FileSystemDestruction、RemoteCodeExecution、DataExfiltration、SystemModification、NetworkAccess、ProcessManipulation、PrivilegeEscalation、CommandInjection,各自带数值化的 confidence_score()),以及 ML 分类器(classification_client.rsSECURITY_PROMPT_CLASSIFIER_ENABLED/SECURITY_COMMAND_CLASSIFIER_ENABLED,调用外部分类 API——本轮未深读,但存在 classification-api-spec.md 文档)。
    • egress_inspector.rs——从拟执行的 shell 命令中提取出站网络”目的地”(extract_destinations)并分类方向(Outbound/Inbound/Unknown)——这是工具调用级别的静态分析,独立于”沙箱与执行隔离”一节描述的 macOS 桌面网络出站代理沙箱(且是额外补充关系)。
    • adversary_inspector.rs(685 行,未深读)——据官方文档存在一份”Adversary Mode”指南(documentation/docs/guides/security/adversary-mode.md,本轮未打开)——标记为二阶段待办。
  • 扩展启动时的供应链检查:见”工具体系”一节的 OSV.dev 恶意包查询(extension_malware_check.rs)——这本质上也是一道安全/权限门(拒绝启动已被污染的 MCP server 包)。
  • 密钥/凭据管理:本轮未直接调查——扩展环境变量通过 extension_manager.rs 中的 merge_environments(envs, env_keys, ...) 合并(仅引用未追踪),另有一个 oauth/ 模块(crates/goose/src/oauth,本轮只列出未读)推测用于 provider OAuth 流程。标记为二阶段待办——目前没有关于 API key/密钥如何存储/在日志中脱敏的具体证据。

沙箱与执行隔离

  • 默认执行模式 = 无隔离developer__shell 工具(agents/platform_extensions/developer/shell.rs)直接在宿主机上运行子进程命令——该文件本身没有容器、chroot 或命名空间隔离。
  • 可选的 Docker 容器化扩展执行(含 developer 扩展本身,因为它和其他内置扩展一样通过同一套机制启动):crates/goose/src/agents/container.rs 定义了一个极简的 Container { id: String } 句柄;extension_manager.rs(约 L1015–1160)——若某个 Agent/会话设置了 ContainerAgent::set_container()/container(),agent.rs L898–905),则所有内置和 stdio 扩展的启动都被包装为 docker exec -i <container_id> ... 而非直接宿主机子进程。这是本次分析在源码中确认存在的沙箱机制——opt-in,非默认。
  • 官方文档记载但本次分析的 commit 源码中未能验证documentation/docs/guides/sandbox.md 描述了一套完整的 macOS-only 桌面沙箱GOOSE_SANDBOX=true),使用苹果的 sandbox-exec(seatbelt)做文件系统/进程限制,配合本地 HTTP CONNECT 出站过滤代理(含可热重载的域名黑名单文件、SSH/git-over-SSH 白名单、可选的 LaunchDarkly 驱动的动态出站控制)。该文档引用的具体源文件路径 ui/desktop/src/sandbox/index.ts 在本次 clone 的 commit 中不存在,全仓库 grep sandbox-execGOOSE_SANDBOX 零命中。应视为一个真实的、官方详细记录的设计,但在 SHA 8694a8d 这个版本的源码里无法验证——可能尚未合并到 main,或存在于私有/企业分支,或文档领先于 OSS 代码。不应在未重新核实更新 commit 的情况下断言该 seatbelt 沙箱已存在于代码中。
  • 未发现 gVisor/Firecracker/microVM 或 WASM 沙箱。

与模型的协同设计

  • Toolshimcrates/goose/src/providers/toolshim.rs,1394 行)是最清晰的模型协同设计案例:对于 tool-calling 能力弱或缺失的模型(博客中明确点名:Gemma3、DeepSeek-R1、Phi-4、Llama4 Maverick),Goose 完全不依赖 provider 的 tool-calling API——而是把工具定义以文本形式塞进系统提示(format_tool_infomodify_system_prompt_for_tool_json),并让模型的自由文本输出经过第二个本地”解释器”模型OllamaInterpreter/LocalInterpreter,默认 mistral-nemo,通过 DEFAULT_INTERPRETER_MODEL_OLLAMA;可经 GOOSE_TOOLSHIM_BACKEND/GOOSE_TOOLSHIM_MODEL 环境变量配置)重新解析、结构化为正规工具调用(augment_message_with_tool_calls)。同时直接处理特定厂商的工具调用标记 token(文件头部可见 <|tool_calls_section_begin|> 等 DeepSeek 风格标记常量)。
  • Toolshim 微调 R&D(博客 2025-04-11-finetuning-toolshim/index.md):计划将小型(≤12B)开源模型专门微调为 toolshim 解释器,训练数据来自真实历史 Goose 会话工具调用(与若干开源模型的重新生成输出配对,过滤掉格式错误/失败的调用)。这是 harness 的工具调用契约与开源模型实际产出能力之间刻意的、有文档记录的协同设计。
  • manages_own_context() provider 标志位(用于 context_mgmt/mod.rscheck_if_compaction_neededmaybe_summarize_tool_pairs)——让特定 provider 可以选择退出 Goose 自身的压缩/摘要逻辑,推测是因为该 provider 在服务端自行管理上下文窗口/缓存。证实核心循环中存在 provider 特定的行为分支,具体哪些 provider 设置了该标志未进一步调查。
  • ACP-as-provider:Goose 可以把外部 ACP agent(Claude Code、Codex)作为模型执行层本身使用,而非普通的 chat-completions provider——“the ACP agent handles tool execution internally”——比简单的 API 封装更深一层的 harness/模型协同设计。
  • tiny_model_system.md——一份专供小型/本地模型使用的、推测更短更简单的系统提示变体,同时存在于 crates/goose/src/prompts/ 和另一个专门做本地推理的 crate crates/goose-local-inference/src/prompts/ 中——证实针对小模型存在刻意区别于主 system.md(面向前沿模型)的提示策略。本轮未深读。

轨迹利用(session/trajectory 是否反哺训练/评测)

  • 未发现在正常使用中自动把会话轨迹反馈进训练或评测的机制。 具体已证实的是:
    • Toolshim 微调数据管道(博客,见”与模型的协同设计”)——明确从历史 Goose 会话中收集工具调用轨迹作为 toolshim 解释器模型的微调数据。这是唯一清晰的轨迹→训练关联,但它是一个有文档记录的 R&D 流程(数据采集 + 离线微调),不是自动化的常驻循环,且训练的是辅助模型,不是主 agent 策略本身。
    • evals/harbor/ 基准测试工具——让 Goose(及竞品 harness:opencode、pi、aider、claude-code)跑 terminal-bench-2,完整记录每个任务的轨迹到 runs/ 下,并配有 agent 驱动的 recipe(analyze_bench_failure.yamlcompare_bench_run.yaml)读取轨迹 + 验证器输出以解释运行间的通过/失败差异——这是面向开发团队的 eval/轨迹分析工具,不是训练循环的反馈。
    • 跨 harness 轨迹导入session/import_formats/{claude_code,codex,pi}.rs)——Goose 可以把 Claude Code/Codex/Pi 的会话轨迹导入自己的会话格式,推测是为了用户方便(继续在别的工具中开始的工作)或可能是为了给 harbor 对比工具提供数据——具体消费方本轮未追踪确认。
    • Nostr 会话导出nostr_share.rs)——面向公开分享的轨迹导出,社交/分享用途,非训练管道。
    • 结论:该维度可概括为**“轨迹的导出/导入服务于互操作性和离线 eval 工具,没有证据表明存在自动化的、面向主 agent 策略的轨迹→训练数据反馈”**。

与同类 harness 的关键差异(1-3 条,可以先留一句概述,后续 synthesis 阶段会做跨 harness 对比)

  • Toolshim 是本次调研中在同类 harness 里少见的设计:为特定弱 tool-calling 开源模型(Gemma3/DeepSeek-R1/Phi-4/Llama4)单独引入一个本地二级解释器模型来补足工具调用能力,这是比”prompt 里放示例”更深的模型协同设计。
  • summon 扩展的 delegate/load 二元设计——用两个通用工具(而非专门的编排 DSL)同时覆盖”生成子代理”和”发现/轮询/取消后台任务”,且编排策略(何时并行、何时分区写操作)直接写在工具 docstring 里让模型读,而非独立的 planner 组件;同时通过 MCP/ACP 两条协议路径原生支持委派给 Codex、Claude Code 等外部 harness,互操作性程度高于多数同类工具。
  • 跨 harness 对比细节(与 Aider/Cline/opencode 等在 agent loop、压缩策略、权限模型上的具体差异)留待 synthesis 阶段统一展开。

原始源码定位

  • repo: https://github.com/aaif-goose/goose(原 https://github.com/block/goose,现仍可 clone/重定向)
  • commit/version analyzed: 8694a8d1040e40735a6ac3dd09a7f1d1ffe4ef8f(2026-07-06)
  • 关键文件列表(相对路径):
    • crates/goose/src/agents/agent.rs
    • crates/goose/src/agents/moim.rs
    • crates/goose/src/agents/tool_execution.rs
    • crates/goose/src/agents/tool_confirmation_router.rs
    • crates/goose/src/agents/retry.rs
    • crates/goose/src/agents/container.rs
    • crates/goose/src/agents/extension_malware_check.rs
    • crates/goose/src/agents/subagent_handler.rs
    • crates/goose/src/agents/subagent_task_config.rs
    • crates/goose/src/agents/platform_tools.rs
    • crates/goose/src/agents/platform_extensions/summon.rs
    • crates/goose/src/agents/platform_extensions/orchestrator.rs(未深读)
    • crates/goose/src/agents/platform_extensions/developer/shell.rs
    • crates/goose/src/agents/extension_manager.rs
    • crates/goose/src/agents/prompt_manager.rs(未深读)
    • crates/goose/src/context_mgmt/mod.rs
    • crates/goose/src/prompts/{system.md,compaction.md,subagent_system.md,plan.md,permission_judge.md,tiny_model_system.md}
    • crates/goose/src/hints/load_hints.rs
    • crates/goose/src/permission/{permission_judge.rs,permission_inspector.rs,permission_store.rs}
    • crates/goose/src/security/{mod.rs,egress_inspector.rs,patterns.rs,scanner.rs,adversary_inspector.rs,classification_client.rs,security_inspector.rs}
    • crates/goose-provider-types/src/goose_mode.rs
    • crates/goose/src/skills/mod.rs
    • crates/goose/src/plugins/{mod.rs,discovery.rs,mcp_servers.rs,formats/gemini.rs,formats/open_plugins.rs}
    • crates/goose/src/hooks/mod.rs
    • crates/goose/src/session/session_manager.rs
    • crates/goose/src/session/nostr_share.rs
    • crates/goose/src/session/import_formats/{claude_code,codex,pi}.rs
    • crates/goose/src/providers/toolshim.rs
    • documentation/docs/goose-architecture/goose-architecture.md
    • documentation/docs/goose-architecture/extensions-design.md
    • documentation/docs/guides/sandbox.md
    • documentation/docs/guides/context-engineering/subagents.mdx
    • documentation/blog/2025-04-11-finetuning-toolshim/index.md
    • README.md
  • 未读但已标记的二阶段待办:crates/goose/src/recipe/*crates/goose/src/acp/*crates/goose/src/scheduler.rscrates/goose-mcp/src/*(developer 之外的内置 MCP server:computercontroller/memory/autovisualiser/peekaboo/tutorial)、crates/goose-server/src/routes/*documentation/docs/guides/security/{adversary-mode,prompt-injection-detection,classification-api-spec}.mddocumentation/docs/guides/sessions/smart-context-management.md,以及重新核实 macOS seatbelt 沙箱是否已在更新的 commit 中落地。

一手源存档(sources/)

存放于 /Users/zhao/projects/self-wiki/ai-research/sources/harness/goose/

  • NOTES.md — 完整调研笔记(本页内容来源)
  • key-files/AGENTS.md — 仓库根目录开发者说明
  • key-files/blog-finetuning-toolshim.md — 官方博客:toolshim 微调 R&D
  • key-files/doc-architecture.md — 官方架构文档
  • key-files/doc-extensions-design.md — 官方扩展设计文档(部分内容与实际代码不一致,已在正文标注)
  • key-files/doc-sandbox.md — 官方沙箱设计文档(引用的源文件在本 commit 中不存在,已在正文标注)
  • key-files/doc-subagents.mdx — 官方子代理文档
  • key-files/dot-goosehints — 仓库自身的 .goosehints 样本
  • key-files/prompt-compaction.mdprompt-permission_judge.mdprompt-plan.mdprompt-subagent_system.mdprompt-system.mdprompt-tiny_model_system.md — 各系统提示模板原文
  • key-files/rust-excerpts/ — 关键 Rust 源码片段(agent.rs、context_mgmt、toolshim、summon 等)