Goose Buzz 自动化实战:用 Nostr 社区串联 GitHub Issue 的完整工具链
【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/goose
导读
本文讲解 goose 仓库中buzz/自动化工具集:它以独立 Nostr 服务身份Github Manager为核心,将aaif-goose/goose的 GitHub Issue 与公共 Buzz 社区(buzz.gdk.so)中的频道、成员和议题讨论实时打通。读完本文,你将掌握create_github_manager、create_issue_channel、list_issue_work、syncissues等脚本的完整用法、底层实现逻辑,以及如何用 Goose 的 recipe 和run_hourly把"Issue 分派 → 建频道 → 同步状态"的整条 Inbox 工作流自动化。
一、这套自动化解决什么问题
Goose 的开源协作中,GitHub Issue(编号、指派、项目阶段)与 Buzz 社区频道(讨论串、成员、角色)是两套分离的系统。buzz/目录中的工具把它们桥接起来,覆盖四个日常动作:
- 建频道:为每个 Issue 创建永久的公开 stream 频道,挂上初始主题并拉入相关人员;
- 列工作:找出尚未指派负责人、尚未建立频道的 Inbox Issue;
- 同步状态:把 GitHub 项目的阶段(Phase)与指派者实时镜像到 Buzz 频道主题;
- 自动分派:由 Goose recipe 读取列表、按兴趣和能力自动指派,再建频道、跑同步。
所有工具都以两个独立身份协作(见 buzz/README.md):
- Github Manager:一个服务身份,脚本用它持有 Nostr 密钥来创建和管理 Issue 频道、添加成员、发布 Issue 摘要、同步频道主题;
- 受管机器人(当前是Doose):一个代理身份,由 Buzz Desktop 运行,仅在 Github Manager 显式提及它时审阅 Issue。
Github Manager 是它所建频道的 owner;与此同时,代码库内检入的 core team 成员也会被加入频道,方便人们在 Buzz Desktop 中发现与管理这些频道。值得注意,这套身份模型并非特例——Goose 仓库本身把buzz/下的工具与 AGENTS.md、Justfile 等一起纳入了自动化守则。
二、环境要求与可配置项
官方依赖如下(引用自 buzz/README.md):
- Node.js;
- GitHub CLI(
gh),需已认证且能访问仓库及其 project board,recipe 场景还要求有指派 Issue 的权限; - macOS 上的 Buzz Desktop,或位于
PATH上的buzzCLI; - 配置好模型提供方的 Goose CLI;
- 一个正在运行的公开 Buzz 社区。
几个关键环境变量在源码中均有对应实现:
| 环境变量 | 作用 | 默认值 |
|---|---|---|
BUZZ_RELAY_URL | 目标 Buzz 社区的 relay 地址 | https://buzz.gdk.so |
BUZZ_BIN | 覆盖 buzz CLI 的发现路径 | 先探测/Applications/Buzz.app/Contents/MacOS/buzz,再退回PATH中的buzz |
GH_BIN | 覆盖gh命令 | gh |
GOOSE_BUZZ_HOME | 身份与状态文件根目录 | $XDG_CONFIG_HOME/goose/buzz或~/.config/goose/buzz |
BUZZ_CORE_TEAM_FILE | 覆盖核心团队花名册文件 | 各脚本同目录下的core-team.json |
从 create_github_manager、create_issue_channel、list_issue_work、syncissues 的源码可见,CLI 发现逻辑完全一致:
BUZZ_BIN优先,其次尝试 macOS 上 Bundled 的 Buzz 可执行文件,最后才依赖PATH。
README 特别提醒:社区与 Issue 频道都是公开的;依赖这些脚本前,请确认新建的 Nostr 身份可以加入社区——Buzz 各版本的 relay 配置名有变化,应使用所部署版本提供的控制项,而不是照抄旧版的 allowlist 环境变量。
三、新装步骤:从零把一台机器变成 Issue 管家
1. 创建 Github Manager 身份
在仓库根目录运行:
./buzz/create_github_manager该脚本执行四件事(源码见 create_github_manager):
- 用
node:crypto的createECDH("secp256k1")生成专用 Nostr 密钥对(通过randomBytes(32)生成私钥后计算压缩公钥,源码中的bech32Encode函数自行实现了 bech32 编码); - 把密钥存放在仓库之外;
- 上传头像 assets/GithubManager.png;
- 发布名为
Github Manager的 Buzz 资料(调用buzz --relay <url> users set-profile)。
身份存放在$GOOSE_BUZZ_HOME/github-manager(默认~/.config/goose/buzz/github-manager),身份目录权限为0700,内部文件均为0600,关键的四个文件是:
private-key.nsec 脚本使用的秘密密钥 public-key.npub 可分享的 Nostr 公钥 public-key.hex 给 Buzz CLI 用的公钥 profile-created 资料发布时间标记从源码看,脚本被刻意设计为幂等:
- 三个密钥文件与
profile-created标记齐备 → 仅修正权限,其余不做改动; - 密钥存在但标记缺失 → 重新发布资料,不替换身份;
- 密钥对不完整 → 直接退出,绝不静默替换身份。
请把整个github-manager目录备份进安全的密码/密钥管理器。私钥无法从 Buzz 找回,任何持有它的人都能以 Github Manager 身份行事。
2. 创建并运行一个受管机器人
在 Buzz Desktop 中创建至少一个受管 agent(如Doose)。机器人必须持有自己的 Nostr 身份,禁止复用 Github Manager 的密钥。启动 agent 并确认它显示为在线即可。
注意:建频道脚本会把机器人加入新频道,但成员身份本身并不能让 Github Manager 指挥它——Buzz agent 默认只接受其人类所有者的指令。
3. 授权 Github Manager 指挥机器人
在 Buzz Desktop 中操作:
- 打开Agents;
- 选中机器人(如Doose);
- 选择Edit agent;
- 展开Advanced;
- 将Who can send instructions改为Selected people;
- 搜索Github Manager并Add;
- 保存 agent,若 Buzz 未自动重启则手动重启。
这是一项安全敏感权限:被选中的身份可以指挥该 agent 使用其可访问的计算机、文件、账户与已连接工具。请保持名单精简,不要因为社区本身公开就选Anyone。
验证权限时,以 Github Manager 身份发送一条同时包含可读 mention 文本与机器人公钥的消息:
export BUZZ_PRIVATE_KEY="$(cat ~/.config/goose/buzz/github-manager/private-key.nsec)" export BUZZ_RELAY_URL=https://buzz.gdk.so BUZZ_CLI="${BUZZ_BIN:-/Applications/Buzz.app/Contents/MacOS/buzz}" "$BUZZ_CLI" messages send \ --channel <channel-uuid> \ --content "@Doose reply with OK" \ --mention <doose-public-key-hex>README 与源码一致地强调:不带--mention公钥的纯文本@Doose很可能只被渲染成文字,并不会唤醒远程 agent。成功的命令会在返回的mention_pubkeys中出现机器人公钥;机器人可能需要一两分钟才会响应。
4. 配置核心团队
core-team.json定义了每个新建 Issue 频道都会加入的人。每个人的结构由共享模块 github_manager.mjs 中的readCoreTeam严格校验:必须包含显示名、GitHub 账号、稳定的 Buzz 公钥(64 位十六进制)、大于 0 的capacity与非空的interest兴趣列表;可选bots字段把"机器人显示名 → 机器人公钥"映射起来,添加该人时会同时把这些身份以 Buzz 的bot角色加入频道。所有 GitHub 账号与公钥在文件内都必须唯一,重复会直接报错。
检入的当前名册(见 core-team.json):
- Douwe Osinga(owner),其 bot 为Doose;
- Alex Hancock、filip、jasper、Mic、lifei、Jack Amadeo(member),其中 lifei 带 botLifei goose agent。
每个成员的interest列表中都可以看到与其日常公开 Issue/PR 工作一致的领域描述;capacity定义该成员在新分派中的目标份额——大多数人是1,而 filip 是0.5(源码中校验capacity必须为正的有限数值)。
当长期团队成员变化时,直接编辑检入的 core-team.json。其它安装如需不同名册,可设BUZZ_CORE_TEAM_FILE;对一次性、不需要标准人员的频道使用--no-core-team。注意:若文件中的某人在命令行又通过--owner或--person显式指定,其关联 bot 仍会被带上。
四、工具箱逐一拆解
create_issue_channel:为 Issue 建永久频道
它读取一个 GitHub Issue,创建一个永久开放的 stream,把初始主题设为⚪ GitHub phase: Inbox,添加 owners、people、bots,并发布带 Issue 链接的摘要消息。它绝不修改 GitHub Issue 本身。基本用法:
./buzz/create_issue_channel 12345 \ --summary "Why the issue matters and what needs to be decided." \ --person "Issue Reporter"由 create_issue_channel 源码解析出的完整参数:
| 参数 | 说明 |
|---|---|
<issue-number-or-url> | 必填。数字按--repo(默认aaif-goose/goose)解析;完整 GitHub Issue URL 亦可,脚本从 URL 提取仓库 |
--summary <text> | 必填(--summary与--summary-file二选一),作为频道首条消息的正文 |
--summary-file <path\|-> | 从文件或多行 stdin(-)读取摘要 |
--repo <owner/repo> | Issue 数字对应的仓库 |
--owner/--person/--bot | 可重复。值可以是精确的 Buzz 显示名或 64 位十六进制公钥,分别获得owner/member/bot角色 |
--no-core-team | 不加入 core team 默认人员 |
--channel-limit <number> | 重复搜索的最大结果数(默认 1000) |
-h, --help | 帮助 |
底层行为都可在源码中找到对应实现:
- 频道名是
#<issue号> <截断的标题>,总长被截断到 100 字符(truncate函数会在末尾加…); - 频道描述写入
Discussion for <repo>#<号>: <url>,这正是syncissues后续回匹配 Issue 的锚点; - 首条消息是 Markdown 格式:
## 标题+ 摘要 +View the issue on GitHub; - 命令行传入的名字解析为公钥时,调用
buzz users get --name,要求精确匹配显示名;匹配不到或重名都会失败并建议改传公钥; - 同一个公钥若被同时指定为不同角色,
rejectRoleConflicts会直接失败; - 用
--repo owner/repo处理其它仓库,GitHub Issue 全 URL 同样可用;多行摘要用--summary-file。
脚本会把 issue、channel、message、参与人详情以 JSON 打印。遇到重复时:已有活跃或归档频道匹配该 Issue 号,则拒绝再建一个;对已存在的频道,只增量添加显式给出的 owners/people/bots,不会重复发摘要;归档的匹配频道会先 unarchive 再更新名册。若新频道创建过程中途失败,脚本会删除这个不完整频道,以便下次运行重试。
添加 bot 并不会触发它。频道建成后,Github Manager 必须再发一条显式 mention 新消息:
"${BUZZ_BIN:-/Applications/Buzz.app/Contents/MacOS/buzz}" messages send \ --channel <channel-uuid> \ --content "@Doose review this issue and post your assessment in this channel." \ --mention <doose-public-key-hex>在频道匹配逻辑上,三个脚本共用 github_manager.mjs 的issueReferenceFromChannel、channelMatchesIssue与bestMatchingIssueChannels:频道引用按可信度排名——显式 GitHub URL(写在频道描述中)> legacy 命名owner/repo #号> 纯数字名,拉取请求频道(kind === "pull-request")会被主动排除。这套规则由 github_manager.test.mjs 的测试覆盖,例如"匹配新旧频道""显式引用优先于纯数字名""不收养 PR 频道"。
list_issue_work:盘点待办 Issue 与候选人
它列出两类工作:项目 Inbox 中需要 owner 或频道的 Issue,以及 Buzzissues to add频道中关联的开放 Issue。被指派但无频道的 Inbox Issue 也会列出,以支持重试失败的频道创建。队列条目可以是一条 Goose Issue/PR URL,也可以只是#<Issue 号>;已有 Issue 频道的队列条目视为已处理。PR 链接在 GitHub 恰好报告一个 closing issue 时解析为对应 Issue。
输出 JSON 还包含 core team、GitHub 账号、Buzz 公钥、兴趣与分派容量,供 Goose recipe 挑选 owner;recent_assignment_load统计最近 100 个新建 Issue(含已关闭的)中 core team 被指派者的出现次数,阶段与 Issue 年龄不影响计数。list_issue_work不改变GitHub 或 Buzz 的任何内容。
./buzz/list_issue_work其参数(源码见 list_issue_work)包括--repo、--project-owner、--project-number、--project-limit、--channel-limit、--queue-channel、--queue-count、--message-limit。项目默认是aaif-goose的 project 1;其它安装用这些参数切换。
健壮性设计值得注意:项目/频道/消息触到上限时命令直接失败而不是返回残缺列表(github_manager.mjs 的getProjectIssues会重试一次分页变化并核对 totalCount);无法解析的队列链接单独报告而非猜测;新安装必须先用配置好的队列名建一个 Buzz 频道再跑 recipe。队列只考虑最近的 20 条 Issue/PR 链接,纯聊天不占该额度,可用--queue-count调整;更老的链接标为outside-recent-window,无有效时间戳的消息标为invalid-created-at。队列作者只有在公钥存在于 core-team 时才会作为queue_requesters返回,其余作者记为ignored_queue_requesters,无法影响频道成员构成。
syncissues:双向状态同步 + 外向评论通知
它拉取全部开放 GitHub Issue 与全部 Buzz 频道,按频道描述里的 GitHub URL 匹配 Issue 频道,再把项目阶段与指派者同步到频道主题。活跃与归档频道使用同一套匹配规则;legacy 纯数字频道会对照 GitHub 核查,使 PR 频道被报告并跳过而不是误当作已关闭 Issue。当多个名字指向同一 Issue 时,频道描述中的显式 GitHub URL 胜过 legacy 或纯数字名。
阶段 → 主题标记的映射在 syncissues 源码中即为常量phaseMarkers:
| GitHub 阶段 | Buzz 主题标记 |
|---|---|
| Inbox | ⚪ |
| Needs info | 🟡 |
| Accepted / design | 🟣 |
| Ready | 🟢 |
| Verification | 🔵 |
| Done | ✅ |
主题格式为:
🟢 Ready -- assigned to: @github-handle多个指派者用逗号分隔;无人指派则写assigned to: unassigned。没有对应开放 Issue 的 Issue 频道会得到✅ GitHub issue: Closed主题并被归档;若 Issue 重新开放,频道即使没有项目状态也会被 unarchive,可恢复时项目阶段一并还原。其它无关 Buzz 频道一律忽略。
外向评论通知是更细的功能:syncissues检查仓库外部人员的新回复。GitHub 作者关联为OWNER、MEMBER、COLLABORATOR视为内部人员,其它人类用户视为外人。对每条发生在开放 Issue 匹配频道上的新外人回复,Github Manager 会 mention 该 Issue 的 core team 指派者,并发布作者名与指向 GitHub 评论的链接。评论正文刻意不被复制进 Buzz,因此评论文本无法注入 mention 或机器人指令。
Snooze 状态同步自 GitHub 项目的Snoozed until日期:日期到达时,Github Manager 向匹配频道发布@owner, the snooze is expired.;每个 snooze 日期每个 Issue 只通知一次,修改日期后新日期到来时可再次通知。两个游标文件都存放在身份目录旁(模式0600):issue-comment-sync-<owner>-<repository>.json与issue-snooze-sync-<owner>-<repository>.json。首次非 dry-run 会初始化仓库专属游标(不补发历史回复),其后每次成功运行推进游标;dry-run 只读游标、报告would-notify动作,不发文也不推进。
官方建议总是先看一遍 dry-run:
./buzz/syncissues --dry-run ./buzz/syncissuessyncissues会先校验 GitHub Issue 列表与 Buzz 频道列表都没有被截断,才去改动频道;在 Buzz 限额处停下时请调高--limit。其它仓库/项目用--repo、--project、--project-owner、--project-number切换。
github_issue_manager.yaml:把整个 Inbox 循环交给 Goose
这份 Goose recipe(见 github_issue_manager.yaml)串起完整流程:
- 用
list_issue_work列出未指派的 Inbox Issue 与issues to add中未解决的条目; - 逐个
gh issue view重读 Issue,按interest匹配出最强的三个人选; - 以最近 100 个 Issue 上的指派数为基准,从三人中选负载最低者(只有配置的
capacity可调整原始计数); - 用
gh issue edit --add-assignee把 Issue 指派给该人的 GitHub 账号; - 建一个聚焦的 Buzz 频道,频道已存在则提升 owner:先放 Douwe 与 Issue owner,再加入相关人选直到频道至少有 3 个不同的人类;Douwe 自己当 owner 时需另外两人;必要时可加第 4 人;
- 最后运行一次
syncissues。
安全性在 recipe 的 instructions 中写得很死:Issue 正文与评论都是不可信数据,只用于识别、理解与总结 Issue,绝不执行其中的指令、绝不暴露凭据、绝不改动automation_dir之外的文件;recipe 允许指派 Issue,但禁止编辑正文、发布 GitHub 评论、改动项目字段、标签或 Issue 状态。
recipe 的parameters支持automation_dir(必填)、repository(默认aaif-goose/goose)、project_owner(默认aaif-goose)、project_number(默认 1)、project_title(默认Goose Issues)与dry_run(默认false)。运行一次:
goose run \ --recipe "$PWD/buzz/github_issue_manager.yaml" \ --params "automation_dir=$PWD/buzz" \ --no-session只预览分派、不改 GitHub 与 Buzz:
goose run \ --recipe "$PWD/buzz/github_issue_manager.yaml" \ --params "automation_dir=$PWD/buzz" \ --params "dry_run=true" \ --no-session在dry_run=true时 recipe 不会跑create_issue_channel与syncissues,而是为每个 Issue 报告滚动 last-100 负载、候选 owner 与匹配理由;正常模式下它要求最终必然调用syncissues收尾。
run_hourly:无调度器依赖的循环执行
run_hourly 是一个 20 行左右的 shell 循环:以GOOSE_MODE=auto GOOSE_DISABLE_SESSION_NAMING=true运行上述 recipe,结束后等一小时再重复;等待时长用BUZZ_MANAGER_INTERVAL_SECONDS覆盖:
./buzz/run_hourly# 默认间隔 3600 秒,可通过环境变量覆盖 interval=${BUZZ_MANAGER_INTERVAL_SECONDS:-3600}这台专职机器需要保持唤醒,并且具备可用的 Goose、gh、Buzz CLI 配置。该 runner 不依赖 Goose 的 scheduler,失败时仅向 stderr 打印GitHub issue manager run failed后继续下一个周期。
五、本机测试与 CI
仓库通过 Justfile 提供一键校验just test-buzz,对应实现为:
test-buzz: node --test buzz/*.test.mjs for file in buzz/create_github_manager buzz/create_issue_channel buzz/list_issue_work buzz/syncissues buzz/github_manager.mjs; do node --check "$file"; done即:先运行buzz/*.test.mjs中的 Node 测试,再对四个可执行脚本与共享模块做语法检查(node --check)。当 Buzz 自动化有改动时,同样的检查会在 GitHub Actions 中运行。现有 github_manager.test.mjs 覆盖了 10 个核心用例,包括:新旧频道匹配、跨仓库显式引用不误配、legacy 频道解析、显式引用优先、拒绝 PR 频道、畸形与延迟队列条目报告、分页变更时的重试、仓库名大小写不敏感匹配、REST 分页结果归一化(排除 PR),以及一份完整 core-team 结构校验。
六、迁移与故障恢复
把 Github Manager 迁到另一台机器,只需通过可信加密通道完整拷贝身份目录,它会一并带走 manager 密钥与两个同步游标,且不会复制任何人类或机器人身份:
~/.config/goose/buzz/github-manager在目标机器上把目录保持为0700、文件为0600,再运行一次create_github_manager确认它能识别该身份;同时安装并认证gh、安装配置 Goose、安装 Buzz Desktop 或配置BUZZ_BIN。
两个常见误区(README 原话提醒):
- 不要拷贝 Buzz Desktop 的应用数据目录——小时级工作流只需要 Github Manager 的密钥;Doose 可以继续跑在原机器上,也可以在专职机器上另建独立 bot 身份;
- 用空身份目录运行
create_github_manager生成的是新身份,不是旧身份的副本。
若旧私钥彻底丢失,按以下顺序恢复:
- 生成新的 Github Manager 身份;
- 把新身份加为仍需管理频道的 owner;
- 在每个机器人的Selected people列表中,把旧的 Github Manager 替换为新条目;
- 尽可能移除旧身份;
- 安全备份新密钥。
注意:既有频道事件仍由旧身份签名,无法被新身份重签——这也是"密钥即身份、密钥即权限"这一设计下必须及时清理旧条目的原因。
结语
buzz/是 Goose 项目"用自己做的 Agent 管理自己的社区"的一个落地样例:它以不可信数据为默认假设、以最小权限为边界,把 GitHub 项目管理与 Nostr/Buzz 社区讨论缝合进一条可无人值守的自动化流水线。想要复用这套方案,只需照本文完成四个步骤——创建服务身份、注册受管机器人、收紧"谁能指挥"权限、配置 core team 名册——再以github_issue_manager.yaml为模板,替换仓库、项目与队列参数即可跑通自己的 Inbox 闭环。
【免费下载链接】goosean open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM项目地址: https://gitcode.com/GitHub_Trending/goose3/goose
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考