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 fromblock/gooseto 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/src无sandbox/目录,全仓库 grepsandbox-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_failureshell 命令重试,见”自进化能力”一节)——若判定无需再重试,则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_limit与GOOSE_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_TEXT、TOOL_LOOP_CONTINUATION_TEXT、MANUAL_COMPACT_CONTINUATION_TEXT)确保模型不会向用户”自曝”被压缩过。
- 可见性魔术:原始消息被打上
- 工具对摘要(区别于整体压缩的更细粒度机制):
maybe_summarize_tool_pairs在后台任务中批量(每批 10 条,TOOLCALL_SUMMARIZATION_BATCH_SIZE)摘要较旧的 tool-request/tool-response 对,触发条件是工具调用数超过一个计算出的截断值(compute_tool_call_cutoff:3 * 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_version、sessions(含 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 参数与
ToolAnnotations(read_only_hint、destructive、idempotent、open_world)的rmcp::model::Tool对象,这些标注被权限系统直接消费。 - 注册:
ExtensionManager(crates/goose/src/agents/extension_manager.rs)为每种扩展配置变体构建 MCP 客户端——Builtin(进程内 duplex pipe 或 Dockerexec)、Stdio(子进程或 Dockerexec)、InlinePython(写临时.py文件执行)。Agent上的add_extension/add_extensions_bulk/remove_extension/list_extensions(agent.rs 约 L1313–1494)。PermissionInspector的apply_tool_annotations会缓存哪些工具是扩展自身声明为只读的(区别于 LLM 判定只读,见”安全与权限”一节)。
- 分派:
Agent::dispatch_tool_call()(agent.rs:1044)按名称把工具调用路由到前端工具(客户端处理,如桌面 UI 动作)、平台工具(内置于 agent 二进制,如platform__manage_schedule、summon扩展的delegate/load),或真正的 MCPcall_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_template,crate::prompt_template)渲染,变量包括moim_system_prompt_block、code_execution_mode、extensions(含.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.md和CLAUDE.md(见crates/goose/src/hints/load_hints.rs,常量GOOSE_HINTS_FILENAME、AGENTS_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 预算与工具列表(SubagentPromptContext:max_turns、subagent_id、task_instructions、tool_count、available_tools)。 - 压缩提示:
compaction.md模板,专供摘要子调用使用的独立系统提示。 - 其他存在但未深读的提示模板:
plan.md(规划模式)、permission_judge.md(只读工具判定,简短)、tiny_model_system.md(面向小型/本地模型的精简系统提示,在goose-local-inference/src/prompts/tiny_model_system.md中也有一份镜像)、recipe.md、session_name.md、apps_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::spawn的BackgroundTask在后台运行,带自己的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.rs的get_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(默认模式)下被模型自主创建——在Approve、SmartApprove、Chat模式下被禁用。 - 外部代理委派: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/(本轮只列出未读)。
- 作为 MCP server:官方示例配置把
- 跨时间的调度/编排:
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/skills(global_skills_dir())与项目级<project>/.agents/skills(project_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.yamlrecipe,让agent 自己读取两份轨迹 + 任务规格 + 验证器输出,解释为何一次运行通过而另一次失败。这是帮助开发者理解基准测试结果的工具,不是自动的循环内自我纠正机制。- 结论:该维度”未实现为自动化的运行时自进化循环”。最接近的两个真实机制是 (a) 确定性的成功检查重试(recipe 功能),(b) 离线/开发侧的、eval 驱动的辅助 toolshim 模型微调,两者均有源码/文档实证,非推测。
- Recipe 级带成功检查的重试:
可观测性(日志 / trace 格式)
- 结构化 tracing span:
tracing::info_span!包裹整个 reply 循环(reply_stream,agent.rs 约 L1887),字段包括trace_input、trace_output、session.id、session.user、session.host、session.agent_type = "goose"——即 Goose 输出的是语义化的、面向 LLM 可观测性的 span 字段,而非普通 Rusttracing。 - OTLP 导出:
crates/goose/src/otel/otlp.rs(981 行,本轮未深读)——真实的 OpenTelemetry Protocol 导出器,由otelcargo feature 控制启用(main.rs中可见#[cfg(feature = "otel")])。 - Langfuse 集成:
crates/goose/src/tracing/langfuse_layer.rs——一个专门的tracing_subscriberLayer,批量收集 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(完全不允许工具调用,纯聊天)。这是控制下述所有机制的顶层开关。- 工具审查流水线:
PermissionInspector(crates/goose/src/permission/permission_inspector.rs)是若干ToolInspector实现(crate::tool_inspection::ToolInspectortrait)之一,其结果合并进PermissionCheckResult { approved, needs_approval, denied }。权限审查的判定是基础值;非权限类审查(安全扫描器)可以在之后覆盖它(apply_inspection_results_to_permissions)——即一次安全命中可以把原本已批准的调用升级为”需要审批”或”拒绝”。 - 只读检测的 LLM-as-judge:
detect_read_only_tools()(permission_judge.rs)——在SmartApprove模式下,Goose 可以让同一个 LLM(通过一个带明确读写判定规则的专用工具platform__tool_by_tool_permission)对一批待执行的工具调用做只读性分类,并自动批准判定为只读的调用。这是真正由 LLM 介导的权限决策,而不只是静态白名单。 - 基于静态标注的只读检测:
PermissionInspector::apply_tool_annotations()同时信任每个工具自身的ToolAnnotations.read_only_hint(由 MCP 扩展自我声明)作为另一个更廉价的信号。 - 人工审批门的机制:
ToolConfirmationRouter(agents/tool_confirmation_router.rs)是一个HashMap<request_id, oneshot::Sender<PermissionConfirmation>>——当工具需要审批时,循环注册一个 receiver 并阻塞等待;UI/CLI 通过deliver()异步送达PermissionConfirmation(AllowOnce/DenyOnce等,PrincipalType::Tool)。失效的 receiver(任务已取消)在下次register()时被清理。有完整单元测试覆盖,包括乱序并发送达场景。 - Prompt 注入/对抗输入安全(
crates/goose/src/security/):SecurityManager::analyze_tool_requests()——受SECURITY_PROMPT_ENABLED开关控制(默认关闭,opt-in)。- 两级检测,均可独立开关:模式/正则式(
patterns.rs——ThreatPattern结构体,含RiskLevelLow/Medium/High/Critical 与ThreatCategory:FileSystemDestruction、RemoteCodeExecution、DataExfiltration、SystemModification、NetworkAccess、ProcessManipulation、PrivilegeEscalation、CommandInjection,各自带数值化的confidence_score()),以及 ML 分类器(classification_client.rs,SECURITY_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/会话设置了Container(Agent::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 中不存在,全仓库 grepsandbox-exec和GOOSE_SANDBOX零命中。应视为一个真实的、官方详细记录的设计,但在 SHA8694a8d这个版本的源码里无法验证——可能尚未合并到 main,或存在于私有/企业分支,或文档领先于 OSS 代码。不应在未重新核实更新 commit 的情况下断言该 seatbelt 沙箱已存在于代码中。 - 未发现 gVisor/Firecracker/microVM 或 WASM 沙箱。
与模型的协同设计
- Toolshim(
crates/goose/src/providers/toolshim.rs,1394 行)是最清晰的模型协同设计案例:对于 tool-calling 能力弱或缺失的模型(博客中明确点名:Gemma3、DeepSeek-R1、Phi-4、Llama4 Maverick),Goose 完全不依赖 provider 的 tool-calling API——而是把工具定义以文本形式塞进系统提示(format_tool_info、modify_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.rs的check_if_compaction_needed与maybe_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/和另一个专门做本地推理的 cratecrates/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.yaml、compare_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.rscrates/goose/src/agents/moim.rscrates/goose/src/agents/tool_execution.rscrates/goose/src/agents/tool_confirmation_router.rscrates/goose/src/agents/retry.rscrates/goose/src/agents/container.rscrates/goose/src/agents/extension_malware_check.rscrates/goose/src/agents/subagent_handler.rscrates/goose/src/agents/subagent_task_config.rscrates/goose/src/agents/platform_tools.rscrates/goose/src/agents/platform_extensions/summon.rscrates/goose/src/agents/platform_extensions/orchestrator.rs(未深读)crates/goose/src/agents/platform_extensions/developer/shell.rscrates/goose/src/agents/extension_manager.rscrates/goose/src/agents/prompt_manager.rs(未深读)crates/goose/src/context_mgmt/mod.rscrates/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.rscrates/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.rscrates/goose/src/skills/mod.rscrates/goose/src/plugins/{mod.rs,discovery.rs,mcp_servers.rs,formats/gemini.rs,formats/open_plugins.rs}crates/goose/src/hooks/mod.rscrates/goose/src/session/session_manager.rscrates/goose/src/session/nostr_share.rscrates/goose/src/session/import_formats/{claude_code,codex,pi}.rscrates/goose/src/providers/toolshim.rsdocumentation/docs/goose-architecture/goose-architecture.mddocumentation/docs/goose-architecture/extensions-design.mddocumentation/docs/guides/sandbox.mddocumentation/docs/guides/context-engineering/subagents.mdxdocumentation/blog/2025-04-11-finetuning-toolshim/index.mdREADME.md
- 未读但已标记的二阶段待办:
crates/goose/src/recipe/*、crates/goose/src/acp/*、crates/goose/src/scheduler.rs、crates/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}.md、documentation/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&Dkey-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.md、prompt-permission_judge.md、prompt-plan.md、prompt-subagent_system.md、prompt-system.md、prompt-tiny_model_system.md— 各系统提示模板原文key-files/rust-excerpts/— 关键 Rust 源码片段(agent.rs、context_mgmt、toolshim、summon 等)