Gas Town Convoy 机制详解:跨 Rig 批量工作追踪的持久化单元
Gas Town Convoy 机制详解跨 Rig 批量工作追踪的持久化单元【免费下载链接】gastownGas Town - multi-agent workspace manager项目地址: https://gitcode.com/GitHub_Trending/ga/gastownConvoy车队是 Gas Town 多 Agent 工作空间管理器中用于批量工作追踪的核心抽象它是一个持久化的追踪单元能够跨越多个 rig代码仓库工作区监控一组关联 issue 的完成进度并在全部完成后自动关闭并发出通知。本文基于 docs/concepts/convoy.md 与 internal/cmd/convoy.go、internal/convoy/operations.go 等源码实现展开读完后可掌握 convoy 的创建、追踪、状态检查、事件驱动派工与落地land通知的完整链路。概念Convoy 是什么Aconvoyis a persistent tracking unit that monitors related issues across multiple rigs. When you kick off work — even a single issue — a convoy tracks it so you can see when it lands and what was includedConvoy 是一个持久的追踪单元跨多个 rig 监控关联的 issue即使只启动单个 issue也会有 convoy 对其进行追踪以便看到它何时完成、包含哪些内容。其结构示意如下 Convoy (hq-cv-abc) │ ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ gt-xyz │ │ gt-def │ │ bd-abc │ │ gastown │ │ gastown │ │ beads │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ nux │ │ furiosa │ │ amber │ │(polecat)│ │(polecat)│ │(polecat)│ └─────────┘ └─────────┘ └─────────┘ │ the swarm (ephemeral)一个 convoy 下挂多个来自不同 rig 的 issue每个 issue 又由一个 polecat工作 Agent 的 worktree执行。Convoy 是“账本”polecat 是“工人”。Convoy vs SwarmConceptPersistent?IDDescriptionConvoyYeshq-cv-*Tracking unit. What you create, track, get notified about.SwarmNoNoneEphemeral. The workers currently on this convoys issues.Stranded ConvoyYeshq-cv-*A convoy with ready work but no polecats assigned. Needs attention.When you kick off a swarm, youre really:Creating a convoy (the tracking unit)Assigning polecats to the tracked issuesThe swarm is just those polecats while theyre workingWhen issues close, the convoy lands and notifies you. The swarm dissolves当你“启动一个 swarm”时实际上做的是1. 创建 convoy追踪单元2. 把 polecat 分配到被追踪的 issue 上3. “swarm”只是这些 polecat 在工作期间的称呼。当 issue 关闭后convoy 落地并发出通知swarm 随之消散。从源码看这种区分在 internal/cmd/convoy.go 中有明确体现convoy 是一个带gt:convoy标签的 beads issue可通过isConvoyIssue判定类型或标签而 worker 只是 tracked issue 上的assignee字段——swarm 没有任何独立数据结构纯粹是“当前分配给该 convoy 所追踪 issue 的工人集合”这一运行时状态。生命周期从 Open 到 LandedOPEN ──(all issues close)──► LANDED/CLOSED ↑ │ └──(add more issues)───────────┘ (auto-reopens)StateDescriptionopenActive tracking, work in progressclosedAll tracked issues closed, notification sentAdding issues to a closed convoy reopens it automatically向已关闭的 convoy 添加 issue 会自动将其重开。源码中的完整状态机文档描述的open/closed是基础状态。在 internal/cmd/convoy.go 中还可以看到更完整的生命周期常量const ( convoyStatusOpen open convoyStatusClosed closed convoyStatusStagedReady staged_ready convoyStatusStagedWarnings staged_warnings trackedStatusUnknown unknown // 跨 rig 无法解析状态时的哨兵值 )staged_ready/staged_warnings来自gt convoy stage命令见 internal/cmd/convoy_stage.go先对一批工作做依赖分析与波次wave规划并生成暂存 convoy确认无误后通过gt convoy launch将其转入open并派发第一波任务。状态迁移由validateConvoyStatusTransition严格约束open ↔ closed允许加 issue 触发自动重开即 closed → openstaged_* → openlaunch与staged_* → closed取消允许staged_* ↔ staged_*重新 stage允许open → staged_*与closed → staged_*拒绝返回 illegal convoy status transition 错误。trackedStatusUnknownunknown是一个值得注意的细节当被追踪的跨 rig bead 所在数据库缺失、parked 或不可路由时其状态无法解析。为避免把“无法确认”误判为“已完成”auto-close 逻辑将 unknown 单独计数、不触发自动关闭gt convoy status中也会以?符号明确标注见 internal/cmd/convoy.go 中closeConvoyIfComplete与formatConvoyStatus的实现。ID 生成Convoy 的 ID 采用hq-cv-前缀加 5 位 base36 随机后缀在 internal/cmd/convoy.go 的generateShortID中实现5 个 base36 字符约有 6000 万36^5 60,466,176种取值源码注释指出按生日悖论约需 1,100 个 ID 才会出现 1% 的碰撞概率对 convoy 的规模而言是安全的。hq-前缀表明 convoy 存储在 town 级HQbeads 库中这是它能跨 rig 追踪的存储基础见下文“跨 Rig 追踪”一节。快速上手Quick Start# Create a convoy tracking some issues gt convoy create Feature X gt-abc gt-def --notify overseer # Check progress gt convoy status hq-cv-abc # List active convoys (the dashboard) gt convoy list # See all convoys including landed ones gt convoy list --all命令详解Create创建 Convoy# Track multiple issues across rigs gt convoy create Deploy v2.0 gt-abc bd-xyz --notify gastown/joe # Track a single issue (still creates convoy for dashboard visibility) gt convoy create Fix auth bug gt-auth-fix # With default notification (from config) gt convoy create Feature X gt-a gt-b gt-c结合 internal/cmd/convoy.go 中convoyCreateCmd的 flag 定义创建时实际可用的完整参数集如下Flag说明--notify [addr]额外的完成通知地址单独使用时默认值为mayor/源码中通过NoOptDefVal mayor/实现--owner addr请求该 convoy 的负责人默认接收完成通知缺省为创建者身份created_by--owned标记为 caller-managed 生命周期打上gt:owned标签不注册自动 witness/refinery 流程之后需手动gt convoy land落地--merge direct\|mr\|local合并策略direct直接推 main无 MR、无 refinerymr创建 merge-request bead 由 refinery 处理默认local保留在 feature 分支上用于上游 PR、人工评审--molecule mol-id关联的 molecule ID--base-branch branchpolecat 的目标基线分支例如feat/extraction-review--from-epic epic-id从 epic 的子任务自动发现追踪对象见下文创建的 convoy 会以--typetask的 bead 写入 town 级 beads并附加gt:convoyowned 时另有gt:owned标签owner、notify、merge、molecule、base-branch 等元数据通过beads.SetConvoyFields序列化进 issue 的 description 字段由 internal/beads/fields.go 中的ConvoyFields结构体与ParseConvoyFields读写。另外源码中有一个防误用保护如果 convoy 名称形似 CLI flag如gt-e0kx5runConvoyCreate会直接拒绝创建beads.IsFlagLikeTitle校验。如果第一个参数看起来像 issue ID带 beads 前缀runConvoyCreate会把所有参数都当作 issue并自动取第一个 issue 的标题作为 convoy 名称。Add添加 Issue# Add issues to existing convoy gt convoy add hq-cv-abc gt-new-issue gt convoy add hq-cv-abc gt-issue1 gt-issue2 gt-issue3 # Adding to closed convoy requires reopening first bd update hq-cv-abc --statusopen gt convoy add hq-cv-abc gt-followup-fix注意文档示例中展示了手动重开的方式但从源码 internal/cmd/convoy.go 的runConvoyAdd实现看当前版本gt convoy add已经内置了自动重开逻辑若目标 convoy 处于closed会先执行bd update id --statusopen并额外把 description 中的CompletionNotifiedAt完成通知状态清空避免重复/陈旧通知最后才建立tracks关系。这与文档“Adding issues to a closed convoy reopens it automatically”的描述一致且比示例中的手动两步更简单。Status查看进度# Show issues and active workers (the swarm) gt convoy status hq-abc # All active convoys (the dashboard) gt convoy statusExample output: hq-cv-abc: Deploy v2.0 Status: ● Progress: 2/4 completed Created: 2025-12-30T10:15:00-08:00 Tracked Issues: ✓ gt-xyz: Update API endpoint [task] ✓ bd-abc: Fix validation [bug] ○ bd-ghi: Update docs [task] ○ gt-jkl: Deploy to prod [task]从 internal/cmd/convoy.go 的runConvoyStatus实现可以看到几个文档未展开的细节数字快捷方式gt convoy status 1可以直接用列表序号代替hq-cv-*IDresolveConvoyNumber解析状态符号语义✓ closed▶ in_progress/hooked? unknown跨 rig 不可达○ 其他issue 行尾括号内显示 issue 类型或 assignee 短名从gastown/polecats/goose这类路径取末段有活跃 worker 时还会以暗色附加worker (age)owned convoy 提示当 owned convoy 的全部 issue 完成但尚未 land 时输出会提示All issues complete. Land with: gt convoy land id--json输出会额外带出lifecyclesystem-managed/caller-managed与merge_strategy字段便于脚本化消费。ListConvoy 仪表盘# Active convoys (default) - the primary attention view gt convoy list # All convoys including landed gt convoy list --all # Only landed convoys gt convoy list --statusclosed # JSON output gt convoy list --jsonExample output:Convoys hq-cv-w3nm6: Feature X ● hq-cv-abc12: Bug fixes ● Use gt convoy status id for detailed view.实际列表实现runConvoyList还支持--tree参数以树形结构展示每个 convoy 及其子 issue 的完成进度✓/▶符号加(2/4)计数。底层查询通过bd list --labelgt:convoy完成并对旧数据做了兜底同时按issue_type convoy做一次 legacy 合并保证未打标签的历史 convoy 也能被列出见 internal/cmd/convoy.go 的listConvoyIssues。Check自动关闭完成的 Convoy文档中 quick start 未列出的重要命令gt convoy check # 检查所有 open convoy gt convoy check hq-cv-abc # 只检查指定 convoy gt convoy check --dry-run # 预览将关闭哪些 convoy它解决一个跨 rig 的语义缺口convoy 存在于 town 级 beads其追踪的 issue 分散在各 rig 的 beads 库中单纯bd close不会自动联动。gt convoy check就是这座桥——它遍历所有 open convoy取回每个 tracked issue 的最新状态当全部为closed/tombstone时自动关闭 convoyreason 为 All tracked issues completed并触发完成通知支持--dry-run预览。该命令可手动执行也会被 deacon patrol 周期性调用命令描述中明确说明。closeConvoyIfComplete中有两个值得注意的防御性设计0/0 不算完成如果一个 convoy 解析不到任何 tracked issue通常是跨 rig 追踪解析失败不会误判为“全部完成”而触发假 landed 通知直接跳过unknown 不关闭状态为unknown跨 rig 数据库不可达的 issue 不会阻止也不会促成关闭而是单独计数并在输出中提示保持 convoy 打开等待下一次检查。Close 与 Land两种关闭方式# 普通关闭默认要求所有 tracked issue 已关闭 gt convoy close hq-cv-abc gt convoy close hq-cv-abc --force # 强制关闭废弃的 convoy gt convoy close hq-cv-abc --reasonno longer needed --force gt convoy close hq-cv-xyz --notify mayor/ # 落地 owned convoy调用方自管理生命周期 gt convoy land hq-cv-abc # 要求 gt:owned 标签 gt convoy land hq-cv-abc --force # 即使还有 open issue gt convoy land hq-cv-abc --keep-worktrees # 跳过 worktree 清理 gt convoy land hq-cv-abc --dry-run # 预览两者的分工在 internal/cmd/convoy.go 中很清晰gt convoy close幂等重复关闭是 no-op默认校验 tracked issue 全部关闭否则列出仍未完成的 issue 并要求--forcegt convoy land是 witness/refinery 合并管线的“调用方自管理等价物”执行三个阶段1. 校验gt:owned标签2. 校验 tracked issue 完成度--force可跳过3. 清理该 convoy tracked issue 的 assignee 对应的 polecat worktreefindConvoyWorktrees通过比对各 rig 下polecats/目录与 assignee 路径rig/polecats/name来定位然后以 Landed by owner 为 reason 关闭 convoy 并发送完成通知。Stranded发现滞留的 Convoygt convoy stranded # 列出需要关注的 convoy gt convoy stranded --json # 机器可读输出供自动化使用从源码findStrandedConvoys与isReadyIssue的实现看“stranded”覆盖三类情况可喂料feedableconvoy 有 ready 但未被分配的 issue——输出会直接给出喂料命令gt sling mol-convoy-feed deacon/dogs --var convoyid卡住needs attention有 tracked issue 但没有任何一个 ready等待依赖解除或 worker 恢复空 convoy0 个 tracked issue建议gt convoy check id清理。“ready”的判定比表面更严格issue 必须未被 blocking 依赖阻塞、没有 open 的 sling 上下文areScheduled批量查询一次判定且open且无 assignee或虽有 assignee 但其 tmux 会话已死亡孤儿分子检测——tmux has-session失败即视为 worker 已死、issue 重新可派。Deacon patrol 会周期性运行该命令并派发 dog 来喂料滞留 convoy。事件驱动的 Convoy 喂料源码视角除了gt convoy check这类被动检查Gas Town 还实现了事件驱动的 convoy 推进。在 internal/convoy/operations.go 的CheckConvoysForIssue中当任意 issue 被关闭时系统会通过 beads 存储的GetDependentsWithMetadata反向查询所有以tracks关系追踪该 issue 的 convoy对每个未关闭、非 staged 的 convoy 执行幂等的gt convoy check id若 check 之后 convoy 仍为 open则调用feedNextReadyIssue反应式地派发下一个 ready issue——把 convoy 的喂料从“等待轮询式 patrol 周期”变成“完成事件即时触发”。feedNextReadyIssue的喂料规则很具体internal/convoy/operations.go按 priority 升序、ID 字典序排序 tracked issue取第一个满足条件的 issueopen、无 assignee、非容器类型、未被阻塞、rig 可路由且未 parked一次只派一个该 issue 完成后的下一次 close 事件再触发下一轮喂料形成流水线节奏slingable 类型白名单只有叶子工作项task/bug/feature/chore以及空类型beads 默认按 task 处理可被派发epic、convoy 等容器类型直接跳过IsSlingableTypeblocking 依赖判定blocks、conditional-blocks、waits-for、merge-blocks四类依赖指向未关闭 issue 时会阻塞派发parent-child 关系刻意不算阻塞子任务在父 epic 仍 open 时也可派发与 molecule step 行为一致。特别地merge-blocks类型下“closed”还不够——被阻 issue 的CloseReason必须以Merged in 开头确认代码真正被集成后才放行防止在未合并的代码基线上派发后续工作派发方式最终执行gt sling issue rig --no-boot若 convoy 元数据中记录了base-branch见create --base-branch会附加--base-branch参数保证 polecat 基于正确分支启动。跨 rig 状态的新鲜度处理是该文件的核心工程难点之一getConvoyTrackedIssues先用本地存储批量取状态对本地库中不存在的 bead例如 hq 库中追踪的ds-*bead优先通过StoreResolver按 ID 前缀路由到对应 rig 的存储做直连查询无 resolver 时回退到按前缀分组、逐 rig 执行bd show --json ids的子进程方案。跨 rig 依赖记录本身以external:prefix:id的包装形式存储FireCrossRigDepNotifications则会在某 issue 关闭时遍历各 rig 存储向被解锁 issue 所在 rig 的 witness 发送 nudge“Dependency resolved: ...”完成跨 rig 依赖解除的主动通知。通知机制NotificationsWhen a convoy lands (all tracked issues closed), subscribers are notified当 convoy 落地——全部被追踪 issue 关闭——订阅者会收到通知# Explicit subscriber gt convoy create Feature X gt-abc --notify gastown/joe # Multiple subscribers gt convoy create Feature X gt-abc --notify mayor/ --notify --humanNotification content: Convoy Landed: Deploy v2.0 (hq-cv-abc) Issues (3): ✓ gt-xyz: Update API endpoint ✓ gt-def: Add validation ✓ bd-abc: Update docs Duration: 2h 15m源码中的notifyConvoyCompletioninternal/cmd/convoy.go揭示了实际投递的完整链路遍历ConvoyFields.NotificationAddresses()owner notify 地址逐一向各地址发送gt mail send ... --from convoy/convoy-id邮件主题形如 Convoy landed:/li向 nudge watcher 发送gt nudge消息NudgeNotificationAddresses()始终通知mayor/除非已在上面的订阅列表中避免重复邮件正文附带 issue 总数与自创建起的 Duration按created_at计算与示例输出中的Duration: 2h 15m对应若 town settings 中convoy.notify_on_complete启用config.LoadOrCreateTownSettings读取还会额外 nudge 活跃的 Mayor 会话最后把当前时间写入 description 字段的CompletionNotifiedAt实现通知幂等——同一 convoy 重复触发完成检查时不会二次轰炸订阅者而gt convoy add重开 convoy 时会清除该字段使下一轮完成能重新通知。从 Epic 自动创建Create from EpicAuto-discover tracked issues from an existing epics children. Useful when a planning/decomposition tool has already structured work as an epic with child implementation beads自动从已有 epic 的子任务发现追踪对象。适用于规划/分解工具已将工作结构化为 epic 子实现 bead 的场景。# Auto-discover children from epic gt convoy create --from-epic gt-epic-abc # Override the convoy name (defaults to epic title) gt convoy create --from-epic gt-epic-abc Custom convoy name # Combine with other flags gt convoy create --from-epic gt-epic-abc --owned --mergedirectHow it works:Verifies the given bead is an epic校验给定 bead 是 epic否则报错--from-epic only works with epic beadsBFS-walks the parent-child hierarchy to find slingable descendantsBFS 遍历父子层级寻找可派发的叶子工作项Creates a standard convoy (hq-cv-*) tracking all slingable children (task, bug, feature, chore)创建标准 convoy追踪所有可派发子项Non-slingable types (sub-epics, decisions) are recursed into but never tracked directly. Only leaf work items appear in the convoy非可派发类型子 epic、decision会被继续递归但不会被直接追踪只有叶子工作项进入 convoy。这一过程在 internal/cmd/convoy.go 的collectEpicChildren中有对应实现BFS 队列遍历bd list children遇到 slingable 类型收入结果集遇到非 slingable 类型则入队继续下探并带visited集合防止环若 epic 下没有任何可派发叶子会报错。convoy 名称缺省取 epic 标题bd show epic的Title。Auto-Convoy on SlingWhen you sling a single issue without an existing convoy当你 sling 单个 issue 且不存在已有 convoy 时:gt sling bd-xyz beads/amberThis auto-creates a convoy so all work appears in the dashboard:自动创建 convoy让所有工作在仪表盘中可见Creates convoy: Work: bd-xyz创建 convoy命名 Work: bd-xyzTracks the issue追踪该 issueAssigns the polecat分配 polecatEven swarm of one gets convoy visibility即使“一个人的 swarm”也有 convoy 可见性。这一保证使 convoy 成为所有工作的统一追踪视图而不是可选项——无论是显式gt convoy create还是gt sling单发dashboardgt convoy list都能看到。跨 Rig 追踪Cross-Rig TrackingConvoys live in town-level beads (hq-cv-*prefix) and can track issues from any rigConvoy 存在于 town 级 beads 中前缀hq-cv-*可追踪任意 rig 的 issue:# Track issues from multiple rigs gt convoy create Full-stack feature \ gt-frontend-abc \ gt-backend-def \ bd-docs-xyzThetracksrelation is:tracks关系具有以下特性Non-blockingdoesnt affect issue workflow不影响被追踪 issue 自身的工作流issue 的关闭/推进不依赖 convoyAdditivecan add issues anytime随时可追加 issueCross-rigconvoy in hq-, issues in gt-, bd-, etc.convoy 在 hq-issue 分布在 gt-、bd-等从源码看跨 rig 能力由几个机制共同支撑追踪关系以tracks类型的依赖记录保存在 convoy 所在库中目标 ID 若跨库则包装为external:prefix:id读取 tracked issue 状态时按 ID 前缀路由到对应 rig 的存储/数据库beads.GetRigNameForPrefix本地查询不到的再经 resolver 或bd show子进程补全——这正是gt convoy status与gt convoy check能显示跨 rig 进度的原因反向查询“谁在追踪我刚关闭的 issue”则用GetDependentsWithMetadata过滤tracks类型支撑上文的事件驱动喂料。Convoy vs Rig Status两种视角ViewScopeShowsgt convoy status [id]Cross-rigIssues tracked by convoy workersgt rig status rigSingle rigAll workers in rig their convoy membershipUse convoys for whats the status of this batch of work?用 convoy 回答“这批工作的状态如何” Use rig status for whats everyone in this rig working on?用 rig status 回答“这个 rig 里大家都在忙什么”两个视角互补convoy 是以工作批次为中心的纵向视图跨 rig 追踪同一目标的进展与落地rig status 是以工作区为中心的横向视图某 rig 内全部 worker 及其 convoy 归属。延伸阅读Propulsion Principle — Worker execution modelworker 执行模型Mail Protocol — Notification delivery通知投递协议关键源码入口convoy CLI 主实现 internal/cmd/convoy.gostage/launch 命令 internal/cmd/convoy_stage.go事件驱动喂料与跨 rig 解析 internal/convoy/operations.goconvoy 元数据字段 internal/beads/fields.go。相关测试如 internal/cmd/convoy_stranded_test.go、internal/cmd/convoy_launch_test.go、internal/convoy/operations_test.go 可作为行为验证的参考。【免费下载链接】gastownGas Town - multi-agent workspace manager项目地址: https://gitcode.com/GitHub_Trending/ga/gastown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考