buzz-integration-hermes
Make Hermes Buzz plugin work against local Buzz relay.
- License 许可
- MIT
- 所属仓库
- zapabob/Skills
- 最近更新
- 2026-10-26
- Stars
- ★ 2
- Forks
- 0
01 前言 Front Matter
- name
- buzz-integration-hermes
- tags
- [ "buzz", "nostr", "plugin", "integration", "relay" ]
- author
- Hermes Agent
- license
- MIT
- version
- 1.0.0
- platforms
- [ "windows", "linux", "macos" ]
- description
- Make Hermes Buzz plugin work against local Buzz relay.
03 SKILL.md 正文
"""Buzz plugin — registers toolset buzz with runtime-gated handlers.
Design:
- Pure functions returning JSON strings.
- No hard dependency on a running relay; missing prereqs surface JSON error payloads so the agent can report them faithfully.
- Docker compose shortcuts are provided for local dev when
vendor/buzzcontains a compose file. BUZZ_BINcan point at a nativebuzzCLI for channel/message/keypair tools. """
Buzz (Block/Square Nostr agent workspace) Hermes Integration
Overview
Buzz is an open-source "human + AI agent collaborative workspace" built on Nostr relays (Rust). This skill documents the minimal steps to make the Hermes plugins/buzz/ toolset actually work against a local Buzz relay.
Prerequisites
- Buzz repo cloned as submodule at
vendor/buzz/ vendor/buzz/docker-compose.yml— 開発 infra 用で relay が不足。実運用/ローカル検証はvendor/buzz/deploy/compose/compose.ymlを使う。vendor/buzz/buzz.exe— 無い場合は既存の%USERPROFILE%\.cargo\bin\buzz.EXEなど PATH 内バイナリを利用できる。plugins/buzz/tools.pyはvendor/buzz/target/release/buzz.exeも自動探索する。vendor/buzz/.env— Hermes ツールはvendor/buzz/.envを読まない。Hermes buzz ツールに渡す場合は明示的にBUZZ_BIN/BUZZ_RELAY_URLを設定するか、ツール側の.env読込を確認する。
Local Same-Machine Agent Interaction
For Hermes-to-other-AI messaging on the same host, Tailscale/Ngrok are not required. Start the relay stack locally and point BUZZ_RELAY_URL at http://localhost:3000 or the observed local relay URL. External exposure only becomes necessary when another machine must reach this relay.
Configuration
-
Start local relay stack (
vendor/buzz/deploy/compose/.envfirst, then):docker compose -f vendor/buzz/deploy/compose/compose.yml up -d # Verify container health: docker compose -f vendor/buzz/deploy/compose/compose.yml ps -
Generate Nostr private key (one-time):
python -c "import secrets; print(secrets.token_hex(32))"Add to
vendor/buzz/.env:BUZZ_PRIVATE_KEY=<64-char-hex> BUZZ_RELAY_URL=ws://localhost:3000 -
Hermes plugin config — already in
plugins/buzz/__init__.py:- Toolset:
buzz - 7 tools:
buzz_relay_status/start/stop,buzz_channel_create/list,buzz_message_send/read - Default relay fallback in
_run():http://localhost:3000
- Toolset:
-
Tailscale exposure (for tailnet access):
tailscale serve --bg --set-path /buzz --yes http://localhost:3000 # Available at https://downl.taile4f666.ts.net/buzz # Verify: curl -s https://downl.taile4f666.ts.net/buzz/health -
Bitwarden backup (one-time after key generation):
# Store BUZZ_PRIVATE_KEY in Bitwarden (item: "Buzz Nostr Private Key") # Verify: item exists, field BUZZ_PRIVATE_KEY present, no plaintext in logs/memory
CLI Argument Mapping (Critical)
The Hermes plugin must match buzz.exe's actual CLI:
| Operation | buzz.exe subcommand | Key flags |
|---|---|---|
| Channel create | channels create |
--name, `--type stream |
| Channel list | channels list |
--limit |
| Message send | messages send |
--channel <UUID>, --content <text> |
| Message read | messages get |
--channel <UUID>, --limit |
Verification Checklist
import os, json
os.environ['BUZZ_BIN'] = 'vendor/buzz/buzz.exe'
from plugins.buzz.tools import buzz_relay_status, buzz_channel_list, buzz_channel_create, buzz_message_send, buzz_message_read
# All should return auth_error (code 3) or user_error (code 1) — NOT CLI syntax errors
for fn in [buzz_relay_status, buzz_channel_list, buzz_channel_create, buzz_message_send, buzz_message_read]:
out = fn({})
data = json.loads(out)
assert data.get('code') in (1, 2, 3, 4, 5), f'CLI syntax error: {data}'
print('All tools reach relay correctly')
# Verify .env auto-loading works
from plugins.buzz.tools import _load_buzz_env
env = _load_buzz_env()
assert 'BUZZ_PRIVATE_KEY' in env, 'Key not loaded from .env'
assert env['BUZZ_PRIVATE_KEY'] == '9a844e43e2df34fac936f8a923980f55a379f6ac1505c4ae43fb2b346cd51f6f'
assert 'BUZZ_RELAY_URL' in env
print('.env auto-load verified')
Common Pitfalls
- Relay port mismatch:
vendor/buzz/deploy/compose/compose.ymlexposes 3000 for the relay HTTP/WS port. Do NOT run the relay on 8080 — on this stackllama-serveralready binds 8080, so a buzz relay on 8080 gets shadowed and every request 404s with a{"Server":"llama.cpp"}body instead of the relay's. - Wrong subcommand: old plugin used
channel create/message read— must bechannels create/messages get. - Host-authority-exact community matching (the #1 local gotcha): Buzz relay is multi-tenant; the community is bound to the authority of
RELAY_URL(afternormalize_host). Incoming requests are rejected404: no community is configured for this hostunless the requestHost/authority matches byte-for-byte. IfRELAY_URL=wss://localhost, connect with--relay http://localhost:3000— NOThttp://127.0.0.1:3000(127.0.0.1 ≠ localhost). SettingRELAY_URL=wss://host.docker.internalDOES ensure a community inside the container, but requests from the Windows host tohttp://host.docker.internal:3000still 404'd in testing — prefer plainlocalhostfor single-host local use. The relay logsDeployment community ensured host:<authority>at startup; that authority is what every client request must present. - buzz.exe global flags go BEFORE the subcommand:
buzz channels list --format compacterrors withunexpected argument '--format' found. Usebuzz --format compact --private-key <hex> --relay <url> channels list.--relay/--private-key/--auth-tag/--formatare all global options (seebuzz --help), so pass them before the subcommand. - Process env doesn't read
.env:os.environdoesn't auto-load.env. Tools must implement_load_buzz_env()to readBUZZ_PRIVATE_KEY/BUZZ_RELAY_URLfromvendor/buzz/.envat runtime. RELAY_OWNER_PUBKEYmust be 64-char hex (Nostr format), never secp compressed: deriving the pubkey with coincurve'sformat(compressed=True)yields a 66-char02…/03…string. The relay logsWARN RELAY_OWNER_PUBKEY is not a valid 64-char hex pubkey — ignoringand ownership bootstraps to the wrong key. Strip the prefix:coincurve.PrivateKey(bytes.fromhex(priv)).public_key.format(compressed=True).hex()[2:](64 chars).- Zero-filled
BUZZ_RELAY_PRIVATE_KEYrestart-loops the relay: a placeholder/zero key makes the container bounce withinvalid BUZZ_RELAY_PRIVATE_KEY: Invalid secret key(statusrestarting, never healthy). Generate withopenssl rand -hex 32(orpython -c "import secrets; print(secrets.token_hex(32))") and pair it with the matchingRELAY_OWNER_PUBKEYderived above. - User-provided nsec must be bech32-decoded with checksum stripped: when a user hands you an
nsec1...key (not raw hex), decode it via bech32 — but strip the final 6 checksum words BEFORE convertbits(5→8). Decoding the whole payload yields 36 bytes (72 hex chars) and coincurve rejects it withSecret scalar must be greater than 0 and less than .... Correct sequence:bech32_decode→data[:-6]→convertbits(5→8)→bytes().hex()→ expect exactly 64 chars. Usescripts/nsec_to_hex.py(also derives the 64-char Nostr pubkey with--pubkey, same[2:]prefix-strip rule as the owner-pubkey pitfall above). Verified 2026-08-08. - Changing
RELAY_URLre-seeds a NEW community — old channels vanish: the community is seeded fromRELAY_URL's host at startup (Deployment community ensured host:<authority>). If you changeRELAY_URL(e.g. fromws://localhost:3000to a publicwss://<ngrok-host>), the relay creates a fresh community for the new host and channels created under the old host no longer appear. Re-create channels (channels create --name ... --type stream --visibility open) against the new URL. Verified 2026-08-08: channels created onlocalhostwere invisible through the ngrok host until recreated.
Public / Hosted Relay (Block communities.buzz.xyz)
The CLI alone cannot self-register on Block's hosted relay. Live probe results:
wss://communities.buzz.xyz→ 404 (no community for that host).wss://relay.communities.buzz.xyz→ 403relay_membership_required(this is the real hosted relay endpoint).wss://buzz.xyz→ 404 (not a relay; serves HTML).
To join, membership is invite/account-gated. The buzz CLI has no invite/join/register subcommand — use a Block community invite link (e.g. https://<community>.communities.buzz.xyz/invite/...) or the web/desktop app to add your Nostr pubkey as a relay member. After membership is granted, buzz --relay wss://relay.communities.buzz.xyz ... reads/writes normally. See references/buzz-cli-public-relay.md for the full probe transcript.
When to Use
- When adding/fixing Hermes Buzz plugin tools
- When verifying local Buzz relay integration
- When exposing Buzz via Tailscale for remote agents
- When Docker Desktop reports launched but
docker infonever becomes responsive
Windows Docker Desktop Daemon Recovery (WSL-hang path)
If Docker Desktop launches but the daemon remains unreachable, the root cause is usually a hung WSL service, not Docker itself. Verified 2026-08-08 on this host:
- Confirm the hang signature:
docker infotimes out;wsl -l -valso times out (WSL hung, not Docker);wsl -d docker-desktop -e truetimes out.wsl -l -vmay list distros asStoppedwhilevmmemWSL/vmwp.exestill hold memory. - Read the logs —
%LOCALAPPDATA%\Docker\log\host\:Docker Desktop.exe.log→[E] backend exited before becoming ready/backend process exitedcom.docker.backend.exe.log/monitor.log→engine linux/wsl failed to start ... DockerDesktop/Wsl/CommandTimedOut: wsl.exe -l -v --allelectron-errd-<date>.log→ error dialog fired from backend
- Check disk free space FIRST:
cmd.exe /c "dir C:\ /a | findstr 空き". WSL2's VHDX on C: cannot expand when C: is nearly full — this host had ~10GB free and WSL distros would not start. Free temp/cache (del /q /f /s "%LOCALAPPDATA%\Temp\*",npm cache clean --force,pip cache purge) via thewindows-di[REDACTED_TOKEN]skill, then retry. - Kill the Docker Desktop process tree, then
wsl --shutdown(this may itself take 30s+; run it backgrounded with a generous timeout, it is not hung forever):cmd.exe /c "taskkill /F /IM docker-desktop.exe /T & taskkill /F /IM com.docker.backend.exe /T & taskkill /F /IM \"Docker Desktop.exe\" /T & taskkill /F /IM wslrelay.exe /T" wsl --shutdown # then re-list: wsl -l -v - Service restart needs admin:
net stop wslservice/sc config com.docker.service→Error 5: Access Deniedfrom a non-elevated shell.sc query WslServicemay show RUNNING even while WSL is functionally hung. Do not loop on these — they cannot succeed without elevation. - Only after
wsl -l -vreturns promptly relaunch Docker Desktop and polldocker infowith a bounded backoff loop, thendocker compose up. - Bash env-var trap: the
terminaltool runs MSYS bash, whereset CARGO_TARGET_DIR=...is a no-op (sets a positional parameter, not an env var). Useexport VAR=valueor inlineVAR=value cmd. A cargo build that silently ignoresCARGO_TARGET_DIRbecause ofsetlooks exactly like a toolchain failure — check this before debugging MSVC/probe errors. - Docker-free fallback is a big lift:
crates/buzz-relayrequires PostgreSQL via sqlx (workspace features arepostgres-only, no sqlite fallback) plus Redis/MinIO. A native relay without Docker means standing up Postgres+Redis on Windows — prefer fixing Docker.
External-AI Interaction Completion Rule
Declare success only after the relay is reachable from the external node and a second identity completes a send/get round trip on the same channel. A running local stack alone is not sufficient proof of cross-AI communication.
Subcommand Drift Guard
buzz.exe CLI surface changes across releases. If channel/message tools fail with unrecognized subcommand, patch plugins/buzz/tools.py to match the installed buzz.exe --help exactly.
Exact Authority, Scheme, and E2E Rules
Buzz tenancy resolves from the request authority, including a non-default port. Keep BUZZ_DOMAIN, RELAY_URL, BUZZ_MEDIA_BASE_URL, BUZZ_MEDIA_SERVER_DOMAIN, and BUZZ_CORS_ORIGINS on the same hostname:port; never mix localhost, host.docker.internal, a Tailscale IP, and a MagicDNS hostname. For a non-TLS local/Tailscale relay, use RELAY_URL=ws://<authority> on the relay and BUZZ_RELAY_URL=http://<authority> for the CLI. Using wss:// against a plain HTTP Docker port causes NIP-98 URL mismatch or TLS errors.
The relay stack is vendor/buzz/deploy/compose/compose.yml. Plugin helpers should resolve paths from the repository root, detect both compose.yml and docker-compose.yml, and use a stable compose project name so status checks inspect the intended stack. The native CLI does not load dotenv files; load only BUZZ_RELAY_URL and BUZZ_PRIVATE_KEY from ignored local dotenv files, never print them, and rotate any key exposed in logs or conversation history.
The current CLI surface is plural: channels list, channels create --name <NAME> --type stream --visibility open, messages send --channel <UUID> --content <TEXT>, and messages get --channel <UUID> --limit <N>. Global flags such as --format, --private-key, and --relay precede the subcommand. Do not use obsolete singular message or nonexistent keypair subcommands.
Verify the real integration through the Hermes handlers in this order: buzz_relay_status → buzz_channel_list → buzz_channel_create → buzz_message_send → buzz_message_read. A successful self-send proves local/Tailscale relay CRUD, but not multi-agent exchange; only claim agent-to-agent communication after a second identity on another node joins the same channel and completes a send/get round trip. Hosted wss://relay.communities.buzz.xyz returning 403 relay_membership_required is an invite/account membership issue, not a CLI syntax failure. See references/local-relay-exact-authority-and-e2e.md for the reusable runbook.
Skill Update Hygiene
This skill governs relay integration; do not create narrow one-off skills like "buzz-relay-on-<date>" for environment fixes. Capture durable class-level lessons here or in references/, and only escalate to a new umbrella skill when the topic outgrows this relay/integration scope.
References
references/local-relay-community-binding.md— localhost vshost.docker.internalcommunity-binding wall, verified working.env, exact-authority connect rule, and the 8080/llama-server shadowing trap.references/local-relay-same-host.md— same-host agent interaction without Tailscale/Ngrok, verified local binary resolution and plugin wiring state.references/buzz-cli-public-relay.md— probe results for Block's hosted relay (wss://relay.communities.buzz.xyz= 403 membership_required), the no-join-subcommand limitation, and the global-flag-before-subcommand ordering rule.references/public-relay-ngrok-e2e.md— full ngrok exposure runbook: RELAY_URL→community reseeding, 64-hex owner pubkey derivation, second-identity send/get round trip (verified 2026-08-08).scripts/nsec_to_hex.py— decode a user-providednsec1...to 64-char hex (with--pubkeyfor the Nostr pubkey); encodes the mandatory checksum-strip before convertbits.
Related Skills
hermes-plugin-development— general plugin authoringtailscale-serve-config— tailnet service exposure
04 同仓库更多 Skills
xurl
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
writing-plans
Write implementation plans: bite-sized tasks, paths, code.
whisper
OpenAI's general-purpose speech recognition model. Supports 99 languages, transcription, translation to English, and language identification. Six model sizes from tiny (39M params) to large (1550M params). Use for speech-to-text, podcast transcription, or multilingual audio processing. Best for robust, multilingual ASR.
weights-and-biases
W&B: log ML experiments, sweeps, model registry, dashboards.
watchers
Poll RSS, JSON APIs, and GitHub with watermark dedup.
serving-llms-vllm
vLLM: high-throughput LLM serving, OpenAI API, quantization.