关于 gimbal-workflows
指导在 Gimbal 中编写 Go 工作流,涵盖结构、Agent 角色、提示词、交接与验证。它强调让决策和证据在源代码中清晰可见,并区分任务策略与适配器恢复。
主要功能
- 01围绕明确结果设计工作流
- 02选择顺序、分支或自适应循环
- 03定义角色、所有权与交接
- 04指导提示词与上下文选择
- 05通过记录的证据验证结果
- 06说明服务与取消的生命周期
适用场景
- 01构建分阶段的研究与实现工作流
- 02协调独立方案并进行评审
- 03设计验证与重新规划循环
- 04根据源代码和证据诊断工作流行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tylergannon/ gimbal --skill gimbal-workflows安装后在 Claude Code 中输入/gimbal-workflows确认已加载。
附带文件references/patterns.md
详细介绍
编写 Gimbal 工作流
编写的程序应让其目的、决策和依据都清晰地呈现在源代码中。力求像一页伪代码一样清楚。研究、方案比选、批评、重试、工作树和交付,都是通过普通 Go 代码和 Gimbal 原语内联编写的策略。
适配器负责传输维护和原生状态协调,并以有界、可观测且负责任的尽力方式完成每个请求的轮次。不要在工作流中针对连接丢失添加重试:回复丢失并不能证明操作从未发生。工作流负责任务策略和独立验证;适配器恢复时必须保留会话身份、避免重复工作、保留取消操作,并让未经验证的远程清理仍可重试。
当前 API 请参阅 Godoc。对于现有命令,请使用 使用 Gimbal;对于构建和安装应用程序, 请使用 构建和发布。
明确结果及其证明方式
与人工在 Gimbal 应用程序中的 /workflows/<name> 页面上一起查看内置工作流源代码。在代码检出目录中,运行 just dev 可启动实时应用程序:
工作流源代码的编辑会刷新其图表、提示词和嵌套上下文检查视图、指南及参数说明。人工可以分享带有已选中和已展开对象的 URL,同时 Agent 编辑这些对象的 Go 源代码。无效编辑会保留上一次成功的视图;标识符变更或移除时,视图会重置,不会猜测。已安装的应用程序会显示随附的快照。阅读页面不会运行工作流;请使用 gimbal run <name> 调用工作流。
使用紧邻操作的文档注释,在第一行提供人类可读的标题,说明操作、范围或条件;后续行提供描述。When true: Command provided 会标注条件为真的分支;case 注释会标注 switch 分支。保留静态源代码所表达的事实:不要虚构运行时值,也不要将未标注的操作解读为 Agent 意图。
说明工作流应完成什么、范围是什么,以及需要观察什么才能确认其奏效。为 Agent 提供目标和有用的已验证事实;除非特定方法是要求,否则让它们自行选择方法。随着事实逐渐明朗,计划可以改变。原始目标始终是权威依据。
在设计中区分三件事:
- 程序: 角色、分支、并发、反馈和停止决策。
- 输入: 本次调用的目标、项目、问题、计划或候选项。
- 知识: Agent 工作时可以检索的材料。
即使输入和知识不断变化,程序也应始终易于理解。将任务数据放在参数、范围上下文和本地文件中,而不是把每项新任务都编码进编排逻辑。
选择最精简且实用的结构
如果单个 Agent 或一个执行序列已足够,就采用它。只有在确实需要有用的上下文、独立判断或工作交接时,才添加角色或阶段。
| 需求 | 结构 |
|---|---|
| 范围明确的单项任务 | 一个 Agent 轮次。 |
| 有依赖关系的阶段 | 显式传递结果的执行序列。 |
| 独立调查或候选方案 | 并发分支,然后汇合。 |
| 多个 Agent 需要相同的初始研究 | 先研究一次,再分叉对话。 |
| 相互竞争的实现方案 | 使用不同工作树,然后由评审者检查实际候选方案。 |
| 批评与修订 | 明确的批评/修订轮次,并设定停止条件。 |
| 已知的有限集合 | 遍历提供的各项。 |
| 下一项有用任务取决于新证据 | 由规划器驱动的循环,并提供工作者反馈和验证反馈。 |
让每项策略都在工作流中清晰可见。隐藏编排逻辑的辅助函数可能会让更短的文件更难理解。在 Gimbal 仓库中,新增导出 API 名称必须获得 Tyler 的明确请求。
选择如何组合研究、并行尝试、批评或自适应实现时,请阅读 工作流模式。
明确角色职责
使用 roles.go 中已定义的角色常量。分支名称用于标识参与者;角色用于标识可复用的工作类型;运行绑定用于选择模型。不要为了分配其他模型而向 internal/builtin/defaults.json
添加特定于工作流或提供方的角色。目录变更需要明确的产品决策,以便模型分配在不同工作流中保持可复用。
研究员负责查明事实并找到有用的来源位置。规划者负责选择下一项任务。工作者负责执行任务。验证者负责检查结果,以及证据是否足以证明满足验收条件。主管负责指导正在工作的 Agent。根据任务需要使用相应角色;列出所有可能的角色并不会让工作流变得更好。
在需要的地方保持独立性。共享研究成果可以避免重复阅读,但评判者必须检查原始证据和实际候选项。实施者的总结可以帮助验证,但无法证明实现有效。将工作者的对话分支给评判者,会连同有用的上下文一起带上其中的假设。
明确责任归属和交接
根据工作的生命周期安排会话。规划者可能需要在多个任务之间保持连续性;任务工作者可能需要与之前的尝试隔离。复用会话也会复用其对话历史。结束一个作用域,并不会抹去该 Agent 已经看到的内容。
每个并行分支都必须有负责人,并在其所属工作结束前完成汇合。取消和清理是两项不同的工作。若并行编辑 Agent 可能互相干扰,就为它们分别提供工作树,并核实它们实际写入的位置。
派发任务前,先在本地保存关键信息。提示词应指明问题、计划、源文件或所需研究成果的绝对路径。对于大型语料库,通过精简索引检索,并传递选定的证据或其位置。只保留相关上下文,不要在每轮对话中复制整个语料库。
交接内容应向下一个角色明确说明具体任务、相关文件、已观察到的结果、尚未解决的发现和决策。明确提供反馈;不要依赖子作用域或提供方对话自动成为共享的项目状态。其他角色必须独立检查的知识,应保存在本地产物中。
编写留有判断空间的提示词
使用通俗的英文:说明要阅读什么、要产出什么结果、重要约束是什么,以及预期答案是什么。让提示词在源代码中易于检查;特定任务的数据应放在上下文中。诊断异常行为时,阅读渲染后的提示词,因为框架指令和先前对话也会产生影响。
如果工作流需要根据字段作出决策,就使用结构化答案。这些字段说明本身就是给 Agent 的指令。否则,普通文本或本地产物可能就足够了。避免使用只是重述模型已有理解的复杂输出约定。
围绕目标调整计划
自适应循环应根据目标、当前待办事项和观察到的结果来选择工作。分配一项目标明确、范围完整且有完成定义的工作。当不确定性阻碍可靠实现时,调查也属于有效工作。
将实际的工作者结果和验证结果反馈给规划流程。保留尚未解决的发现,并说明推迟工作的原因,以免重新规划时悄然丢失这些内容。评审发现是需要针对目标调查的主张,而不是自动纳入目标的事项。
让重试、限制和升级处理清晰可见,并与任务相称。提供的计划可以作为待办事项的起点,但不应决定之后的每项分配。结束任务调度与实现目标是两个独立的决定。
将能力投入到存在不确定性的环节。当边界清晰的规划能让分配易于撤销且可独立检查时,前沿规划器即使需要一次昂贵的调用,也可能值得使用。对于低风险的后台工作,如果经过的时间不如 token 成本重要,而且工作流能够容忍几次已完成的尝试被验证拒绝,直到某次尝试成功,就可以使用成本更低的 Terra 或 Sonnet 工作者。验证器的能力应与风险相匹配;将每次拒绝反馈给规划流程,并限制尝试次数。
这是工作流特性,而不是一句模型选择口号。对于工作不可逆、验证薄弱,或错误尝试可能破坏共享状态的情况,不要使用这种模式。提供商、执行框架或执行方面的错误不属于被拒绝的实现尝试;除非工作流明确处理此类错误,否则不要重试。
防止范围偏移
对于实现工作流,应为规划器、工作者和验证器提供范围指导。指导内容应反对过度设计、未请求的功能、过度打磨,以及缺乏合理的实际失败单元测试支撑的假设性边界情况修复。
指导仅供参考,绝不能成为完成工作的门槛。也要在初始任务分配中写明必要约束:短暂的调用可能在指导发挥作用前就已结束。在启动独立运行或托管实例前设置 TYPESAFE_API_KEY。Jev 会筛查已完成且暴露的思考内容,供已连接的监督者查看;它没有定时检查节奏,也没有备用机制。不提供这些事件的提供商不会触发自动评审。应观察异议是否改变了行为,而不要将建立连接或发送消息视为监督有效的证明。
验证行为并评估完成情况
在可行时,应在实现前选择有意义的验收依据。 不要让执行者为了通过检查而降低该条件。记录实际检查结果;Agent 声称检查通过,不能推翻命令失败的事实。
当 Agent 需要解读命令结果时,使用 Check:它会在当前作用域中记录命令、工作目录、退出代码、两个输出流以及任何执行错误,供下一轮使用。它的键遵循与 Set 相同的规则:在该作用域内是编译时常量,且只写入一次。在调用位置明确命名重复观察,例如 tests.1 和 tests.2。非零退出代码是证据,不是 Check 错误;执行、捕获或记录失败才是错误。普通 Go 代码需要返回值本身时,使用 RunCommand。Check 收集证据,但绝不会认证成功。
对于必须在一个作用域内持续运行的前台依赖(例如开发服务器),使用 Service(ctx, name, workdir, command)。Gimbal 会通过 zsh -c 启动该字符串,并立即继续;成功启动并不代表已就绪。应在普通工作流代码中通过 Check 或服务公开的协议检查就绪状态。在作用域关闭前发生任何退出(包括退出代码为零),都会导致所属作用域失败并取消。
声明该服务的作用域就是其生命周期边界。在 Iterate 外声明的服务会在各个条目作用域之间保持运行;在条目内声明的服务会在进入下一个条目前结束。正常关闭和取消时,会向服务的进程组发送 SIGTERM,随后在限定时间后升级为 SIGKILL。命令必须在前台运行,其后代进程也必须留在该进程组中。Gimbal 会记录输出和状态,但不会添加重启、健康检查,也不会管理由 Docker、Overmind 或类似工具在外部拥有的资源。
验证者会检查工作及其验证是否合理。构建或测试门禁通过,只能证明它实际覆盖的内容。有关实时工作流、外部引导或浏览器交互的声明,需要通过观察这些行为来验证。应区分任务结果、执行错误、已结束的调度和已达成的目标。
如果缺少证明或仍存在实际阻碍,应如实报告结果。 风格偏好和无关改进不应成为验收门槛。
让工作流可调用且易于理解
编写一个普通的 Go 入口,接收 context.Context、gimbal.Env,并可选地接收一个包内的 Params 结构体。支持的调用字段类型为字符串、整数、布尔值,以及这些类型的 polytype.Optional。字段注释用于提供可见的帮助文本;JSON 标签用于提供提交时使用的名称。必填字符串不得为空白,必填整数必须为正数。可选字段会保留省略与显式空值、false 和零之间的区别;Optional 不接受 null。
使用已安装的宿主生成外部模块:
gimbal generate --dir . --entry Review --name review \
--role-default code-review=gpt-5.6-luna
在项目的 go.mod 中将 github.com/tylergannon/polytype/polytype 声明为 Go 工具,并固定到宿主的 Polytype 版本。将 Gimbal 和所有共享包固定到已部署的宿主版本,并使用相同的 Go 工具链、平台和构建标志。生成过程会针对具体的本地 Generate[T] 输出调用 go tool polytype --validate,并在工作流包中写入输入适配器、架构、有序字段、图和源代码指南。以 Go 源代码和字段注释为准;更改输入、输出或工作流结构后应重新生成。无需生成项目的前端。
A 个插件的主包会导出 Register(*gimbal.Registry) error。使用 RegisterWorkflow 注册生成的 ReviewDefinition(),并使用 RegisterBackend 注册任何后端配置/工厂。使用本地主机匹配的构建标志,通过 go build -buildmode=plugin 构建。对于已发布的 CLI,使用 -trimpath,并按照分发中所述,在 Go 工作区中使用精确的已发布 Gimbal 源码。将 .so 安装到已配置的 --plugin-dir 中。中央服务和工作流守护进程会在接受任务前,分别加载各自配置目录中的插件,并按排序顺序加载。将匹配的插件部署到中央服务和工作流环境;重启后,新目录才会生效。不兼容或重复的定义会导致启动失败。生成的图不具有初始化注册权限。
内置工作流遵循相同的定义和注册表路径。其清单保存在 internal/builtin/workflows.go 中;go generate ./... 会重新生成该选择。CLI 从所选中央服务获取描述,生成实用的参数和角色标志,然后提交纯调用数据。共享的 Run 表单会使用相同的运行时元数据,包括可选的 Include 控件。中央服务会在接纳前验证,工作流守护进程则会在启动独立运行器前再次准备。使用 JSON 或 @file 配合 --input,或使用参数标志;使用 --follow 等待任务完成。
工作流路由和任务路由彼此独立。--workflow-endpoint 用于选择 HTTP 工作流守护进程;--workflow-project 用于指定其本地项目,--work-dir 用于指定其执行目录。--task-endpoint 用于选择任务守护进程。对于已注册的后端,使用 --workflow-route 或 --task-route,并提供包含 name、configuration 和 environment 的 JSON 路由。每个环境都提供自己的工作区根目录和已配置的仓库。中央项目路径不是远程执行目录。请显式传输指定的上下文和任务文件;正文中任意的绝对路径不会自动改写。普通本地调用仍会作为独立子进程运行,并使用直接位于本地的任务。
对于远程轮次,gimbal.WithTaskFiles(ctx, backend.TaskFile{Name: "input.txt", Bytes: data}) 会提供显式命名的字节数据,以及运行时管理的上下文。任务环境会写入这些文件,并向 Agent 提供其原生路径。使用 gimbal.WithYields(ctx, "store", "DATABASE_URL") 作为 RunCommand、Check 或前台 Service 的上下文参数,以声明输出。不要赋值给返回的上下文:输出只属于该生产者,工作流检查器会拒绝其他位置的声明。程序会将 NAME=value 字符串写入 ENV_FILE;只有资源就绪后,服务才会将已完成的文件原子重命名到目标位置。即使服务没有输出,也必须发布空文件。有限运行时长的生产者只有在以零状态退出后才会发布输出。
gimbal.WithRequirements(ctx, "store", "DATABASE_URL") 用于声明使用操作的需求。重复调用会累积对多个存储区的访问权限。在任一声明中,都可以用 gimbal.DefaultStore 指定未命名的存储区。Gimbal 会检查指定的值,并授予对整个可见存储区的访问权限。程序会接收字符串环境变量;Agent 则会调用其原生执行器提供的、作用于特定操作的 Gimbal 回调。值不会自动插入提示词。子定义会在所有存储区中遮蔽祖先定义。
命名环境使用 OrchestratorBackend 建立监听守护进程;消息传递负责交付工作,SecretsBackend 提供限定作用域的值。路由的 Backends 构造数据会显式配置这些依赖。提供的本地实现会启动已配置的守护进程命令,并使用私有共享文件存储。清理作用域时,会先停止依赖它的原生任务,再释放值,最后释放环境占用。服务会收到 SIGINT,并有十秒时间完成清理;无法确认的清理状态会继续保留。系统不提供自动重放、重启、密钥轮换或逐键权限管理。
独立运行 gimbal.Run(gimbal.Project(ctx, dir), ...) 会在调用方进程中执行,并将内容写入 dir/runs,不会连接到正在运行的实例。gimbal run-prompt 会创建自己的无头运行时;除非通过 --logs 指定一个全新的空目录,否则会使用临时日志目录。这两种路径都不会加入托管实例的实时控制,也不会继承其启动环境。请将它们的持久状态与已获准加入运行中实例的项目分开;并发使用共享状态不受支持。
CLI 文档是编写工作流的一部分。调用方无需阅读实现,就应能了解用途、必需输入、有意义的默认值、输出或变更、完成条件与验证要求、限制,以及实用的调用方式。应针对相应工作流提供足够详细的信息,而不是套用固定字数或模板化内容。
当前生成器会将入口函数的文档摘要用于简短帮助,将包文档用于详细帮助,并将参数字段注释用于标志帮助。请将详细说明和示例放在包文档中;仅写在函数注释中的额外段落不会出现在详细帮助里。
运行启动时,会将已注册的图与持久状态一同保存。运行界面读取的是保存的图,因此守护进程重启或之后构建工作流,都不会改变已有运行的图。请保留工作流的 go:generate 指令,并在更改其结构后重新生成。
修改注释后,请检查生成的工作流列表和详细帮助。图或输出架构不能替代面向调用方的文档。如果所需帮助必须修改生成器,请明确指出具体缺口。
最后通过观察验证
运行相关检查,并使用 Luna 或 Haiku 等低成本模型实际执行工作流。检查实际的提示词、交接、决策、验证和结果。确认调用方能通过 CLI 帮助发现并理解该工作流。报告观察到的情况、运行所用的模型,以及仍未验证的内容。