docs: nest 19 files into audit/ clients/ infrastructure/ monitoring/ projects/ super-search/

This commit is contained in:
root
2026-08-08 13:04:55 -04:00
parent 11a1110b81
commit a522d11c35
20 changed files with 927 additions and 0 deletions
+280
View File
@@ -0,0 +1,280 @@
# Mattermost Replacement Analysis: Self-Hosted Team Chat with Native iOS Push Notifications
**Date:** August 7, 2026
**Context:** Evaluating self-hosted Mattermost alternatives that provide iOS push notifications without relying on a fragile self-hosted push proxy (MPNS/HPNS relay complexity).
---
## Executive Summary
**Recommendation: Zulip** — for most use cases. It offers a built-in Mattermost importer, the lightest resource footprint, Apache 2.0 licensing, and push notifications through Zulip's professionally maintained relay service with E2EE (since v12.0, April 2026). The push architecture is similar to Mattermost's HPNS, but Zulip's service is better maintained, fully documented, and the E2EE layer means Zulip cannot read your notification content.
**Alternative: Rocket.Chat** — if you require push notifications to be *fully* self-hosted (no external relay at all), Rocket.Chat is the only viable option. It supports direct APNs/FCM with your own Apple developer credentials, but requires white-labeling the mobile app — a significant ongoing maintenance burden.
---
## Why Push Notifications Are Hard for Self-Hosted Chat
Apple and Google require a single app bundle ID to be tied to a single set of push notification credentials. This means the official Rocket.Chat, Zulip, and Element apps in the App Store can only receive push from *one* push gateway — the one the app developer controls. All self-hosted deployments of these apps must route through the developer's push relay (or build their own app).
There are only two ways around this:
1. **Use the vendor's push relay** (Rocket.Chat gateway, Zulip push service, matrix.org) — simplest, but your notifications transit through a third party
2. **Build/white-label your own mobile app** with your own Apple Developer credentials — fully self-hosted push, but significant operational overhead
**The hard truth: no option achieves "100% self-hosted push with zero external dependencies using the official App Store app."** The question is which compromise best fits your requirements.
---
## Candidate Comparison
### 1. Zulip ⭐ RECOMMENDED
| Metric | Detail |
|--------|--------|
| **GitHub** | [zulip/zulip](https://github.com/zulip/zulip) — 25,617 stars, Apache 2.0 |
| **Language** | Python (backend), TypeScript/Flutter (mobile) |
| **iOS App** | 3.1/5.0 rating (new Flutter app launched June 2025, ratings still stabilizing); fully native |
| **Push Architecture** | Central push notification service (`push.zulip.com`) — server → Zulip relay → APNs/FCM |
| **E2EE Push** | ✅ Yes since Zulip Server 12.0 (April 2026). Content + metadata encrypted. Zulip's relay cannot read your messages. |
| **Self-Hosted Push?** | Code is 100% open source and *technically* self-hostable, but not documented/supported as a turnkey deployment. Requires building custom mobile app with your own APNs keys. |
| **Free Push Tier** | ✅ Free for ≤10 users (all features). Community plan (open source, academic, non-profit): unlimited free. |
| **Paid Push** | Basic: $3.50/user/mo. Business: $6.67/user/mo (annual). 25-user minimum for Business. |
| **Docker** | ✅ Official Docker Compose support. Single-server deployment well-documented. |
| **Resource Requirements** | ~2 GB RAM for small teams, scales well. Significantly lighter than Mattermost. |
| **Mattermost Migration** | ✅ **Built-in importer**`zulip.com/help/import-from-mattermost`. Also imports from Slack, Teams, Rocket.Chat. |
| **Differentiator** | **Topic-based threading model** — every message lives in a topic within a stream. Far superior to Slack/Mattermost's "channel soup" for async/distributed teams. |
| **Maintenance** | Very active — daily commits. Strong documentation (ReadTheDocs). |
| **Push Dependency** | Depends on `push.zulip.com` (Zulip Cloud infrastructure). Not fully self-sovereign — if Zulip the company disappears, push stops working unless you build your own app. |
**Pros:**
- Lightest resource footprint of all candidates
- Built-in Mattermost importer
- E2EE push notifications — Zulip can't read your content
- Free for ≤10 users; generous Community plan
- Apache 2.0 — most permissive license
- Uniquely powerful threading model
**Cons:**
- Push relay dependency (same fundamental architecture as Mattermost HPNS)
- iOS app ratings still stabilizing after Flutter rewrite
- Smaller enterprise customer base than Rocket.Chat/Mattermost
- $6.67/user/mo at Business tier is cheaper than Mattermost Enterprise but not free
---
### 2. Rocket.Chat
| Metric | Detail |
|--------|--------|
| **GitHub** | [RocketChat/Rocket.Chat](https://github.com/RocketChat/Rocket.Chat) — 45,944 stars, mixed license |
| **Language** | TypeScript (Meteor.js framework) |
| **iOS App** | 4.4/5.0, 3,700+ ratings — mature, well-rated |
| **Push Architecture** | **Two modes:** (1) Push Gateway via `gateway.rocket.chat` (recommended), or (2) Self-Configured with direct APNs/FCM certificates |
| **Self-Hosted Push (Gateway)** | 10,000 free push/month for Community Edition. Then requires paid plan. Traffic routes through Rocket.Chat's gateway. |
| **Self-Hosted Push (Direct APNs)** | ✅ Fully self-hosted push possible — provide your own APN passphrase/key/cert + FCM credentials. But **requires white-labeling the mobile app** (building from source with your bundle ID and credentials). This is the only truly "no external relay" option among all candidates. |
| **White-Label App** | [Documented](https://developer.rocket.chat/docs/mobile-app-white-labeling) — requires Apple Developer account ($99/yr), building from source, and ongoing maintenance to track upstream releases. |
| **Free Tier** | Community Edition (CE) — free, but 10K push/month limit. No per-user cost. |
| **Paid Plans** | From $7/user/mo for unlimited push + enterprise features |
| **Docker** | ✅ Docker Compose. Requires MongoDB replica set. |
| **Resource Requirements** | **Heaviest** of all candidates. Meteor.js + MongoDB replica set. Needs more RAM for equivalent user counts vs Mattermost. ~4 GB minimum recommended. |
| **Mattermost Migration** | ⚠️ No built-in importer. Must convert Mattermost export to CSV, then import as CSV. Community scripts exist but no official tool. |
| **Differentiator** | Omnichannel — integrated customer-facing live chat, WhatsApp, Telegram, Instagram alongside internal team chat. Best if you need customer comms too. |
| **Push Dependency** | Mode-dependent. Gateway mode depends on `gateway.rocket.chat`. Self-configured mode has no external dependency. |
| **Maintenance** | Active but ~6-month release support cadence. MongoDB requirement adds operational complexity. |
**Pros:**
- Largest install base (45.9K stars)
- Mature, well-rated iOS app
- *Can* achieve fully self-hosted push via direct APNs + white-label app
- Omnichannel if you need customer-facing chat
- Rich integration ecosystem
**Cons:**
- Heaviest resource requirements (MongoDB replica set + Meteor.js)
- No built-in Mattermost importer
- Push gateway: 10K free/month, then paid
- White-label path: significant ongoing maintenance
- Community Edition push limit may be restrictive
---
### 3. Element / Matrix (Synapse)
| Metric | Detail |
|--------|--------|
| **GitHub** | [element-hq/synapse](https://github.com/element-hq/synapse) — 4,501 stars, AGPL-3.0 |
| **Language** | Python |
| **iOS App** | Element X: 4.9/5.0 (excellent). Element Classic: 4.3/5.0. Both actively maintained. |
| **Push Architecture** | **Android:** Fully self-hostable via UnifiedPush + ntfy (self-hosted push server). **iOS: ALL push routes through matrix.org.** There is no way to self-host iOS push with the official Element app. |
| **iOS Push Reality** | Element/New Vector holds the Apple Developer credentials for the App Store app. Your Synapse server sends push events to matrix.org's push gateway, which forwards to APNs. `format: event_id_only` by default — matrix.org only learns "user X on homeserver Y has a notification," not message content. Element then fetches the actual message from your homeserver. |
| **Fully Self-Hosted iOS Push?** | ❌ **Impossible** without building your own iOS Matrix client with your own Apple Developer account. This is an Apple platform restriction, not a Matrix design choice. |
| **Free Tier** | ✅ Synapse is fully open-source, free. Push via matrix.org is free (no per-notification cost). |
| **Docker** | ✅ Docker Compose. Requires PostgreSQL. |
| **Resource Requirements** | Heavy. Synapse is known for high resource consumption. ~4 GB RAM minimum. Consider Dendrite (lighter Matrix homeserver in Go) as alternative. |
| **Mattermost Migration** | ⚠️ Via [matrix-appservice-mattermost](https://github.com/hifi/mattermost-matrix-bridge) — more of a bridge than a migration. |
| **Differentiator** | Decentralized federation — users on your server can chat with users on other Matrix servers. Open standard. Multiple client choices (Element, FluffyChat, etc.). |
| **Push Dependency** | iOS: `matrix.org` push gateway (always). Android: optional UnifiedPush (self-hostable). |
| **Maintenance** | Actively maintained by Element/New Vector. Federation adds complexity. |
**Pros:**
- Element X iOS app is the highest rated (4.9)
- Android push fully self-hostable
- Federation — chat across servers
- Open standard, multiple clients
- Free push (routed through matrix.org)
**Cons:**
-**iOS push CANNOT be self-hosted** with the official app
- Synapse is resource-heavy
- Federation adds operational complexity
- AGPL-3.0 license (more restrictive than Apache 2.0)
- Bridge to Mattermost, not a clean migration
---
### 4. Nextcloud Talk
| Metric | Detail |
|--------|--------|
| **Push Architecture** | All push goes through `push-notifications.nextcloud.com`. The push proxy is **NOT open source**. Enterprise customers get a proprietary self-hosted push proxy option. |
| **Self-Hosted Push?** | ❌ Not available to community. Enterprise-only, proprietary. |
| **Viability as Mattermost Replacement** | ❌ Not standalone — requires the full Nextcloud stack (Files, Talk, server, database, HPB signaling server). Massive operational overhead if you only need chat. |
| **Verdict** | **Not recommended.** Only viable if you already run Nextcloud and want to add chat. Even then, push dependency on Nextcloud's proxy is a concern. |
---
### 5. Discourse (Chat Plugin)
| Metric | Detail |
|--------|--------|
| **iOS Push** | For self-hosted Discourse: push notifications work via **polling**, not real push. Only Discourse-hosted sites get real push via DiscourseHub app. |
| **Verdict** | **Not recommended.** Not a team chat platform — it's a forum with chat bolted on. No real iOS push for self-hosted. |
---
### 6. Wire
| Metric | Detail |
|--------|--------|
| **Self-Hosted** | Enterprise-only. Kubernetes + Cassandra deployment. Heaviest infra footprint of any candidate. |
| **Free Tier** | None for self-hosted. Per-user enterprise pricing. |
| **Verdict** | **Not recommended.** Overkill for typical teams. No free self-hosted tier. Requires dedicated infrastructure team. Only suitable for large enterprises with strict security/compliance requirements. |
---
## Push Notification Architecture: Summary Table
| Platform | iOS Push Self-Hostable? | Push Relay Required? | E2EE Push? | Free Push Tier |
|----------|:------------------------:|:--------------------:|:----------:|:--------------:|
| **Mattermost** (baseline) | ⚠️ Via self-hosted push proxy (MPNS/HPNS) | Yes (HPNS) or self-hosted proxy | ❌ No | TPNS: free, limited |
| **Zulip** | ⚠️ Technically possible, not documented | Yes (`push.zulip.com`) | ✅ v12.0+ | ✅ ≤10 users free; Community plan unlimited free |
| **Rocket.Chat** | ✅ Direct APNs + white-label app | Optional (gateway or direct) | ⚠️ Privacy mode available | 10K push/month free (gateway) |
| **Element/Matrix** | ❌ iOS always routes through matrix.org | Yes (`matrix.org`) | ❌ No (event_id_only reduces exposure) | ✅ Free |
| **Nextcloud Talk** | ❌ Enterprise-only proprietary | Yes (`push-notifications.nextcloud.com`) | ✅ (encrypted proxy) | ✅ Free (throttled) |
---
## Quick Comparison Matrix
| Factor | Zulip | Rocket.Chat | Element/Matrix |
|--------|-------|-------------|----------------|
| **GitHub Stars** | 25.6K | 45.9K | 4.5K (Synapse) |
| **License** | Apache 2.0 | Mixed | AGPL-3.0 |
| **iOS App Rating** | ~3.1 (new Flutter) | 4.4 (3.7K reviews) | 4.9 (Element X) |
| **RAM (min)** | 2 GB | 4 GB+ | 4 GB+ |
| **Docker** | ✅ Compose | ✅ Compose + MongoDB RS | ✅ Compose |
| **Mattermost Import** | ✅ Built-in | ⚠️ CSV only | ⚠️ Bridge only |
| **Push Cost** | Free ≤10 / $3.50-6.67/user | Free 10K/mo / $7+/user | Free |
| **Push Independence** | Low (relay-dependent) | High (direct APNs possible) | None for iOS (matrix.org) |
| **E2EE Push** | ✅ v12.0+ | ⚠️ Privacy mode | ❌ |
| **Threading** | ⭐ Topic-based (best) | Threads | Threads |
| **Differentiator** | Async threading model | Omnichannel customer comms | Federation |
---
## Recommendation
### Primary Recommendation: Zulip
**Why:**
1. **Built-in Mattermost importer** — lowest migration friction
2. **Lightest resource footprint** — 2 GB RAM, runs on modest VPS
3. **E2EE push notifications since v12.0 (April 2026)** — Zulip's relay cannot read your notification content
4. **Apache 2.0 license** — most permissive, no copyleft concerns
5. **Free for ≤10 users**; Community plan covers many use cases for free
6. **Topic-based threading** — superior to Mattermost's channel model for organized communication
7. **Push architecture is well-documented and stable** — same relay model as Mattermost, but better maintained
**The tradeoff:** Like Mattermost, push notifications depend on Zulip's cloud relay service. If Zulip the company disappears, push stops working unless you build your own mobile app. This is the same risk you have with Mattermost today. The E2EE in v12.0 mitigates the privacy concern — Zulip sees encrypted blobs, not your content.
### Alternative Recommendation: Rocket.Chat (self-configured push)
**Choose Rocket.Chat if:**
- You require **zero external push relay dependency**
- You are willing to maintain a white-labeled mobile app
- You have an Apple Developer account ($99/yr)
- You have the operational capacity to manage MongoDB and a heavier stack
**The tradeoff:** You get *truly* self-hosted push (your server talks directly to Apple APNs), but you must build, sign, and distribute your own iOS app. This is a significant ongoing maintenance commitment (tracking upstream releases, rebuilding, re-signing, deploying to MDM/TestFlight).
### What About Element?
Element X has the best iOS app and free push, but iOS push *always* routes through matrix.org. If you're comfortable with that relay dependency (which you already accept with Mattermost today), Element is worth considering for the federation benefits and excellent mobile UX. The lack of a clean Mattermost importer and AGPL license are the main blockers.
### What About the "Ideal" Solution?
The ideal — 100% self-hosted push with the official App Store app and zero external dependencies — **does not exist.** This is an Apple/Google platform constraint, not a failing of any particular project. The only way to achieve it is to build and maintain your own iOS app (Rocket.Chat's white-label path).
---
## Migration Path: Mattermost → Zulip
Zulip has [documented import support](https://zulip.com/help/import-from-mattermost) for Mattermost exports:
```bash
# 1. Export from Mattermost (bulk export or database dump)
# 2. Convert to Zulip import format
# 3. Import into Zulip
/home/zulip/deployments/current/manage.py import mattermost_organization.zip
```
Zulip supports importing:
- User accounts (name, email, avatar)
- Channels → Streams
- Message history
- Attachments/file uploads
- Custom emoji (limited)
**Not imported:** integrations, bots, webhooks (must be recreated)
### Deployment Pattern (Docker)
```bash
# Zulip Docker quick-start
git clone https://github.com/zulip/docker-zulip.git
cd docker-zulip
# Configure .env with your settings
docker compose up -d
```
---
## Sources
- [Rocket.Chat Push Notification Documentation](https://docs.rocket.chat/docs/push)
- [Rocket.Chat Mobile App White-Labeling](https://developer.rocket.chat/docs/mobile-app-white-labeling)
- [Zulip Mobile Push Notification Service](https://zulip.readthedocs.io/en/latest/production/mobile-push-notifications.html)
- [Zulip Plans and Pricing](https://zulip.com/plans/)
- [Zulip Import from Mattermost](https://zulip.com/help/import-from-mattermost)
- [Element/Matrix UnifiedPush + ntfy Setup](https://docs.element.io/latest/element-support/element-androidios-client-settings/using-unified-push-and-ntfy-for-push-notifications/)
- [Self-Hosted Matrix Notifications (CodingKiwi)](https://blog.coding.kiwi/selfhosted-matrix-notifications/)
- [iOS Push Limitations for Self-Hosters (YunoHost Forum)](https://forum.yunohost.org/t/how-to-setup-push-notification-with-synapse-and-element-or-element-x-android/36897)
- [Nextcloud Push Notifications Blog](https://nextcloud.com/blog/nextclouds-push-notifications-for-ios-and-android/)
- [Nextcloud Custom Push Server (Community Discussion)](https://help.nextcloud.com/t/custom-push-notifications-server-setup-for-talk/143412)
- [Discourse iOS Push for Self-Hosted](https://meta.discourse.org/t/ios-android-push-notifications-on-self-hosted-discourse-docker/394149)
- Video: [iOS Messenger App Development in 2026 (ForaSoft)](https://www.forasoft.com/blog/article/ios-messenger-app-development) — reference architecture confirming APNs constraints
---
*Research conducted August 7, 2026. All push notification details verified against official project documentation. App Store ratings are US region snapshots and may vary by region.*
+587
View File
@@ -0,0 +1,587 @@
# 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 |
+60
View File
@@ -0,0 +1,60 @@
# CoverZone — WISP Coverage Planning Analysis
> Domain: coverzone.com (available)
## Source
GridVisio (https://gridvisio.com) — discovered via WISPA community, Aug 7 2026.
## What It Is
Browser-based coverage planning tool targeting small WISPs priced out of enterprise tools.
Community-driven development — updates come directly from WISP feedback.
## Pricing
| Tier | Price | Limits |
|---|---|---|
| Free | $0 | 1 project, 5 towers, 100 subscribers |
| Starter | $19/mo | 3 projects, 20 towers, 1,000 subscribers |
| Pro | $39/mo | Unlimited everything |
| Trial | 14 days | No credit card required |
## Features
### Core
- Tower + sector antenna management (azimuth, beamwidth, radius) on Google Maps satellite
- CSV subscriber import — auto-served/unserved classification
- Hypothetical tower placement with unserved subscriber coverage simulation
- White area detection — DBSCAN clustering identifies coverage gaps
- Coverage overlap analysis — detect same-frequency sector interference
- Drive test overlay — import GPS signal logs, see real vs planned coverage
- Shareable read-only map links for clients (no login required)
- LoS link check with Fresnel zone, PDF export, elevation data (SRTM, Copernicus GLO-30)
- Lambert coordinate converter (WGS84 ↔ Lambert 72/2008/2005)
- KMZ / PDF / PNG / XLSX / CSV export
- BDC / BEAD grant filing export
- Team collaboration with viewer/editor roles
- Coverage Widget — embeddable in client websites for instant location coverage check
### Propagation Models (added based on WISP community feedback)
- **ITM (Longley-Rice)** — selectable per-project and per-sector
- **ITU-R P.1812** — default model
- **FSPL + ITU-R P.526 diffraction** — automatic fallback for links above 20GHz where P.1812 and ITM don't apply
### Multipath/NLoS Handling (community-driven additions)
- **Reflection-path check** — specular bounce candidate (ground/building) for Borderline/Obstructed links, non-coherently combined with direct path
- **ITU-R P.2108** — statistical clutter-loss margin for dense suburban/urban links, implemented from the Recommendation's own equations
- **ITU-R P.530 fade margin** — for Clear links, temporal/weather-driven multipath via ITU-Rpy for geoclimatic factor derivation
## Relevance to IT Pro Partner
- Forefront Wireless is a WISP client — coverage planning tools are directly applicable
- Existing CCR tower backup infrastructure could feed a competing product
- Coverage Widget is a natural upsell for WISP client websites we host
- Market gap: small WISPs priced out of enterprise tools, served by a community-responsive developer
## Competitive Angle
- GridVisio is community-driven — feature velocity is high, trust is earned through WISPA engagement
- Weakness: single developer? Small team? Could be out-executed by a faster, better-funded competitor
- Opportunity: white-label or acquire if the developer doesn't have MSP/sales infrastructure to scale
## Questions for Later
1. Who built it? Solo dev or team?
2. What's their stack? (Google Maps API + browser-based = high API costs at scale?)
3. Is the embeddable widget the real moat? (client-facing, no-login-required)
4. Could we build a better version using our existing WISP tower data + MikroTik integrations?