Files
itpp-infrastructure/projects/buzz-agent-integration-spec.md

588 lines
32 KiB
Markdown

# Server-Side Agent Integration with Buzz
**Status:** Speculative / Research
**Date:** 2026-08-07
**Author:** Sho'Nuff
**Relay:** `wss://buzz.iamgmb.com` (app3, Docker Compose)
## Executive Summary
Buzz's native agent integration model (`buzz-acp`) is **desktop-centric**: it spawns ACP-compliant agent binaries as local subprocesses via stdio. Hermes is server-side (Core VPS) and cannot be spawned as a local binary on a user's laptop. This spec evaluates four integration paths to make Hermes a first-class participant in Buzz channels — able to receive @mentions and post replies — and recommends a Nostr-native WebSocket client approach modeled after the proven OpenClaw Buzz plugin.
---
## 1. ACP Protocol Research
### 1.1 What is ACP?
The **Agent Client Protocol (ACP)** is an open standard hosted at [agentclientprotocol.com](https://agentclientprotocol.com/), governed by a spec repo at [github.com/agentclientprotocol/agent-client-protocol](https://github.com/agentclientprotocol/agent-client-protocol). It is modeled after LSP (Language Server Protocol) and standardizes communication between code editors/IDEs and AI coding agents.
**Protocol fundamentals:**
- **Wire format:** JSON-RPC 2.0 over stdio (primary transport today)
- **Roles:** Client (editor/IDE/harness) ↔ Agent (AI coding tool)
- **Lifecycle:** `initialize``session/new``session/prompt``session/update` (streaming) → `StopReason`
- **Concepts:** Sessions, tool calls, cancellation, context window updates, authentication
- **Rust crate:** [`acp-sdk`](https://crates.io/crates/acp-sdk) provides typed wire messages
**Key ACP methods:**
| Method | Direction | Purpose |
|--------|-----------|---------|
| `initialize` | Client → Agent | Handshake, negotiate protocol version + capabilities |
| `session/new` | Client → Agent | Create session, pass cwd + MCP server configs |
| `session/prompt` | Client → Agent | Send user prompt, agent loops LLM + tool calls |
| `session/cancel` | Client → Agent | Cancel ongoing session |
| `session/close` | Client → Agent | Close session, free resources |
| `session/update` | Agent → Client | Streaming updates: tool calls, text chunks, usage |
| `authenticate` | Client → Agent | Auth before session creation |
**AGENT NOTIFICATION — `buzz-agent` implementation:**
- Single binary, ACP-compliant. Speaks MCP to tools (stdio only, no HTTP MCP).
- Up to 8 concurrent sessions per process.
- Non-streaming HTTP POST to LLM providers (Anthropic, OpenAI, OpenRouter).
- Not persistent (in-memory per process), no `session/load`.
### 1.2 Remote Transport Status
**ACP remote transports are in active development but NOT shipped yet:**
- An RFD (Request for Discussion) exists at [agentclientprotocol.com/rfds/streamable-http-websocket-transport](https://agentclientprotocol.com/rfds/streamable-http-websocket-transport)
- A **Transports Working Group** has been formed, co-led by Block/Goose and JetBrains
- The RFD proposes:
- **Streamable HTTP** (HTTP/2, long-lived GET streams, `Acp-Connection-Id` + `Acp-Session-Id` headers)
- **WebSocket** (`GET /acp` with `Upgrade: websocket` header)
- Unified `/acp` endpoint routing
- This is an RFD, not implemented. No timeline published.
**Current reality:** ACP is stdio-only for production use. Remote agents are a documented goal, not a working feature.
### 1.3 How Buzz Uses ACP
Buzz's agent harness is **`buzz-acp`** — a Rust binary that bridges the Buzz relay to AI agents:
```
┌──────────────┐ WebSocket ┌──────────┐ stdio ACP ┌───────────────┐
│ Buzz Relay │ ◄────────────────► │ buzz-acp │ ◄───────────────► │ Agent Binary │
│ (Nostr) │ (NIP-01 events) │ (harness)│ (JSON-RPC 2.0) │ (goose,codex, │
└──────────────┘ └──────────┘ │ claude-code) │
└───────────────┘
```
**How `buzz-acp` works (from `.env.example` + source analysis):**
1. **Connects to relay** via WebSocket using `BUZZ_PRIVATE_KEY` (Nostr keypair, NIP-42/98 auth)
2. **Subscribes to events** where the agent's pubkey appears in `p` tags (i.e., @mentions)
- `BUZZ_ACP_SUBSCRIBE=mentions` (default) — subscribe only to events mentioning agent
- `BUZZ_ACP_SUBSCRIBE=all` — subscribe to all channel events
- `BUZZ_ACP_SUBSCRIBE=config` — rule-based via TOML config file
3. **Spawns agent binary** as subprocess (Goose, Codex, Claude Code, or any ACP agent)
- `BUZZ_ACP_AGENT_COMMAND` / `BUZZ_ACP_AGENT_ARGS`
4. **Forwards prompts** to agent via ACP `session/prompt`, streams results back to relay
5. **Manages presence** (kind 20001 online/offline), typing indicators (kind 20002), dedup
**Key insight:** `buzz-acp` itself IS the WebSocket-to-stdio bridge. It doesn't expose a remote API — it IS the client that connects to the relay and spawns agents. There is **no existing `buzz-acp` HTTP API** to connect remote agents to.
### 1.4 The @mention Mechanism
In Buzz/Nostr, "mentioning" an agent means including its Nostr pubkey as a `p` tag in a channel message event. The relay's subscription registry fans out matching events to all subscribed WebSocket clients. `buzz-acp` subscribes with a filter like `{"#p": [agent_pubkey]}` and receives all events that tag that pubkey. There is **no special server-side routing** — it's standard Nostr subscription fan-out.
---
## 2. Integration Architecture Options
### 2.1 Option A: Bridge Agent (Stdio ACP Proxy)
Deploy a lightweight binary on Core (or app3) that:
1. Implements the ACP client side (speaks JSON-RPC 2.0 over stdio to a dummy agent)
2. OR implements the ACP agent side (so `buzz-acp` can spawn it) that proxies to Hermes
```
┌──────────┐ WS ┌──────────┐ stdio ACP ┌──────────────┐ HTTP/WS ┌──────────┐
│ Relay │◄─────►│ buzz-acp │◄──────────►│ Bridge Binary │◄────────►│ Hermes │
└──────────┘ └──────────┘ └──────────────┘ └──────────┘
(runs on Core)
```
**How it works:**
- `buzz-acp` spawns the bridge binary as an ACP agent subprocess
- Bridge binary receives ACP `session/prompt` containing the user's message
- Bridge forwards it to Hermes via REST API or WebSocket
- Hermes processes, returns response
- Bridge sends response back through ACP `session/update` notifications
**Pros:**
- Uses Buzz's native agent machinery (presence, typing, turn lifecycle)
- Agent appears in Buzz Desktop's agent panel naturally
- Gets @mention routing for free via `buzz-acp`
**Cons:**
- `buzz-acp` must run on a machine that can reach Hermes (not a laptop — would need to run on Core or app3)
- Stdio bridge is fragile (subprocess lifecycle, crash recovery, binary distribution)
- ACP is designed for local coding agents, not remote conversational agents — impedance mismatch
- Bridge must implement full ACP agent spec (initialize, sessions, tool calls, cancellation)
- `buzz-acp` is a desktop-side component — running it headless on a VPS is an off-label use
- Requires compiling and maintaining a Rust binary (ACP SDK crate)
**Effort:** High. Requires implementing an ACP-compliant agent from scratch.
### 2.2 Option B: Nostr-Native WebSocket Client (RECOMMENDED)
Hermes connects directly to the Buzz relay as a Nostr WebSocket client with its own keypair — exactly how `buzz-acp` and the Buzz Desktop app connect.
```
┌──────────┐ WebSocket (NIP-01/42/98) ┌──────────┐
│ Relay │◄─────────────────────────────────────►│ Hermes │
└──────────┘ Signed Nostr events (kind 9) └──────────┘
@mentions via p-tag subscriptions
```
**How it works:**
1. Hermes generates or is assigned a Nostr keypair (pubkey = Buzz identity)
2. Hermes connects to `wss://buzz.iamgmb.com` via WebSocket
3. Hermes authenticates via NIP-42 (signed AUTH challenge) or NIP-98 (HTTP auth)
4. Hermes subscribes to events with `{"#p": [hermes_pubkey]}` — receives all @mentions
5. When a mention arrives, Hermes routes it to its AI pipeline, generates a response
6. Hermes publishes a signed Nostr event (kind 9 or 40002) back to the same channel
7. Hermes manages presence (kind 20001) and typing indicators (kind 20002)
**Proof of concept: OpenClaw Buzz Plugin**
[OpenClaw's Buzz channel plugin](https://docs.openclaw.ai/channels/buzz) does exactly this. It connects an OpenClaw gateway (server-side agent platform) to Buzz as a Nostr client. Key details from their docs:
- Connects to relay via WebSocket with a dedicated Nostr keypair
- Bot identity must be added to rooms with **Bot** role via `buzz channels add-member --role bot`
- Subscribes to room events, handles kind 9 (normal messages), kind 40002 (rich-content), kind 40008 (structured diffs)
- Publishes presence every 30 seconds
- Sends typing indicators (kind 20002) while processing
- Supports NIP-27 native mentions in replies
- Handles reconnection, dedup, and stale session recovery
- One identity can serve many rooms
**Pros:**
- **Architecturally correct** — Buzz IS a Nostr relay. Connecting as a Nostr client is the first-class path.
- No desktop dependency — runs entirely server-side
- Proven pattern (OpenClaw already does this successfully)
- Hermes gets full Buzz citizenship: presence, typing, reactions, profile, DMs
- Uses standard protocols: WebSocket + JSON (NIP-01), Schnorr signatures
- No ACP impedance mismatch — Hermes processes messages its own way
- Can be implemented in Python (websockets + nostr-py or `secp256k1` bindings)
- Coexists with other agents — Hermes is just another pubkey in the channel
- Reuses Hermes's existing AI pipeline, tools, and skills
**Cons:**
- Must implement Nostr protocol handling (event signing, subscription management, NIP-42 auth)
- Does NOT use Buzz's native ACP agent panel UI — Hermes appears as a "bot" member, not a managed agent
- No turn lifecycle management (ACP's `session/prompt``end_turn` model)
- Must handle WebSocket reconnection, event dedup, and subscription state
- Nostr python libraries are less mature than JS/Rust ecosystems
**Effort:** Medium. Requires a Nostr client module in Python (~500-800 lines).
### 2.3 Option C: Webhook Adapter (Buzz Workflows)
Use Buzz's YAML workflow engine to detect @mentions and fire webhooks to Hermes's REST API.
```
┌──────────┐ Buzz Workflow ┌─────────────┐ HTTP POST ┌──────────┐
│ Relay │────────►────────►│ Workflow │────────────►│ Hermes │
│ (event) │ trigger on │ Engine │ webhook │ REST API │
└──────────┘ kind 9 + p-tag └──────┬───────┘ └────┬─────┘
│ │
┌──────▼───────┐ ┌──────▼─────┐
│ Response │◄─────────│ AI reply │
│ back to │ REST API │ generated │
│ channel │ └────────────┘
└──────────────┘
```
**How it works:**
1. Create a Buzz workflow YAML that triggers on new messages in specific channels
2. Workflow filter matches events where `p` tag includes Hermes's pubkey
3. On match, workflow fires a `webhook` action to Hermes's REST API
4. Hermes processes the message and generates a response
5. Response is posted back to the channel via `buzz-cli` or relay REST API (NIP-98 signed)
**Buzz workflow capabilities (from ARCHITECTURE.md):**
- Triggers: message, reaction, schedule, webhook
- Actions: send message, add reaction
- `send_dm` and `set_channel_topic` actions are stubbed (return `NotImplemented`)
- Approval gates partially wired (WF-08: runs hitting approval gates fail)
**Pros:**
- Zero new protocol code — uses HTTP webhooks and REST API
- Leverages existing Buzz features (workflows are YAML-defined, relay-managed)
- Simple mental model — "when someone @mentions Hermes, POST to this URL"
- Hermes's existing REST API can be the webhook target
- No Nostr key management for Hermes (workflow signs events on its behalf)
**Cons:**
- **Workflow engine has gaps:** `send_dm` and `set_channel_topic` return `NotImplemented` (ARCHITECTURE.md §9, WF-07). Approval gates are partially broken (WF-08). Unknown if webhook→Hermes→response path works end-to-end.
- Workflow execution latency — not real-time; workflow engine processes events on a schedule
- Workflows can only react to events, not participate — no typing indicators, presence, or ongoing conversation state
- Hermes would not have its own Nostr identity — it's the workflow acting on its behalf
- No conversational context — each @mention is a fresh workflow run
- The workflow engine is undergoing active development; breaking changes possible
- Rate limiting unknown for workflow-triggered actions
**Effort:** Low to prototype, high risk of hitting engine limitations.
### 2.4 Option D: Future ACP Remote Transport
Wait for the ACP Transports Working Group to ship the Streamable HTTP / WebSocket remote transport, then have Hermes implement the ACP agent side over that transport.
**Status:** RFD stage — no timeline, no implementation.
**Pros:**
- Eventually the "right" answer — fully standards-compliant
- Hermes would be a first-class managed agent in Buzz Desktop
- Remote transport is being designed for exactly this use case
**Cons:**
- **Does not exist yet.** Building anything that depends on it today is blocked.
- Timeline unknown — could be months or years
- Would still need to implement ACP agent protocol (not just transport)
- ACP is coding-agent-optimized; conversational agents are a secondary concern
**Effort:** Blocked. Cannot proceed until spec is finalized and implemented.
---
## 3. Comparison Matrix
| Criterion | Bridge Agent (A) | Nostr-Native (B) | Webhook (C) | Future ACP (D) |
|-----------|:---:|:---:|:---:|:---:|
| **Works today** | ⚠️ Off-label | ✅ Proven (OpenClaw) | ⚠️ Workflow gaps | ❌ Doesn't exist |
| **Deployment complexity** | High (Rust binary) | Medium (Python module) | Low (YAML + HTTP) | Unknown |
| **Latency** | Low (WebSocket → stdio) | Low (WebSocket native) | Medium-High (workflow poll) | Low |
| **Reliability** | Medium (subprocess mgmt) | High (direct WS) | Low (engine gaps) | Unknown |
| **Buzz agent UX** | Full (ACP panel) | Bot member (no ACP panel) | None (workflow) | Full (ACP panel) |
| **Hermes identity** | Via buzz-acp key | Own Nostr keypair | Relay-owned (workflow) | Own ACP identity |
| **Presence/typing** | ✅ | ✅ | ❌ | ✅ |
| **Conversational context** | Via ACP sessions | App-level state | ❌ (per-invocation) | Via ACP sessions |
| **Maintenance burden** | High | Medium | Low (but fragile) | Unknown |
| **Protocol maturity** | ACP v1 (stable) | NIPs (stable) | Buzz workflows (beta) | ACP remote (pre-RFC) |
| **Coexists w/ other agents** | ✅ | ✅ | ✅ | ✅ |
---
## 4. Recommended Path: Nostr-Native WebSocket Client
### 4.1 Justification
The Nostr-native approach is recommended for the following reasons:
1. **Architectural correctness.** Buzz IS a Nostr relay. Connecting as a Nostr client is the protocol's first-class integration path. The relay doesn't distinguish between "human," "agent," or "bot" — all are Nostr keypairs publishing signed events. Hermes joining as another keypair is exactly how Buzz was designed to work.
2. **Proven in production.** OpenClaw's Buzz plugin has already solved this exact problem — connecting a server-side AI agent platform to Buzz channels via WebSocket. Their docs describe a working implementation with presence, typing indicators, mention handling, and reconnection logic.
3. **No desktop dependency.** This approach runs entirely on Core. No `buzz-acp` binary needed. No ACP stdio bridge. No subprocess lifecycle management.
4. **Full Buzz citizenship.** Hermes gets its own Nostr identity, can have a profile (kind 0), presence status, typing indicators, and can participate in any channel it's added to.
5. **No blocking dependencies.** The Nostr protocol is stable (NIP-01, NIP-42, NIP-98). The ACP remote transport is not.
6. **Leverages existing Hermes infrastructure.** Hermes already has a REST API, Telegram integration, MCP tools, and an AI pipeline. The Nostr client becomes another input/output channel alongside those.
7. **Coexistence.** If Buzz later ships remote ACP transport, a Nostr-native Hermes can operate alongside ACP-managed agents. The two approaches are complementary, not mutually exclusive.
**Trade-offs accepted:**
- Hermes appears as a "Bot" member in Buzz, not in the managed-agent ACP panel
- No turn lifecycle management from Buzz's perspective (Hermes manages its own conversational state)
- Must maintain WebSocket connection health (but this is standard infrastructure)
### 4.2 What "Bot" Member Means in Practice
In Buzz, a bot member with a Nostr keypair:
- Can be @mentioned like any other member
- Can post messages, reactions, and edits
- Has an online/offline presence indicator
- Shows typing indicators while processing
- Can be added to or removed from channels
- Has a profile (display name, avatar)
- Appears in the member list with a "Bot" role badge
- Cannot be spawned/managed via ACP (no agent panel controls)
This is functionally equivalent to how Slack bots, Discord bots, or Telegram bots work — they're members of the room, not subprocesses managed by the client.
---
## 5. Implementation Outline
### 5.1 Components
```
┌──────────────────────────────────────────────────────────────┐
│ Core (Hermes VPS) │
│ │
│ ┌─────────────────┐ ┌──────────────────────────────┐ │
│ │ Hermes Core │◄───►│ Buzz Nostr Client Module │ │
│ │ (AI pipeline, │ │ │ │
│ │ tools, skills) │ │ ┌──────────┐ ┌───────────┐ │ │
│ │ │ │ │ WS Conn │ │ Event Sign │ │ │
│ │ │ │ │ Manager │ │ er (Schnorr│ │ │
│ │ │ │ └──────────┘ └───────────┘ │ │
│ │ │ │ ┌──────────┐ ┌───────────┐ │ │
│ │ │ │ │ Sub Mgmt │ │ Presence │ │ │
│ │ │ │ └──────────┘ └───────────┘ │ │
│ └─────────────────┘ └──────────────┬───────────────┘ │
│ │ │
└─────────────────────────────────────────┼─────────────────────┘
│ WebSocket (WSS)
│ NIP-01 events
┌─────▼──────┐
│ Buzz Relay │
│ (app3) │
└────────────┘
```
**New components:**
1. **`buzz_client.py`** — Nostr WebSocket client module (~500 lines)
- WebSocket connection management (connect, reconnect, heartbeat)
- NIP-42 authentication (sign AUTH challenge)
- Event signing (Schnorr signatures via `secp256k1` or `nostr-py`)
- Subscription management (REQ, CLOSE, EVENT delivery)
- Event publishing (EVENT → relay)
2. **`buzz_channel.py`** — Hermes channel adapter (~200 lines)
- Bridges Buzz events ↔ Hermes message pipeline
- Filters events (ignore self, dedup by event ID)
- Converts Nostr events to Hermes internal message format
- Routes Hermes responses back to Buzz channels
- Manages presence updates (30s interval)
3. **Buzz identity** — one Nostr keypair
- Generated via `buzz-admin generate-key` on app3
- Private key stored in Hermes secrets/env
- Public key added to relay membership and target channels
### 5.2 Protocols & Wire Format
**Connection:**
```
Client Relay (wss://buzz.iamgmb.com)
│ WebSocket connect │
│─────────────────────────────────────────►│
│ ← AUTH challenge │
│◄─────────────────────────────────────────│
│ AUTH response (signed challenge) │
│─────────────────────────────────────────►│
│ ← AUTH OK │
│◄─────────────────────────────────────────│
```
**Subscription (NIP-01 REQ):**
```json
["REQ", "hermes-mentions", {"#p": ["<hermes_pubkey_hex>"], "kinds": [9, 40002], "since": <last_seen_timestamp>}]
```
**Message format (kind 9 — NIP-29 group chat):**
```json
{
"id": "<sha256>",
"pubkey": "<sender_pubkey>",
"kind": 9,
"tags": [
["h", "<channel_uuid>"],
["p", "<hermes_pubkey>"],
["e", "<thread_root>", "", "reply"]
],
"content": "{\"text\": \"@Hermes what's the status of the backup?\"}",
"sig": "<schnorr_sig>",
"created_at": 1234567890
}
```
**Response message (kind 9):**
```json
{
"id": "<sha256>",
"pubkey": "<hermes_pubkey>",
"kind": 9,
"tags": [
["h", "<channel_uuid>"],
["e", "<thread_root>", "", "reply"],
["p", "<requester_pubkey>"]
],
"content": "{\"text\": \"The backup completed successfully at 03:00 UTC. Latest snapshot: backup-2026-08-07.tar.gz\"}",
"sig": "<schnorr_sig>",
"created_at": 1234567895
}
```
**Presence (kind 20001, ephemeral, not stored):**
```json
["EVENT", {
"kind": 20001,
"content": "{\"status\": \"online\"}",
"tags": [],
...
}]
```
**Typing indicator (kind 20002, ephemeral):**
```json
["EVENT", {
"kind": 20002,
"content": "",
"tags": [["h", "<channel_uuid>"]],
...
}]
```
### 5.3 Auth Model
**Nostr keypair:**
- Generate via `buzz-admin generate-key` on app3 (or `openssl rand -hex 32` for privkey → derive pubkey via secp256k1)
- Hermes holds the private key (nsec or hex) in environment/secrets
- Public key (64-char hex) is used for:
- Relay membership: `./run.sh add-member <hermes_pubkey> --role member`
- Channel membership: `buzz channels add-member --channel <uuid> --pubkey <hermes_pubkey> --role bot`
- NIP-98 HTTP auth for REST API calls (if using REST fallback)
**NIP-42 authentication flow:**
1. Relay sends `["AUTH", "<challenge_string>"]` on WebSocket connect
2. Hermes constructs a kind 22242 auth event: `{"kind": 22242, "tags": [["challenge", challenge], ["relay", "wss://buzz.iamgmb.com"]], "content": "", ...}`
3. Hermes signs the event with its private key (Schnorr)
4. Hermes sends `["AUTH", <signed_event>]` to relay
5. Relay verifies signature and pubkey membership → connection authenticated
**API token alternative:**
Buzz supports API tokens as an alternative to NIP-42/NIP-98 for service accounts. This would replace the WebSocket auth dance with a static bearer token. However, API tokens are less documented and may not support all event kinds.
### 5.4 Deployment
| Component | Location | Details |
|-----------|----------|---------|
| Buzz Nostr client module | Core (Hermes VPS) | Python module imported by Hermes; runs in-process |
| Nostr keypair | Core (secrets) | Private key in `.env` or HashiCorp Vault |
| Relay membership | app3 | `./run.sh add-member` once during setup |
| Channel membership | app3 (via buzz-cli) | `buzz channels add-member --role bot` per channel |
| WebSocket connection | Core → app3:443 | WSS through CloudPanel Nginx |
**Note:** The WebSocket connection goes through CloudPanel's Nginx reverse proxy (`wss://buzz.iamgmb.com`). CloudPanel already includes WebSocket upgrade headers — no Nginx config changes needed.
### 5.5 Python Dependencies
| Package | Purpose |
|---------|---------|
| `websockets` | Async WebSocket client |
| `secp256k1` (or `coincurve`) | Schnorr signature signing/verification |
| `cryptography` | SHA-256 hashing for event IDs |
| `bech32` | npub/nsec encoding (optional, for UX) |
**Or:** Use `nostr-py` / `python-nostr` if they're mature enough. Research needed.
### 5.6 Effort Estimate
| Phase | Work | Est. Days |
|-------|------|-----------|
| **Prototype** | Nostr event signing + WebSocket connect + basic REQ/EVENT | 2-3 |
| **Channel adapter** | Message routing, dedup, mention detection, response posting | 2-3 |
| **Polish** | Presence, typing indicators, reconnection, error handling | 2-3 |
| **Integration** | Wire into Hermes's message pipeline + tool access | 2-3 |
| **Testing** | Multi-channel, concurrent mentions, reconnect scenarios | 2-3 |
| **Total** | | **10-15 days** |
This assumes the developer is familiar with Nostr protocol basics and Python async programming.
### 5.7 Alternate: Use `buzz-cli` as a Thin Proxy
As a lower-effort starting point, Hermes could use the existing `buzz-cli` binary for outbound messaging (posting replies) instead of implementing Nostr event signing from scratch:
```python
# Post a reply via buzz-cli
subprocess.run([
"buzz", "messages", "send",
"--channel", channel_uuid,
"--content", response_text,
"--reply-to", thread_event_id
], env={"BUZZ_RELAY_URL": "wss://buzz.iamgmb.com", "BUZZ_PRIVATE_KEY": hermes_nsec})
```
This avoids implementing Schnorr signing in Python but still requires a separate mechanism for **listening** to inbound mentions (since `buzz-cli` is request-response, not a persistent listener). The WebSocket subscription must still be implemented.
---
## 6. Open Questions
### 6.1 Must-Answer Before Building
| # | Question | How to Answer |
|---|----------|---------------|
| Q1 | **Does `buzz-cli` support a persistent listen/subscribe mode?** Current docs show only REST commands. If it has a hidden `buzz listen` or `buzz stream` mode, the implementation simplifies dramatically. | Search `buzz-cli/src/` for listen/stream/subscribe; test with `buzz help` |
| Q2 | **What Python Nostr library is production-ready?** `nostr-py`, `python-nostr`, `nostr-sdk`? We need WebSocket client + Schnorr signing + NIP-42 auth. | Test each library against `wss://buzz.iamgmb.com` with a test keypair |
| Q3 | **Can a non-ACP agent get the "Bot" role and appear in the member list?** OpenClaw does this, but need to verify exact permissions/UX. | Test with a manually-generated keypair added via `buzz channels add-member --role bot` |
| Q4 | **What happens when an agent is @mentioned in a channel it hasn't joined?** Does the relay deliver the event anyway? Does Buzz Desktop show it? | Test by subscribing to #p tag without channel membership |
| Q5 | **How does message threading work for agents?** Can Hermes reply in-thread by including the root event tag? | Examine OpenClaw's threading implementation; test manually |
| Q6 | **What's the rate limit for agent-standard tier?** Config defaults show 120 messages/min, but enforcement is stubbed (`AlwaysAllowRateLimiter`). | Check if rate limiting is enforced in our relay version |
### 6.2 Would-Be-Nice Answers
| # | Question |
|---|----------|
| Q7 | When will the ACP remote transport ship? (Informs whether to invest in Nostr-native or wait for ACP) |
| Q8 | Can Buzz workflows be used as a reliable event bridge, or are the `NotImplemented` stubs blocking? |
| Q9 | Does the relay's REST API support subscribing to events via long-poll or SSE? (Alternative to WebSocket for listening) |
| Q10 | Can Hermes's profile (kind 0) include custom metadata that Buzz Desktop renders (e.g., "AI Assistant" badge)? |
| Q11 | How does agent-to-agent communication work in Buzz? Can Hermes @mention another agent? |
| Q12 | What's the multi-community story? If we host multiple Buzz communities on the same relay, can one Hermes identity participate in all? |
---
## 7. References
| Resource | URL |
|----------|-----|
| Buzz GitHub | https://github.com/block/buzz |
| Buzz README | https://github.com/block/buzz/blob/main/README.md |
| Buzz Architecture | https://github.com/block/buzz/blob/main/ARCHITECTURE.md |
| Buzz Agent Vision | https://github.com/block/buzz/blob/main/VISION_AGENT.md |
| buzz-acp crate | https://github.com/block/buzz/tree/main/crates/buzz-acp |
| buzz-cli crate | https://github.com/block/buzz/tree/main/crates/buzz-cli |
| buzz-agent crate | https://github.com/block/buzz/blob/main/crates/buzz-agent/README.md |
| ACP Specification | https://agentclientprotocol.com/ |
| ACP Schema | https://agentclientprotocol.com/protocol/v1/schema |
| ACP Remote Transport RFD | https://agentclientprotocol.com/rfds/streamable-http-websocket-transport |
| ACP GitHub | https://github.com/agentclientprotocol/agent-client-protocol |
| Buzz .env.example | https://github.com/block/buzz/blob/main/.env.example |
| OpenClaw Buzz Plugin | https://docs.openclaw.ai/channels/buzz |
| Buzz Self-Host Guide | https://engineering.block.xyz/blog/run-your-own-buzz-relay |
| Buzz Skill (internal) | `~/.hermes/skills/devops/buzz-self-hosted-relay/SKILL.md` |
| Our relay deployment | `/opt/buzz/deploy/compose` on app3 (152.53.241.111) |
---
## Appendix A: Nostr NIPs Used by Buzz
From ARCHITECTURE.md and source analysis:
| NIP | Name | Buzz Usage |
|-----|------|------------|
| NIP-01 | Basic protocol | Event format, REQ/EVENT/CLOSE messages |
| NIP-02 | Contact list | User contacts/follows |
| NIP-05 | DNS-based identity | `/.well-known/nostr.json` |
| NIP-11 | Relay info | `GET /` returns relay metadata |
| NIP-16 | Replaceable events | Profile (kind 0), channel metadata |
| NIP-25 | Reactions | Kind 7 emoji reactions |
| NIP-27 | Text note references | `nostr:npub1...` and `nostr:note1...` |
| NIP-29 | Group chat | Kind 9 stream messages |
| NIP-34 | Git hosting | Repository announcements, patches |
| NIP-38 | User statuses | Profile status text+emoji |
| NIP-42 | Auth | `AUTH` challenge-response on WebSocket |
| NIP-98 | HTTP Auth | Schnorr-signed kind 27235 for REST API |
## Appendix B: Buzz Custom Event Kinds
| Kind | Name | Description |
|------|------|-------------|
| 9 | Stream message | Channel chat message (NIP-29) |
| 7 | Reaction | Emoji reaction (NIP-25) |
| 20001 | Presence | Ephemeral online/away status |
| 20002 | Typing | Ephemeral typing indicator |
| 22242 | Auth | NIP-42 authentication event |
| 27235 | HTTP Auth | NIP-98 HTTP authentication |
| 40002 | Stream message v2 | Rich-content channel message |
| 40003 | Stream message edit | Edit of a previous message |
| 40008 | Structured diff | Code diff with metadata |
| 43001 | Job request | Agent job request (ACP) |
| 40100 | Canvas | Channel canvas content |