Block 开源多 Agent 通信平台 buzz:从拉仓库到跑通中继

2026-08-05

本文基于 buzz 仓库 commit 8342dfc(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/block/buzz 最新代码与文档为准。

你在这个仓库里遇到的安装问题,八成不出在 Rust 编译上,而出在你以为自己装的是一个 Rust 项目。 Block 开源的多 Agent 通信平台 buzz 拉下来之后,cargo build --workspace 能跑通并不代表你装好了:桌面端根本不在这个 workspace 里,工具链不在你的 ~/.cargo 里,数据库、缓存、对象存储三件套还得先在 Docker 里起来。把这三件事的边界搞清楚,装机就是三条命令;搞不清楚,你会在”编译过了但什么都跑不起来”的状态里耗掉一个下午。

站内已经写过几篇安装类文章,分工不一样:Claude Code 安装失败排查处理的是单个 CLI 工具的装不上;AI 工具选型流程解决的是装之前该不该装;Pascal Editor 安装上手是另一个前端型开源仓库的上手路径。本篇只管一件事——buzz 这种”Rust workspace 外挂多个前端、工具链走垫片”的多语言仓库,装的时候和普通 Rust 项目差在哪。

一、先弄清你要装的是什么

buzz 建在 Nostr 之上。Nostr 是一套很薄的开放消息协议,只有三个核心概念,你把它们记住就够读懂这个仓库了:

  • 事件(event):所有内容的统一载体。一条消息、一个表情回应、一次工作流执行、一条 git 补丁记录,在协议里都是同一种结构的 JSON,靠一个整数 kind 区分类型。仓库里 crates/buzz-core/src/kind.rs 就是这份 kind 号码的登记表,文件开头自己写明它是权威来源,比如频道消息是 KIND_STREAM_MESSAGE: u32 = 9
  • 签名与密钥自持:每个事件都由发布者用自己的私钥签名,接收方独立验签。crates/buzz-core/src/event.rs 里的 StoredEvent 就带一个 verified 标记,它的单元测试直接构造了一个被篡改签名的事件,断言”事件 ID 校验仍然通过、但签名校验失败”。身份就是那把私钥——CLI 侧 BUZZ_PRIVATE_KEY 是必填项,没有找回流程,丢了私钥等于丢了这个身份,这一点在你给 Agent 分配身份时要提前想清楚。
  • 中继(relay):存事件、转发事件的服务端。它不是区块链节点,就是一个带存储和订阅的服务器。buzz 的中继叫 buzz-relay,默认跑在 ws://localhost:3000

还有一个缩写你会反复撞见:NIP。它是 Nostr 生态里协议提案文档的统称,一份 NIP 规定一件事该怎么编码、怎么校验,靠编号互相引用。这里有两类,别混:一类是生态通用的数字编号——README 里 git 补丁走 NIP-34,NOSTR.md 说这个中继原生支持 NIP-29(基于中继的群组)并用 NIP-42 做客户端到中继的鉴权;另一类是 buzz 自己起草、编号用两个字母的扩展,docs/nips/ 下那 15 份就是,比如 NIP-AA.md 讲的是带 NIP-OA 主人授权凭据的 Agent 密钥怎么获得中继访问权。这些文档开头都标着 draft,也就是说它们是这个项目的提案而非既成标准。看到 NIP-xx 先分清是哪一类,能省掉不少查错方向的时间。

仓库 README 是这样定位自己的:一个人和 AI Agent 共处同一批房间的可自托管工作区,每条消息、每个表情回应、每步工作流、每次评审通过、每个 git 事件都是同一份日志里的签名事件,作者是人还是进程,形状、身份模型、审计轨迹都一样。这是项目自己的说法。README 另外用一张三栏表把功能分成”已经能用 / 正在接线 / 只有观点还没代码”三档,并在表下提醒读者先别把合规计划押在第三栏上。仓库根目录还有 8 份 VISION*.md,那些是愿景文档,不是功能清单,装机前别拿它当验收标准。

仓库结构是这样的:

组成部分它负责什么对应仓库位置你什么时候会碰到它
Rust workspace中继、CLI、Agent 接入、数据库、搜索、审计等 29 个成员crates/(28 个 crate)+ examples/countdown-botjust buildcargo build --workspace
桌面端Tauri + React 客户端,Rust 侧独立成另一个 workspacedesktop/,原生层在 desktop/src-tauri/just devjust desktop-dev
移动端Flutter 客户端(README 归在”正在接线”一栏)mobile/(含 android/ios/lib/just mobile-testjust ci
Web 与后台中继可选托管的邀请落地页、只读管理面板web/admin-web/just relay-webjust admin
工具链垫片hermit 环境,按需下载并钉住各语言工具版本bin/activate-hermithermithermit.hcl每开一个新终端
任务编排所有开发动作的唯一入口根目录 Justfile从头到尾
数据库迁移27 份 SQL,由 buzz-admin migrate 应用migrations/just setup 隐式执行
协议规范项目自定义的 NIP 草案文档docs/nips/(15 份 md + 2 份 fixtures json),另有 crates/buzz-core/src/pairing/NIP-AB.md要改事件格式或读懂配对流程时

有两个细节值得单独拎出来。一是根目录 Cargo.toml 里写着 exclude = ["desktop/src-tauri"]——桌面端的 Rust 代码被显式排除在主 workspace 之外,所以 cargo build --workspace 不会碰它,检查它要用 cargo check --manifest-path desktop/src-tauri/Cargo.toml,Justfile 里那些 desktop-tauri-* 配方就是干这个的。二是根目录同时存在 AGENTS.mdCLAUDE.md,两份都是给 AI 编码工具读的贡献指南,内容一致,只是文件名对应不同工具的约定。

二、hermit 垫片接管了工具链

bin/README.hermit.md 自己解释了这个目录是什么:一个 hermit bin 目录,里面的符号链接由 hermit 管理,会自动下载 hermit 本身以及各个包,这些包只属于当前环境。bin/hermit.hcl 里就一行 manage-git = true

激活方式是 . ./bin/activate-hermit。注意开头那个点——这个脚本必须被 source,不能直接执行,它第一行判断就是:

if [ "${BASH_SOURCE-}" = "$0" ]; then
  echo "You must source this script: \$ source $0" >&2
  exit 33
fi

直接 ./bin/activate-hermit 会以退出码 33 结束,什么都不做。这是新人第一个卡点,报错信息很清楚,但很多人习惯性地直接跑。

垫片带来的第二个变化是”版本号有两套”。rust-toolchain.toml 里钉的是:

[toolchain]
channel = "1.95.0"
profile = "default"

而根 Cargo.toml[workspace.package] 写的是 rust-version = "1.88.0",CONTRIBUTING.md 的前置条件表里也写 Rust 1.88+、Node.js 24+、pnpm 10+、Flutter 3.41+、Docker 24+。这两个数字不冲突:1.88 是这份代码声明的最低可编译版本,1.95.0 是这个仓库实际会拉下来用的版本。你本机装了 1.90 也不会”版本不够”,rustup 读到 rust-toolchain.toml 会自己去装 1.95.0。理解这个区别很重要——遇到编译差异时,先确认自己到底跑在哪个版本上。

第三个变化是下载时机。hermit 的工具是首次调用时才下载的,所以 just bootstrap 干的事情就是把它们各调一遍触发下载:

echo "Ensuring toolchain via Hermit..."
cargo --version &
node --version &
pnpm --version &
wait

同一个配方还会检查 docker 是否存在,以及在 .env 不存在时从 .env.example 复制一份。它可以随时重复执行。

第四个变化最容易被误解,我一开始也想岔了:Justfile 里确实有配方会把 bin/ 显式塞到 PATH 最前面,但只是一小部分。近百条配方里带这一句的只有十来条,而且集中在”要长跑或要拉起进程”的那几个——bootstraphooksrelayrelay-webadmindevdesktop-standalonestagingproduction,以及压测和 goose 相关的几条。你每天用得最多的 buildfmt-checkclippytest-unit 恰恰没有build 就是光秃秃一行 cargo build --workspace,用的是你当前 shell 里那个 cargo。

这条差别的实际后果是:不要以为”走 just 就安全”。忘了 source hermit 而直接 just clippy,跑的就是你系统那份 rustc;just dev 却是钉住的那份。同一个仓库、两种工具链,正是”CI 过了本地不过”这类问题最常见的来源。可靠做法只有一个——每开一个新终端先 . ./bin/activate-hermit,再谈别的。

三、setup、build、dev 三步各自在做什么

README 的”每天开工”流程只有两行,但底下的依赖链值得展开。

just setup 依赖 bootstrap,然后执行 scripts/dev-setup.sh。这个脚本先做前置检查:docker 命令在不在、docker daemon 起没起,任一不满足直接退出。然后加载 .env,并且会顺手把历史遗留的默认值改写掉——这个项目改过名,脚本里还留着把 postgres://sprout:sprout_dev@… 迁到 postgres://buzz:buzz_dev@… 的兼容逻辑,也会停掉并删除叫 sprout-postgressprout-redis 之类的旧容器,好让 buzz-* 容器能占住标准端口。这一步只动容器不动卷。

CONTRIBUTING.md 列出了 just setup 起的服务:Postgres 在 :5432、Redis 在 :6379、Adminer 在 :8082、Keycloak 在 :8180(本地 OAuth/OIDC 测试用)、MinIO 在 :9000(媒体存储)、Prometheus 在 :9090(指标)。然后跑迁移。

迁移这一步在 Justfile 里叫 _ensure-migrations,它自己又依赖 _ensure-services

_ensure-migrations: _ensure-services
    cargo run -p buzz-admin -- migrate
    ./scripts/seed-local-community.sh

_ensure-services 的判断方式是 docker inspectbuzz-postgresbuzz-redis 的健康状态,都 healthy 就直接跳过,否则 docker compose up -d 后轮询 40 次、每次间隔 3 秒,超时就报错退出。所以你会看到 just relayjust devjust admin 这些配方启动时先愣几秒——它们都挂着这条依赖,实际是在等容器健康。

just dev 除了 bootstrap_ensure-migrations,还多依赖一个 _ensure-sidecar-stubs

TARGET=$(rustc -vV | sed -n 's|host: ||p')
mkdir -p desktop/src-tauri/binaries
SIDECARS=(buzz-acp buzz-agent buzz-dev-mcp git-credential-nostr buzz)

配方注释写得很直白:Tauri 在编译期校验 externalBin,所以要先 touch 出占位文件。也就是说,桌面端把 Agent 接入器、开发用 MCP 服务、git 凭据助手、CLI 这几个二进制当作随包分发的 sidecar;你要是绕过 just 直接对 desktop/src-tauri 跑 cargo,占位文件不存在,编译期就会挂在这一步,而报错信息和你改的代码毫无关系。非 Windows 目标还会多一个 buzz-backend-kubernetes

just dev 本身在启动前还会用 lsof 依次探测三个端口——中继 3000、健康检查 8080、指标 9102——只要有一个被占,它拒绝启动并把占用进程打出来,提示你”常常是一个没退干净的 buzz-relay”。这是个好设计,省掉了”桌面端连到了上一次残留的中继”这类幽灵问题。

装完之后怎么确认真的通了?TESTING.md 给的最小序列是:生成密钥对、建频道、发消息、读回来。

GEN=$(buzz-admin generate-key)
export BUZZ_PRIVATE_KEY=$(echo "$GEN" | awk '/Secret key:/ {print $3}')

CHANNEL=$(buzz channels create --name "smoke-$$" --type stream --visibility open | jq -r '.channel_id')
SEND=$(buzz messages send --channel "$CHANNEL" --content "hello from smoke test")
buzz messages get --channel "$CHANNEL" --limit 5 | jq .

文档说明发送成功会打印 {"event_id":"…","accepted":true,"message":""}。跑通这段,说明中继、Postgres、鉴权链路、CLI 签名都是好的。

四、边界与代价

这套安装设计不是没有取舍,装之前最好知道它放弃了什么。

你装的是一整套后端,不是一个客户端。 只想试用应用的人,README 明确指路去 releases 下载打包好的 macOS/Linux/Windows 构建,或者一键部署一个托管中继;从源码构建这条路是给要改代码、要自托管的人准备的。Postgres、Redis、MinIO 少一个都跑不完整,笔记本上常驻这一套是有成本的。

本地默认配置是敞开的。 TESTING.md 里写得很清楚:中继以开发模式启动(BUZZ_REQUIRE_AUTH_TOKEN=false),启动日志会打一条 WARN 提醒你,这在本地测试是预期行为。配置表里 BUZZ_REQUIRE_RELAY_MEMBERSHIPBUZZ_REQUIRE_MEDIA_GET_AUTH 默认也都是 false。开发模式下 REST 接口允许用 X-Pubkey 头做回退鉴权。这些默认值意味着:这个中继不能直接对公网暴露。真要做单机或 VPS 部署,README 指的是 deploy/compose/ 里的生产 Compose 包(Postgres、Redis、MinIO、可选 Caddy/TLS),根目录那份 docker-compose.yml 只用于日常开发。

数据全部落在你自己这边。 事件进你自己的 Postgres,媒体进 MinIO 或 S3,审计是库里的哈希链日志(BUZZ_AUDIT_ENABLED 默认 true)。自托管的另一面就是备份、升级、权限全归你管,出问题没有别人的运维兜底。

Agent 的权限边界要自己划。 仓库里 buzz-dev-mcp 被 AGENTS.md 描述为开发者 MCP 服务,提供 shell 与文件编辑工具;README 说 Windows 上 Agent 的 shell 工具在 bash 下运行,所以需要装 Git for Windows,也可以用 BUZZ_SHELL 指到别的 bash 兼容 shell。把这两条连起来看:接进来的 Agent 有自己的密钥、自己的频道成员身份,能执行 shell 命令、能改文件。ACP 接入器的 BUZZ_ACP_RESPOND_TO 默认是 owner-only,TESTING.md 为了方便测试让你改成 anyone——那就是把门打开了,测完记得改回去。这块的通用思路可以参考给 Agent 设计最小权限Agent 工作区隔离,本文不展开。

跑完整 CI 门槛的代价不低。 just ci 的依赖链是 check + test-unit + desktop-test + desktop-build + desktop-tauri-check + desktop-tauri-test + web-build + mobile-test,其中 mobile-testflutter test。没装 Flutter,这条门槛你就跑不完。Linux 上还有一层:hermit 钉的是语言工具链不是系统库,桌面端 Rust crate 要链接 GTK 和 WebKitGTK,CONTRIBUTING.md 给了一整串 apt 包名,装不全会在 just check 中途挂在 pkg-config 报错上。只改中继或 CLI 的话,文档也给了退路——just fmt-checkjust clippyjust test-unitjust test 都不需要 GTK。

它明确不管的事。 README 的”What it is not”三条:不是区块链;不是”AI 替代人”的方案,它认为人留在回路里、Agent 留在房间里时效果最好;不是完成品。加上前面说的三栏表和 8 份愿景文档——安装文档能保证的只有”已经能用”那一栏。

五、上手与避坑清单

每条都是”为什么会踩 + 怎么避”。

1. activate-hermit 被直接执行。 会踩是因为看到可执行文件的本能反应是 ./ 跑它,而它退出码 33 且不报太多细节。避法:永远写成 . ./bin/activate-hermit,写进你的项目启动别名里;每开一个新终端都要重来一次。

2. cargo build --workspace 之后找不到桌面端。 会踩是因为根 Cargo.tomldesktop/src-tauri 排除在外,构建日志里不会有任何提示。避法:桌面端一律走 just devjust desktop-dev,要单独检查就带 --manifest-path desktop/src-tauri/Cargo.toml

3. 绕过 just 直接编译 Tauri 层,挂在 sidecar 上。 会踩是因为 Tauri 编译期就要校验 externalBin 声明的二进制存在,而那几个文件是构建产物。避法:先跑一次任何依赖 _ensure-sidecar-stubs 的配方(just desktop-tauri-check 就行)生成占位文件。

4. 端口撞车。 中继要占 3000、8080、9102 三个端口,Adminer、Keycloak、MinIO、Prometheus 又各占一个。会踩是因为你可能已经装了 Buzz Desktop,或者上一次的中继没退干净。避法:just dev 会自己预检并拒绝启动,读它打印的占用进程;手动起中继时用 TESTING.md 给的整套覆盖(BUZZ_BIND_ADDRBUZZ_HEALTH_PORTBUZZ_METRICS_PORT,以及 CLI 侧的 BUZZ_RELAY_URL)。

5. just reset 把你不想删的数据也删了。 会踩是因为 TESTING.md 点明:桌面端用的是同一批容器名 buzz-postgresbuzz-redis 和同一批默认端口,你的测试中继写的其实是桌面端那个库。避法:需要隔离就先停掉桌面端,或者按文档用 COMPOSE_PROJECT_NAME=buzz-dev docker compose … 跑一套独立的 Compose 项目。顺带一提,CONTRIBUTING.md 说 just reset 只清开发态的那份(~/.buzz-devbuzz-desktop-dev keyring、dev 版 bundle id),不碰已安装应用的 ~/.buzz

6. 环境变量从上一个会话漏过来。 会踩是因为 BUZZ_AUTH_TAGBUZZ_RELAY_URLBUZZ_PRIVATE_KEY 这类变量很容易被你写进 shell 配置或从测试环境继承,而本地开发中继对陈旧的 BUZZ_AUTH_TAG 零容忍,第一次 CLI 写操作就报 auth_error: BUZZ_AUTH_TAG verification failed … signature verification failed。避法:开工前先 unset BUZZ_AUTH_TAG BUZZ_RELAY_URL BUZZ_PRIVATE_KEY,TESTING.md 把这条单独做成了警示块。

7. RELAY_URL 没有 BUZZ_ 前缀。 会踩是因为其它变量全带前缀,你会下意识写成 BUZZ_RELAY_URL 去改中继对外通告的地址,结果改的是 CLI 的目标地址。避法:记住这条例外——RELAY_URL 是中继在 NIP-11 元数据和 NIP-42 鉴权挑战里通告出去的地址,TESTING.md 的配置表专门给它加了粗体注解。

8. CLI 收 http、ACP 接入器要 ws。 会踩是因为两者共用 BUZZ_RELAY_URL 这一个变量名,但 buzz-acp 要的是 ws://。避法:切换角色时重新 export 一遍,主机和端口保持一致。

9. Agent 启动了却装死。 会踩是因为 Agent 身份不是任何频道的成员,日志会打 discovered 0 channel(s),然后静默忽略所有 @提及。避法:用另一个身份执行 buzz channels add-member --channel "$CHANNEL" --pubkey "$AGENT_PUBKEY" --role member;文档说加完不用重启,它会收到成员变更通知并即时订阅。另外 Agent 身份必须和发消息的身份不同——即使 BUZZ_ACP_RESPOND_TO=anyone,它也会跳过自己签名的事件。

10. debug 与 release 二进制混着用。 会踩是因为 TESTING.md 让你先 cargo build --release 再把 target/release 加进 PATH,而 just setup 结束时打印的”Next steps”横幅仍然推荐 just relay(debug 构建)。文档专门加了一条”忽略这个横幅”的提示。避法:认准自己这轮用的是哪种构建,改完代码记得重新 build,否则会遇到 relay error 500 这类看起来毫无道理的错误——TESTING.md 的排错表第一行就是它,原因写的是”陈旧的二进制”。

六、装完之后先验哪几件事

一份可以照着过的自检清单:

  • . ./bin/activate-hermit 之后,cargo --version 输出的是 1.95.0,不是你系统那份;
  • docker compose psbuzz-postgresbuzz-redis 都是 healthy;
  • curl -s http://localhost:3000/health 返回 okcurl -s http://localhost:8080/_readiness 返回 {"status":"ready"}(健康与就绪探针在独立端口上,绕开鉴权中间件,主端口也顺带暴露了 /health);
  • TESTING.md 那段建频道、发消息、读回来的冒烟序列跑通;
  • just test-unit 全绿——它不需要任何基础设施。

接下来该读哪个文件,取决于你要动什么。要改协议层,从 crates/buzz-core/src/kind.rs 开始,CONTRIBUTING.md 的”How to Add a New Event Kind”把从定义常量、注册所需鉴权 scope(crates/buzz-relay/src/handlers/ingest.rs 里的 required_scope_for_kind())、挂后置副作用(crates/buzz-relay/src/handlers/side_effects.rs)到落库和测试的九步全列了。要理解系统边界读 ARCHITECTURE.md。要把 Agent 真正接进来,TESTING.md 的 ACP 章节是最短路径。想看这个项目在密码学上较真到什么程度,翻 crates/buzz-core/src/pairing/ —— 设备配对那份 NIP-AB 规范旁边放着一个 NIP-AB.spthy 文件,是给形式化验证工具用的协议模型(形式化验证指的是用数学方法穷举协议在攻击者存在时的所有可能状态,而不是靠跑测试用例撞运气),模型里连”二维码被泄露""源端会话密钥被攻陷”这样的攻击者能力都显式建了规则。

最后提醒一句:这是别人的仓库,上面所有行为都以你拉到的那份代码为准。装机文档写得再细,也会被一次重构改掉——遇到对不上的地方,Justfile 和 scripts/ 下那几个 shell 脚本永远比文档更接近事实。

本篇属于一个把开源多 Agent 通信平台 buzz逐层拆开讲的系列,整体地图见 buzz 是什么:Block 开源的多 Agent 通信平台全景图;沿着这条线往下,还可以看 Block 开源多 Agent 通信平台 buzz 的四层排障顺序buzz 命令行怎么用:Block 开源的多 Agent 通信平台上手

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。