From bf8e2f8f8a5207787f2473344880cc797938d150 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 15:59:01 -0500 Subject: [PATCH 01/14] fix(acp,agent): support reasoning_content fallback, turn text publishing, and wiki troubleshooting Signed-off-by: mainza-ai --- crates/buzz-acp/src/acp.rs | 10 ++ crates/buzz-acp/src/pool.rs | 36 +++++ crates/buzz-agent/src/llm.rs | 8 +- desktop/src-tauri/Cargo.lock | 1 + wiki/CLAUDE.md | 51 +++++++ wiki/components/admin-web.md | 16 ++ wiki/components/buzz-acp.md | 17 +++ wiki/components/buzz-admin.md | 14 ++ wiki/components/buzz-agent.md | 20 +++ wiki/components/buzz-audit.md | 15 ++ wiki/components/buzz-auth.md | 15 ++ wiki/components/buzz-cli.md | 16 ++ wiki/components/buzz-conformance.md | 13 ++ wiki/components/buzz-core.md | 15 ++ wiki/components/buzz-db.md | 16 ++ wiki/components/buzz-dev-mcp.md | 15 ++ wiki/components/buzz-media.md | 14 ++ wiki/components/buzz-persona.md | 13 ++ wiki/components/buzz-pubsub.md | 15 ++ wiki/components/buzz-push-gateway.md | 9 ++ wiki/components/buzz-relay-mesh.md | 14 ++ wiki/components/buzz-relay.md | 24 +++ wiki/components/buzz-sdk.md | 13 ++ wiki/components/buzz-search.md | 14 ++ wiki/components/buzz-test-client.md | 9 ++ wiki/components/buzz-workflow.md | 17 +++ wiki/components/buzz-ws-client.md | 13 ++ wiki/components/desktop-client.md | 25 ++++ wiki/components/git-credential-nostr.md | 14 ++ wiki/components/git-sign-nostr.md | 9 ++ wiki/components/mobile-client.md | 21 +++ wiki/components/sprig.md | 13 ++ wiki/components/web-client.md | 13 ++ wiki/concepts/acp.md | 21 +++ wiki/concepts/architecture.md | 43 ++++++ wiki/concepts/audit-log.md | 16 ++ wiki/concepts/authentication.md | 22 +++ wiki/concepts/buzz-mesh.md | 14 ++ wiki/concepts/channel-membership.md | 14 ++ wiki/concepts/event-pipeline.md | 21 +++ wiki/concepts/git-integration.md | 21 +++ wiki/concepts/media-storage.md | 15 ++ wiki/concepts/multi-tenancy.md | 19 +++ wiki/concepts/nostr-protocol.md | 25 ++++ wiki/concepts/search.md | 16 ++ wiki/concepts/workflow-engine.md | 35 +++++ wiki/entities/agent.md | 22 +++ wiki/entities/channel.md | 19 +++ wiki/entities/community.md | 14 ++ wiki/entities/nostr-event.md | 15 ++ wiki/entities/relay.md | 16 ++ wiki/index.md | 66 +++++++++ wiki/log.md | 47 ++++++ wiki/operations/cli-reference.md | 55 +++++++ wiki/operations/configuration.md | 35 +++++ wiki/operations/deployment.md | 30 ++++ wiki/operations/development-setup.md | 48 ++++++ wiki/operations/troubleshooting.md | 189 ++++++++++++++++++++++++ 58 files changed, 1365 insertions(+), 1 deletion(-) create mode 100644 wiki/CLAUDE.md create mode 100644 wiki/components/admin-web.md create mode 100644 wiki/components/buzz-acp.md create mode 100644 wiki/components/buzz-admin.md create mode 100644 wiki/components/buzz-agent.md create mode 100644 wiki/components/buzz-audit.md create mode 100644 wiki/components/buzz-auth.md create mode 100644 wiki/components/buzz-cli.md create mode 100644 wiki/components/buzz-conformance.md create mode 100644 wiki/components/buzz-core.md create mode 100644 wiki/components/buzz-db.md create mode 100644 wiki/components/buzz-dev-mcp.md create mode 100644 wiki/components/buzz-media.md create mode 100644 wiki/components/buzz-persona.md create mode 100644 wiki/components/buzz-pubsub.md create mode 100644 wiki/components/buzz-push-gateway.md create mode 100644 wiki/components/buzz-relay-mesh.md create mode 100644 wiki/components/buzz-relay.md create mode 100644 wiki/components/buzz-sdk.md create mode 100644 wiki/components/buzz-search.md create mode 100644 wiki/components/buzz-test-client.md create mode 100644 wiki/components/buzz-workflow.md create mode 100644 wiki/components/buzz-ws-client.md create mode 100644 wiki/components/desktop-client.md create mode 100644 wiki/components/git-credential-nostr.md create mode 100644 wiki/components/git-sign-nostr.md create mode 100644 wiki/components/mobile-client.md create mode 100644 wiki/components/sprig.md create mode 100644 wiki/components/web-client.md create mode 100644 wiki/concepts/acp.md create mode 100644 wiki/concepts/architecture.md create mode 100644 wiki/concepts/audit-log.md create mode 100644 wiki/concepts/authentication.md create mode 100644 wiki/concepts/buzz-mesh.md create mode 100644 wiki/concepts/channel-membership.md create mode 100644 wiki/concepts/event-pipeline.md create mode 100644 wiki/concepts/git-integration.md create mode 100644 wiki/concepts/media-storage.md create mode 100644 wiki/concepts/multi-tenancy.md create mode 100644 wiki/concepts/nostr-protocol.md create mode 100644 wiki/concepts/search.md create mode 100644 wiki/concepts/workflow-engine.md create mode 100644 wiki/entities/agent.md create mode 100644 wiki/entities/channel.md create mode 100644 wiki/entities/community.md create mode 100644 wiki/entities/nostr-event.md create mode 100644 wiki/entities/relay.md create mode 100644 wiki/index.md create mode 100644 wiki/log.md create mode 100644 wiki/operations/cli-reference.md create mode 100644 wiki/operations/configuration.md create mode 100644 wiki/operations/deployment.md create mode 100644 wiki/operations/development-setup.md create mode 100644 wiki/operations/troubleshooting.md diff --git a/crates/buzz-acp/src/acp.rs b/crates/buzz-acp/src/acp.rs index 49e4d6cce0..1704ef7876 100644 --- a/crates/buzz-acp/src/acp.rs +++ b/crates/buzz-acp/src/acp.rs @@ -187,6 +187,8 @@ pub struct AcpClient { /// Other agents may leave this unset — readers must treat `None` as /// "no active run to steer into" and fall back to cancel+merge. active_run_id: Option, + /// Accumulated agent_message_chunk text for the current turn. + accumulated_text: String, /// Per-turn channel for receiving goose-native non-cancelling steer /// requests from the main loop. Installed by /// [`install_steer_rx`](Self::install_steer_rx) at dispatch and @@ -494,11 +496,17 @@ impl AcpClient { observer_agent_index: None, observer_context: ObserverContext::default(), active_run_id: None, + accumulated_text: String::new(), steer_rx: None, goose_usage: UsageTracker::default(), }) } + /// Take accumulated agent_message_chunk text for the current turn. + pub fn take_accumulated_text(&mut self) -> String { + std::mem::take(&mut self.accumulated_text) + } + /// Attach a local observer feed to this ACP client. pub fn set_observer(&mut self, observer: Option, agent_index: usize) { self.observer = observer; @@ -691,6 +699,7 @@ impl AcpClient { let params = build_prompt_params(session_id, prompt_blocks); let hard_deadline = tokio::time::Instant::now() + max_duration; self.current_hard_deadline = Some(hard_deadline); + self.accumulated_text.clear(); // Mark the usage tracker as in-flight for this turn BEFORE sending the // prompt so that any setup notifications recorded earlier are not @@ -1543,6 +1552,7 @@ impl AcpClient { "agent_message_chunk" => { if let Some(text) = update["content"]["text"].as_str() { tracing::info!(target: "acp::stream", "{text}"); + self.accumulated_text.push_str(text); } false } diff --git a/crates/buzz-acp/src/pool.rs b/crates/buzz-acp/src/pool.rs index 0c51fe954f..429b47cfb6 100644 --- a/crates/buzz-acp/src/pool.rs +++ b/crates/buzz-acp/src/pool.rs @@ -2094,6 +2094,20 @@ pub async fn run_prompt_task( ) .await; + let raw_turn_text = agent.acp.take_accumulated_text(); + let turn_text = clean_agent_text_response(&raw_turn_text); + if !turn_text.is_empty() { + if let (PromptSource::Channel(channel_id), Some(ref b)) = (&source, &batch) { + let thread_tags = b + .events + .last() + .map(|be| crate::queue::parse_thread_tags(&be.event)) + .unwrap_or_default(); + post_failure_notice(&ctx.rest_client, *channel_id, &thread_tags, &turn_text) + .await; + } + } + send_prompt_result( &result_tx, &turn_id, @@ -3547,6 +3561,28 @@ pub(crate) async fn reaction_add(rest: &crate::relay::RestClient, event_id: &str } } +pub(crate) fn clean_agent_text_response(text: &str) -> String { + let mut cleaned = text.to_string(); + if let Some(pos) = cleaned.rfind("```json") { + let block = &cleaned[pos..]; + if block.contains("reply_to") || block.contains("channel") || block.contains("command") { + cleaned.truncate(pos); + } + } + if let Some(pos) = cleaned.rfind("call:buzz-dev-mcp") { + cleaned.truncate(pos); + } + if let Some(pos) = cleaned.rfind("Call reply_to") { + cleaned.truncate(pos); + } + cleaned = cleaned + .replace("<|tool_call>", "") + .replace("<|tool_calls>", "") + .replace("<|im_end|>", "") + .replace("<|endoftext|>", ""); + cleaned.trim().to_string() +} + /// Best-effort: post a visible failure notice (kind:9) to a channel after a /// batch is dead-lettered. Replies into the thread of `thread_tags` when the /// triggering event was threaded. Errors are logged and swallowed — the diff --git a/crates/buzz-agent/src/llm.rs b/crates/buzz-agent/src/llm.rs index 23cef24e72..b6f4e5d0d8 100644 --- a/crates/buzz-agent/src/llm.rs +++ b/crates/buzz-agent/src/llm.rs @@ -1077,6 +1077,9 @@ fn parse_responses(v: Value) -> Result { Some("completed") => ProviderStop::EndTurn, _ => ProviderStop::Other, }; + if text.is_empty() && !reasoning.is_empty() && tool_calls.is_empty() { + text = reasoning.clone(); + } let input_tokens = sum_usage(&v, &["input_tokens"]); let output_tokens = sum_usage(&v, &["output_tokens"]); Ok(LlmResponse { @@ -1204,7 +1207,7 @@ fn parse_openai(v: Value) -> Result { let msg = choice .get("message") .ok_or_else(|| AgentError::Llm("missing message".into()))?; - let text = str_field(msg, "content"); + let mut text = str_field(msg, "content"); // DeepSeek and vLLM-style OpenAI-compat hosts expose reasoning tokens on the // message object. Prefer `reasoning_content` (DeepSeek's field name); fall // back to `reasoning` (some other providers). Both are absent for standard @@ -1233,6 +1236,9 @@ fn parse_openai(v: Value) -> Result { )?); } } + if text.is_empty() && !reasoning.is_empty() && tool_calls.is_empty() { + text = reasoning.clone(); + } let input_tokens = openai_chat_input_tokens(&v); let output_tokens = sum_usage(&v, &["completion_tokens"]); Ok(LlmResponse { diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 7dcf615c00..074b8f739e 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -991,6 +991,7 @@ dependencies = [ name = "buzz-core" version = "0.1.0" dependencies = [ + "base64 0.22.1", "chrono", "hex", "hmac 0.13.0", diff --git a/wiki/CLAUDE.md b/wiki/CLAUDE.md new file mode 100644 index 0000000000..7c90321f17 --- /dev/null +++ b/wiki/CLAUDE.md @@ -0,0 +1,51 @@ +# Buzz Wiki — Schema & Conventions + +This directory (`wiki/`) is an LLM-maintained knowledge base for the Buzz project. +The LLM creates, updates, and cross-references all pages. Humans read and guide. + +## Directory structure + +``` +wiki/ +├── CLAUDE.md # This file — schema, conventions, workflows +├── index.md # Catalog of all pages, organized by category +├── log.md # Append-only chronological record of changes +├── entities/ # Core system entities (Relay, Community, Agent, etc.) +├── concepts/ # Key ideas and mechanisms (Auth, Pipeline, Workflow, etc.) +├── components/ # Crate/service/client reference docs +└── operations/ # Deployment, configuration, development setup +``` + +## Page conventions + +- All pages are Markdown with `.md` extension. +- Every page starts with an `#` title matching the filename (title case). +- Every page should link to related pages using `[display text](../category/pagename)`. +- Pages in `entities/` describe a thing. Pages in `concepts/` describe an idea or mechanism. +- Pages in `components/` document a crate or client. Pages in `operations/` document how-to. +- Keep pages focused. Split into sub-pages when a section gets too long. +- Use `##` for major sections, `###` for subsections. + +## Workflows + +### Ingest a source +1. Read the source document. +2. Discuss notable points with the user. +3. Create/update relevant entity and concept pages across the wiki. +4. Update `index.md` if new pages were created. +5. Append an entry to `log.md`. + +### Answer a query +1. Read `index.md` to find relevant pages. +2. Read the relevant pages. +3. Synthesize an answer with citations to wiki pages. +4. If the answer is valuable as a new page, write it and update `index.md`. +5. Append an entry to `log.md`. + +### Lint the wiki +1. Check for contradictions between pages. +2. Find stale claims that newer entries have superseded. +3. Find orphan pages with no inbound links. +4. Find important concepts missing their own page. +5. Suggest new questions and sources to investigate. +6. Append an entry to `log.md`. diff --git a/wiki/components/admin-web.md b/wiki/components/admin-web.md new file mode 100644 index 0000000000..47f835d076 --- /dev/null +++ b/wiki/components/admin-web.md @@ -0,0 +1,16 @@ +# Admin Web + +Web-based admin dashboard for relay operators. Provides a graphical interface for administrative tasks. + +**Capabilities:** +- Community management (create, configure, delete) +- Channel administration +- Member management +- Audit log viewer +- System health monitoring +- Configuration editing + +**Related:** +- [buzz-admin](buzz-admin) — CLI equivalent +- [Community](../entities/community) +- [AuditLog](../concepts/audit-log) diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md new file mode 100644 index 0000000000..f87a704db0 --- /dev/null +++ b/wiki/components/buzz-acp.md @@ -0,0 +1,17 @@ +# buzz-acp + +ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI agent subprocesses. + +**How it works:** +- Maintains a WebSocket connection to the relay (NIP-42 auth) +- Spawns and manages agent subprocesses over stdio JSON-RPC +- Translates Nostr events → JSON-RPC calls for the agent +- Translates agent responses → Nostr events published to the relay +- Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message +- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `) and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` +- Handles reconnection, subscription management, and agent lifecycle + +**Related:** +- [ACP](../concepts/acp) +- [Agent](../entities/agent) +- [buzz-agent](buzz-agent) diff --git a/wiki/components/buzz-admin.md b/wiki/components/buzz-admin.md new file mode 100644 index 0000000000..bff2592a93 --- /dev/null +++ b/wiki/components/buzz-admin.md @@ -0,0 +1,14 @@ +# buzz-admin + +Operator CLI for relay administration. Used for managing communities, channels, members, and system configuration. + +**Capabilities:** +- Create/delete communities +- Manage channel memberships +- View audit log +- System health checks +- Configuration management + +**Related:** +- [Community](../entities/community) +- [AdminWeb](admin-web) diff --git a/wiki/components/buzz-agent.md b/wiki/components/buzz-agent.md new file mode 100644 index 0000000000..c7131dcbe1 --- /dev/null +++ b/wiki/components/buzz-agent.md @@ -0,0 +1,20 @@ +# buzz-agent + +A minimal ACP-compliant agent binary. Can be used as a reference implementation or as a lightweight agent for simple automation tasks. + +**Features:** +- ACP-compliant stdio JSON-RPC communication +- Basic message send/receive +- Reaction handling +- LLM provider support (Anthropic, OpenAI, local OpenAI-compatible endpoints like OMLX/Ollama) +- Reasoning content fallback (`reasoning_content` / `reasoning` parsing for local models) +- Designed to be swapped out for more capable agents (Goost, Codex, Claude Code) + +**LLM Response Parsing:** +- In `crates/buzz-agent/src/llm.rs`, responses from OpenAI-compatible endpoints are parsed by `parse_openai` and `parse_responses`. +- When local reasoning models output generated text in `reasoning_content` while leaving `content: ""`, `buzz-agent` falls back to `reasoning` to populate turn text output. + +**Related:** +- [ACP](../concepts/acp) +- [buzz-acp](buzz-acp) +- [Agent](../entities/agent) diff --git a/wiki/components/buzz-audit.md b/wiki/components/buzz-audit.md new file mode 100644 index 0000000000..2c48d9c24a --- /dev/null +++ b/wiki/components/buzz-audit.md @@ -0,0 +1,15 @@ +# buzz-audit + +SHA-256 hash-chain tamper-evident audit log. + +**Key responsibilities:** +- Appending audit entries to the hash chain +- Single-writer serialization via `pg_advisory_lock` +- 10 audit action types (event/create/delete, channel CRUD, member add/remove, auth success/failure, rate limit) +- Querying audit history for investigations +- All audit actions are also emitted as Nostr events + +**Related:** +- [AuditLog](../concepts/audit-log) +- [buzz-db](buzz-db) +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-auth.md b/wiki/components/buzz-auth.md new file mode 100644 index 0000000000..d5668da52a --- /dev/null +++ b/wiki/components/buzz-auth.md @@ -0,0 +1,15 @@ +# buzz-auth + +Authentication, authorization, rate limiting, and scope enforcement. + +**Key responsibilities:** +- NIP-42 WebSocket challenge/response auth +- NIP-98 HTTP request auth +- Rate limiting per connection and per pubkey +- SSRF protection (`is_private_ip()` checking IPv4/IPv6 private/loopback/link-local ranges) +- Scope enforcement for admin operations + +**Related:** +- [Authentication](../concepts/authentication) +- [buzz-relay](buzz-relay) — integrates auth into connection lifecycle +- [ChannelMembership](../concepts/channel-membership) diff --git a/wiki/components/buzz-cli.md b/wiki/components/buzz-cli.md new file mode 100644 index 0000000000..0acd7fd527 --- /dev/null +++ b/wiki/components/buzz-cli.md @@ -0,0 +1,16 @@ +# buzz-cli + +Agent-first CLI tool. Designed for LLM tool calls — JSON in, JSON out. Every command accepts structured input and returns structured output. + +**Use cases:** +- Querying channel messages +- Sending messages programmatically +- Managing channels and memberships +- Triggering workflows +- Integration with agent subprocesses + +The CLI is the recommended way for agents to interact with Buzz when they need more structured control than real-time messaging provides. + +**Related:** +- [ACP](../concepts/acp) +- [Agent](../entities/agent) diff --git a/wiki/components/buzz-conformance.md b/wiki/components/buzz-conformance.md new file mode 100644 index 0000000000..9d788ff2f9 --- /dev/null +++ b/wiki/components/buzz-conformance.md @@ -0,0 +1,13 @@ +# buzz-conformance + +Multi-tenant conformance tests. Verifies that the relay behaves correctly under multi-tenant deployment, including: + +- Tenant isolation (community A cannot see community B's data) +- Auth across tenants +- Correct scoping of events, channels, and memberships by community_id +- Rate limits per tenant + +**Related:** +- [MultiTenancy](../concepts/multi-tenancy) +- [buzz-test-client](buzz-test-client) +- [Community](../entities/community) diff --git a/wiki/components/buzz-core.md b/wiki/components/buzz-core.md new file mode 100644 index 0000000000..0d62c52294 --- /dev/null +++ b/wiki/components/buzz-core.md @@ -0,0 +1,15 @@ +# buzz-core + +Core types and zero-I/O logic. The foundation crate that everything else depends on. Contains no I/O, no database access, no network — purely data structures and algorithms. + +**Contents:** +- Event type definitions (81 kinds in `kind.rs`) +- Event verification (Schnorr signature checks) +- Filter matching (NIP-01 filter evaluation) +- Core data structures (`Event`, `Filter`, `Subscription`, `Channel`, etc.) +- Constants, enums, and utility functions + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [buzz-relay](buzz-relay) — consumes core types +- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-db.md b/wiki/components/buzz-db.md new file mode 100644 index 0000000000..987e8c055c --- /dev/null +++ b/wiki/components/buzz-db.md @@ -0,0 +1,16 @@ +# buzz-db + +Postgres event store and data access layer. Uses **sqlx** for runtime-queried database access (no compile-time macros). + +**Key responsibilities:** +- Event persistence (idempotent insert by event ID) +- Event querying (by filter, by ID, by kind, by author, by channel) +- Channel CRUD +- Community CRUD +- Search queries over `search_tsv` GIN index +- Connection pooling and migration management (25 SQL migrations, auto-applied on startup) + +**Related:** +- [buzz-relay](buzz-relay) — primary consumer +- [buzz-search](buzz-search) — search queries +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-dev-mcp.md b/wiki/components/buzz-dev-mcp.md new file mode 100644 index 0000000000..5cc1aa286f --- /dev/null +++ b/wiki/components/buzz-dev-mcp.md @@ -0,0 +1,15 @@ +# buzz-dev-mcp + +MCP (Model Context Protocol) server providing shell and file-edit tools. Intended for development agents that need to interact with the filesystem. + +**Tools provided:** +- Shell command execution +- File read/write/edit operations +- Directory listing + +Uses the **rmcp** SDK (Rust MCP implementation). + +**Related:** +- [ACP](../concepts/acp) +- [buzz-acp](buzz-acp) +- [buzz-persona](buzz-persona) diff --git a/wiki/components/buzz-media.md b/wiki/components/buzz-media.md new file mode 100644 index 0000000000..d749e47867 --- /dev/null +++ b/wiki/components/buzz-media.md @@ -0,0 +1,14 @@ +# buzz-media + +Blossom protocol media storage backed by S3-compatible object storage. + +**Key responsibilities:** +- File upload via HTTP (NIP-98 auth) +- Thumbnail generation (server-side image processing) +- File serving with content-type headers and caching +- Blob deletion +- S3 configuration (endpoint, bucket, region, credentials) + +**Related:** +- [MediaStorage](../concepts/media-storage) +- [buzz-relay](buzz-relay) — serves media endpoints diff --git a/wiki/components/buzz-persona.md b/wiki/components/buzz-persona.md new file mode 100644 index 0000000000..8b62b86eaa --- /dev/null +++ b/wiki/components/buzz-persona.md @@ -0,0 +1,13 @@ +# buzz-persona + +Agent persona packs — bundles of model configuration and system prompts that define an agent's behavior and capabilities. + +Examples: +- **Ralph** — code review persona +- **Scout** — research persona + +Each persona specifies: model backend, system prompt, tool permissions, and channel memberships. + +**Related:** +- [Agent](../entities/agent) +- [buzz-acp](buzz-acp) diff --git a/wiki/components/buzz-pubsub.md b/wiki/components/buzz-pubsub.md new file mode 100644 index 0000000000..4f220a8828 --- /dev/null +++ b/wiki/components/buzz-pubsub.md @@ -0,0 +1,15 @@ +# buzz-pubsub + +Redis-backed pub/sub, presence tracking, and typing indicators. + +**Key responsibilities:** +- Cross-process event broadcasting via Redis pub/sub +- Presence tracking (who is online in which channels) +- Typing indicator propagation (agents broadcast typing too) +- Uses `deadpool-redis` for connection pooling + +In a multi-process relay deployment, events published by one process are broadcast to subscribers on all processes via Redis pub/sub. + +**Related:** +- [buzz-relay](buzz-relay) +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-push-gateway.md b/wiki/components/buzz-push-gateway.md new file mode 100644 index 0000000000..d0f280dce3 --- /dev/null +++ b/wiki/components/buzz-push-gateway.md @@ -0,0 +1,9 @@ +# buzz-push-gateway + +Push notification gateway. Bridges Nostr events to push notification services (APNs for iOS, FCM for Android). + +**Flow:** Event arrives at relay → relay notifies push gateway → gateway formats push payload → sends to APNs/FCM for offline or backgrounded clients. + +**Related:** +- [MobileClient](mobile-client) +- [DesktopClient](desktop-client) diff --git a/wiki/components/buzz-relay-mesh.md b/wiki/components/buzz-relay-mesh.md new file mode 100644 index 0000000000..8011d6000e --- /dev/null +++ b/wiki/components/buzz-relay-mesh.md @@ -0,0 +1,14 @@ +# buzz-relay-mesh + +Inter-relay mesh transport. Uses **iroh** for peer-to-peer connections between relays. + +**Purpose:** Enables Buzz Mesh shared AI compute across relay communities. Relay instances in the mesh can share computational resources for agent inference. + +**Transport features (from iroh):** +- NAT traversal +- End-to-end encryption +- Relay fallback for difficult network conditions + +**Related:** +- [BuzzMesh](../concepts/buzz-mesh) +- [Relay](../entities/relay) diff --git a/wiki/components/buzz-relay.md b/wiki/components/buzz-relay.md new file mode 100644 index 0000000000..74cc457d55 --- /dev/null +++ b/wiki/components/buzz-relay.md @@ -0,0 +1,24 @@ +# buzz-relay + +The main WebSocket relay server. Built with **Axum** on **Tokio**. Coordinates all subsystems and never exposes internal crate boundaries to clients. + +**Key responsibilities:** +- WebSocket connection lifecycle (accept, auth, recv/send/heartbeat loops, cleanup) +- Event pipeline execution (12 steps) +- HTTP endpoints: `/events`, `/query`, `/count`, `/hooks/*`, `/media/*`, `/git/*` +- Connection management via `ConnectionManager` and `SubscriptionRegistry` (DashMap) +- Community binding via `TenantContext` + +**Connection lifecycle:** +1. Community binding (Host header → TenantContext) +2. Semaphore acquire (connection limit) +3. NIP-42 challenge (`["AUTH", ""]`) +4. Authentication (client signs challenge) +5. Three concurrent tasks: `recv_loop`, `send_loop`, `heartbeat_loop` (30s ping) +6. Cleanup on disconnect + +**Related:** +- [Relay](../entities/relay) +- [EventPipeline](../concepts/event-pipeline) +- [buzz-core](buzz-core) +- [buzz-db](buzz-db) diff --git a/wiki/components/buzz-sdk.md b/wiki/components/buzz-sdk.md new file mode 100644 index 0000000000..ed937562fd --- /dev/null +++ b/wiki/components/buzz-sdk.md @@ -0,0 +1,13 @@ +# buzz-sdk + +Typed Nostr event builders for Rust. Provides a type-safe API for constructing Nostr events programmatically. + +**Features:** +- Typed event builders for common event kinds +- Automatic field validation +- Schnorr signing integration +- Filter construction helpers + +**Related:** +- [buzz-core](buzz-core) — uses core types +- [NostrEvent](../entities/nostr-event) diff --git a/wiki/components/buzz-search.md b/wiki/components/buzz-search.md new file mode 100644 index 0000000000..8dac3c946b --- /dev/null +++ b/wiki/components/buzz-search.md @@ -0,0 +1,14 @@ +# buzz-search + +Postgres full-text search (FTS) index and query support. + +**Key responsibilities:** +- Maintaining the `search_tsv` tsvector column and GIN index +- Building FTS queries from NIP-50 search filters +- Excluding privacy-sensitive event kinds from indexing +- Tenant-scoped search (by `community_id`) + +**Related:** +- [Search](../concepts/search) +- [buzz-db](buzz-db) — shares the Postgres connection +- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-test-client.md b/wiki/components/buzz-test-client.md new file mode 100644 index 0000000000..8ad778634d --- /dev/null +++ b/wiki/components/buzz-test-client.md @@ -0,0 +1,9 @@ +# buzz-test-client + +Integration test harness for the Buzz relay. Provides programmatic access to connect, authenticate, send events, and verify responses. + +Used by the integration test suite to verify relay behavior end-to-end. + +**Related:** +- [buzz-conformance](buzz-conformance) +- [buzz-relay](buzz-relay) diff --git a/wiki/components/buzz-workflow.md b/wiki/components/buzz-workflow.md new file mode 100644 index 0000000000..b194075c5f --- /dev/null +++ b/wiki/components/buzz-workflow.md @@ -0,0 +1,17 @@ +# buzz-workflow + +YAML-as-code workflow engine for channel automation. + +**Key responsibilities:** +- Loading and parsing workflow YAML files +- Evaluating trigger conditions (message_posted, reaction_added, schedule, webhook) +- Executing action chains (send_message, send_dm, set_channel_topic, add_reaction, call_webhook, request_approval, delay) +- Cron scheduler (ticks every 60 seconds) +- `evalexpr` condition evaluation with custom string/regex functions + +**Approval gates** (request_approval action): schema, API, and UI are built; executor persistence is pending. + +**Related:** +- [WorkflowEngine](../concepts/workflow-engine) +- [EventPipeline](../concepts/event-pipeline) +- [Channel](../entities/channel) diff --git a/wiki/components/buzz-ws-client.md b/wiki/components/buzz-ws-client.md new file mode 100644 index 0000000000..1a27456250 --- /dev/null +++ b/wiki/components/buzz-ws-client.md @@ -0,0 +1,13 @@ +# buzz-ws-client + +Shared WebSocket client library implementing NIP-42 authentication. Used by other components that need to connect to a relay as a client. + +**Features:** +- NIP-42 auth flow (connect, challenge, sign, verify) +- Automatic reconnection +- Subscription management +- Event sending and receiving + +**Related:** +- [buzz-acp](buzz-acp) — uses this for relay connections +- [Authentication](../concepts/authentication) diff --git a/wiki/components/desktop-client.md b/wiki/components/desktop-client.md new file mode 100644 index 0000000000..37c54b7956 --- /dev/null +++ b/wiki/components/desktop-client.md @@ -0,0 +1,25 @@ +# Desktop Client + +Native desktop application built with **Tauri 2** and **React 19**. + +**Tech stack:** +- Tauri 2 (Rust backend + webview frontend) +- React 19 with Vite +- Tailwind CSS for styling +- Biome for linting/formatting +- Playwright for E2E testing +- pnpm package manager + +**Features:** +- Stream channel real-time chat +- Forum thread browsing +- Canvas editing +- Media uploads (paste/drop/attach) +- Voice huddles (WebSocket Opus relay) +- Git repo browser (via web client embedded views) +- Agent management + +**Related:** +- [buzz-relay](buzz-relay) — backend +- [MobileClient](mobile-client) — companion app +- [WebClient](web-client) diff --git a/wiki/components/git-credential-nostr.md b/wiki/components/git-credential-nostr.md new file mode 100644 index 0000000000..6ada7e58c7 --- /dev/null +++ b/wiki/components/git-credential-nostr.md @@ -0,0 +1,14 @@ +# git-credential-nostr + +A git credential helper that authenticates `git push` and `git fetch` operations using a Nostr key (NIP-98 HTTP auth). + +**How it works:** +- Git calls the credential helper when it needs credentials for an HTTP remote +- The helper signs an auth request with the Nostr key +- The relay verifies the signature and allows the git operation +- No passwords, tokens, or SSH keys needed + +**Related:** +- [GitIntegration](../concepts/git-integration) +- [git-sign-nostr](git-sign-nostr) +- [Authentication](../concepts/authentication) diff --git a/wiki/components/git-sign-nostr.md b/wiki/components/git-sign-nostr.md new file mode 100644 index 0000000000..c13ddb8331 --- /dev/null +++ b/wiki/components/git-sign-nostr.md @@ -0,0 +1,9 @@ +# git-sign-nostr + +A tool for signing git objects (commits, tags) with a Nostr key rather than a traditional PGP key. + +**Usage:** Replaces or supplements `git commit -S` / `git tag -s`. The signature is generated using the Nostr keypair (secp256k1) instead of a PGP key. + +**Related:** +- [GitIntegration](../concepts/git-integration) +- [git-credential-nostr](git-credential-nostr) diff --git a/wiki/components/mobile-client.md b/wiki/components/mobile-client.md new file mode 100644 index 0000000000..05ea694692 --- /dev/null +++ b/wiki/components/mobile-client.md @@ -0,0 +1,21 @@ +# Mobile Client + +Mobile application for iOS and Android built with **Flutter** and **Dart**. + +**Tech stack:** +- Flutter + Dart +- Riverpod for state management +- flutter_hooks for local state +- Catppuccin theme (Latte light / Macchiato dark) + +**Features:** +- Stream channel messaging +- Forum thread browsing +- Push notifications (via buzz-push-gateway) +- Media viewing and upload +- Agent interactions + +**Related:** +- [buzz-push-gateway](buzz-push-gateway) +- [DesktopClient](desktop-client) +- [buzz-relay](buzz-relay) diff --git a/wiki/components/sprig.md b/wiki/components/sprig.md new file mode 100644 index 0000000000..1a96365d3c --- /dev/null +++ b/wiki/components/sprig.md @@ -0,0 +1,13 @@ +# sprig + +All-in-one development harness combining ACP, agent, and MCP server into a single process. Useful for local development and testing. + +**Bundles:** +- ACP harness (relay connection) +- Agent subprocess +- MCP tools (shell, file-edit) + +**Related:** +- [buzz-acp](buzz-acp) +- [buzz-agent](buzz-agent) +- [buzz-dev-mcp](buzz-dev-mcp) diff --git a/wiki/components/web-client.md b/wiki/components/web-client.md new file mode 100644 index 0000000000..5dc6e2497e --- /dev/null +++ b/wiki/components/web-client.md @@ -0,0 +1,13 @@ +# Web Client + +Browser-based web application. Primarily a **repo browser** for the NIP-34 git hosting feature, served by the relay over HTTP. + +**Tech stack:** +- React + Vite +- Tailwind CSS +- Served directly by `buzz-relay` + +**Related:** +- [DesktopClient](desktop-client) +- [GitIntegration](../concepts/git-integration) +- [buzz-relay](buzz-relay) diff --git a/wiki/concepts/acp.md b/wiki/concepts/acp.md new file mode 100644 index 0000000000..53a640a913 --- /dev/null +++ b/wiki/concepts/acp.md @@ -0,0 +1,21 @@ +# ACP (Agent Communication Protocol) + +The Agent Communication Protocol bridges Buzz relay events to AI agent subprocesses. It is the standard way for agents to connect to a Buzz community. + +**How it works:** +- `buzz-acp` spawns an agent subprocess (e.g., Goost, Codex, Claude Code) +- Agent and harness communicate over stdio JSON-RPC +- The harness translates Nostr events (messages, reactions, etc.) into calls the agent understands +- Agent actions (sending messages, reacting, etc.) are translated back into Nostr events and published to the relay + +**Architecture:** +``` +Relay ← WebSocket → ACP Harness ← stdio JSON-RPC → Agent Subprocess +``` + +The harness maintains the WebSocket connection to the relay, handles reconnection, manages subscriptions, and translates between the two protocols. + +**Related:** +- [Agent](../entities/agent) +- [buzz-acp](../components/buzz-acp) +- [buzz-agent](../components/buzz-agent) diff --git a/wiki/concepts/architecture.md b/wiki/concepts/architecture.md new file mode 100644 index 0000000000..ad9e8c4484 --- /dev/null +++ b/wiki/concepts/architecture.md @@ -0,0 +1,43 @@ +# Architecture + +Buzz is a self-hostable team workspace built on a single Nostr relay as the source of truth. + +## Layers + +``` +Clients (Desktop, Mobile, CLI, Agent) ← WebSocket / HTTP + │ + buzz-relay (Axum) + │ + ┌────┼────┐ + │ │ │ +Postgres Redis MinIO +``` + +**The relay** is the central coordinator. All subsystems (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) are orchestrated by `buzz-relay` and never talk to each other directly. Cross-subsystem coordination happens only through the relay. + +**Clients** connect via WebSocket (real-time) or HTTP (REST). Every action is a signed Nostr event. + +**Data stores** — Postgres (events, channels, search, audit, workflows), Redis (pub/sub, presence, typing indicators), MinIO/S3 (media attachments). + +## Design principles + +- **Single source of truth** — the relay event log. No P2P gossip. +- **URL is the community** — one URL = one isolated workspace. +- **Membership is the only gate** — no roles, no permissions, no ACLs beyond channel membership. +- **Events are immutable** — once written, events are never modified. +- **Everything is an event** — messages, reactions, workflow steps, git pushes, huddles. 81 event kinds. + +## Security model + +- NIP-42 for WebSocket auth (challenge-response) +- NIP-98 for HTTP auth (Nostr-signed HTTP requests) +- Channel membership is the only access control +- Hash-chain audit log for tamper-evident record +- SSRF protection via `is_private_ip()` checks + +**Related:** +- [Relay](../entities/relay) +- [EventPipeline](event-pipeline) +- [MultiTenancy](multi-tenancy) +- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/audit-log.md b/wiki/concepts/audit-log.md new file mode 100644 index 0000000000..5eaa696d3e --- /dev/null +++ b/wiki/concepts/audit-log.md @@ -0,0 +1,16 @@ +# Audit Log + +Buzz maintains a tamper-evident audit trail using a SHA-256 hash chain. + +- Each audit entry contains: timestamp, action type, actor pubkey, target, previous hash, and metadata +- The chain is single-writer — serialized via `pg_advisory_lock` to prevent concurrent writes +- 10 audit action types: `EventCreated`, `EventDeleted`, `ChannelCreated`, `ChannelUpdated`, `ChannelDeleted`, `MemberAdded`, `MemberRemoved`, `AuthSuccess`, `AuthFailure`, `RateLimitExceeded` +- The hash chain ensures that modifying any historical entry would invalidate all subsequent hashes +- All audit actions are also Nostr events, making them visible in the relay's event stream + +**Source:** `buzz-audit` crate + +**Related:** +- [buzz-audit](../components/buzz-audit) +- [EventPipeline](event-pipeline) +- [Architecture](architecture) diff --git a/wiki/concepts/authentication.md b/wiki/concepts/authentication.md new file mode 100644 index 0000000000..f364ab32f9 --- /dev/null +++ b/wiki/concepts/authentication.md @@ -0,0 +1,22 @@ +# Authentication + +Buzz uses Nostr's cryptographic identity model. Authentication is based on Schnorr signatures over the secp256k1 curve. + +## NIP-42 (WebSocket) + +The relay issues a random challenge string on connection. The client signs it with their Nostr private key and sends it back. The relay verifies the signature against the advertised pubkey. + +**Flow:** Connect → `["AUTH", ""]` → client signs → `["AUTH", {"event": ...}]` → verified + +## NIP-98 (HTTP) + +HTTP requests include a Nostr-signed authorization header. The relay verifies the signature against the pubkey. Used for REST endpoints (media upload, git operations, admin API). + +## Rate limiting + +The `buzz-auth` crate enforces rate limits per connection and per pubkey, with separate limits for different event kinds. + +**Related:** +- [buzz-auth](../components/buzz-auth) +- [NostrEvent](../entities/nostr-event) +- [ChannelMembership](channel-membership) diff --git a/wiki/concepts/buzz-mesh.md b/wiki/concepts/buzz-mesh.md new file mode 100644 index 0000000000..0b6fe64e0c --- /dev/null +++ b/wiki/concepts/buzz-mesh.md @@ -0,0 +1,14 @@ +# Buzz Mesh + +Buzz Mesh enables relay communities to pool opted-in member hardware into shared AI compute. Agents consume this compute via a local OpenAI-compatible endpoint. + +**Transport:** Uses **iroh** for inter-relay mesh transport — a peer-to-peer networking library with NAT traversal, end-to-end encryption, and relay fallback. + +**Runtime:** Uses **llama.cpp** for native on-device LLM inference, or forwards to external providers. + +**Design goal:** Shared AI compute across a community, reducing reliance on external API providers and keeping inference local. + +**Related:** +- [Agent](../entities/agent) +- [buzz-relay-mesh](../components/buzz-relay-mesh) +- [ACP](acp) diff --git a/wiki/concepts/channel-membership.md b/wiki/concepts/channel-membership.md new file mode 100644 index 0000000000..23bba3b78e --- /dev/null +++ b/wiki/concepts/channel-membership.md @@ -0,0 +1,14 @@ +# Channel Membership + +Channel membership is the only access control mechanism in Buzz. There are no roles, permissions, or ACLs — if you are a member of a channel, you can read and write to it. + +This is a deliberate design choice that simplifies the security model: the event pipeline has exactly one access control check at step 6, and it's a simple membership lookup. + +- Membership is scoped to a [Community](../entities/community) +- Agents have their own memberships, managed independently of human members +- Membership changes are themselves Nostr events (auditable) + +**Related:** +- [Channel](../entities/channel) +- [EventPipeline](event-pipeline) +- [Authentication](authentication) diff --git a/wiki/concepts/event-pipeline.md b/wiki/concepts/event-pipeline.md new file mode 100644 index 0000000000..1a0706f0b2 --- /dev/null +++ b/wiki/concepts/event-pipeline.md @@ -0,0 +1,21 @@ +# Event Pipeline + +Every Nostr event in Buzz goes through a 12-step pipeline when received by the relay: + +1. **Auth check** — verify the client is authenticated (NIP-42) +2. **Pubkey match** — ensure the event pubkey matches the authenticated client +3. **Reject reserved kinds** — prevent spoofing of internal event types (KIND_AUTH) +4. **Ephemeral route** — ephemeral events are broadcast but not persisted +5. **Schnorr verify** — cryptographic signature verification +6. **Membership check** — verify sender is a member of the target channel +7. **DB insert** — idempotent write to Postgres (event ID is the dedup key) +8. **Redis publish** — publish to Redis pub/sub for cross-process notification +9. **Fan-out** — send event to all subscribed WebSocket connections +10. **Search index** — update Postgres FTS search index +11. **Audit log** — append to the hash-chain audit trail +12. **Workflow trigger** — evaluate workflow conditions and execute matching actions + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [Relay](../entities/relay) +- [buzz-relay](../components/buzz-relay) diff --git a/wiki/concepts/git-integration.md b/wiki/concepts/git-integration.md new file mode 100644 index 0000000000..0bf7e1b5bd --- /dev/null +++ b/wiki/concepts/git-integration.md @@ -0,0 +1,21 @@ +# Git Integration + +Buzz implements NIP-34 for git hosting, plus additional tools for Nostr-signed git operations. + +## NIP-34 Git Hosting + +The relay hosts bare git repos over smart HTTP. Repos are accessed via the relay's HTTP endpoints, authenticated with NIP-98. + +## Branch-as-Room + +Creating a feature branch automatically creates a channel where patches, CI results, reviews, and merge decisions live. This ties git workflow directly into the chat workspace. + +## Tools + +- **git-sign-nostr** — sign git commits, tags, and other objects with a Nostr key +- **git-credential-nostr** — git credential helper that authenticates push/fetch using Nostr keys + +**Related:** +- [git-sign-nostr](../components/git-sign-nostr) +- [git-credential-nostr](../components/git-credential-nostr) +- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/media-storage.md b/wiki/concepts/media-storage.md new file mode 100644 index 0000000000..da1a5f82a4 --- /dev/null +++ b/wiki/concepts/media-storage.md @@ -0,0 +1,15 @@ +# Media Storage + +Buzz uses the Blossom protocol for media uploads and storage, backed by S3-compatible object storage (MinIO in development, any S3 provider in production). + +- Users paste, drag, or attach files in channels +- Files are uploaded to S3 via the relay's HTTP endpoints (NIP-98 auth) +- The relay generates server-side thumbnails for images +- Files are served with content-type headers and caching +- Media events are Nostr events with references to the stored blob + +**Configuration:** S3 endpoint, bucket, region, access key, and secret key via environment variables. + +**Related:** +- [buzz-media](../components/buzz-media) +- [Relay](../entities/relay) diff --git a/wiki/concepts/multi-tenancy.md b/wiki/concepts/multi-tenancy.md new file mode 100644 index 0000000000..921ddb16a6 --- /dev/null +++ b/wiki/concepts/multi-tenancy.md @@ -0,0 +1,19 @@ +# Multi-Tenancy + +Buzz supports multi-tenant deployments where multiple communities share the same Postgres/Redis/MinIO infrastructure while maintaining strict isolation. + +## Isolation Model + +- **Community** is the tenant boundary — one workspace, one URL, one isolated world +- All data is scoped by `community_id` at the database level +- The relay extracts the community from the Host header on connection +- `TenantContext` is established before any handler runs + +## Formal Verification + +The multi-tenant relay behavior has been mechanized in **TLA+** for correctness verification. Authorization properties are verified in **Tamarin** (a security protocol verifier). These formal specs live in `docs/formal/`. + +**Related:** +- [Community](../entities/community) +- [Architecture](architecture) +- [buzz-conformance](../components/buzz-conformance) diff --git a/wiki/concepts/nostr-protocol.md b/wiki/concepts/nostr-protocol.md new file mode 100644 index 0000000000..f3423986da --- /dev/null +++ b/wiki/concepts/nostr-protocol.md @@ -0,0 +1,25 @@ +# Nostr Protocol + +Buzz is built on the Nostr protocol — an open, decentralized protocol for signed events. + +## Standard Compliance + +- Wire-compatible with NIP-01 (event format, relay-client protocol) +- NIP-42 (authentication via challenge-response) +- NIP-50 (search) +- NIP-98 (HTTP auth) +- NIP-34 (git integration) + +## Custom Extensions + +Buzz extends Nostr with 81 event kinds in the 40000-49999 custom range, covering: stream messages, forum posts, DMs, canvases, reactions, workflows, git operations, media, huddles, typing indicators, and admin actions. + +## Key Differences from P2P Nostr + +Unlike typical Nostr relays, Buzz is **not P2P**. There is no gossip or replication between relays. The relay is the single source of truth. This is intentional — Buzz is a workspace, not a decentralized social network. The Nostr protocol is used for its cryptographic identity and event model, not for federation. + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [Authentication](authentication) +- [GitIntegration](git-integration) +- [EventPipeline](event-pipeline) diff --git a/wiki/concepts/search.md b/wiki/concepts/search.md new file mode 100644 index 0000000000..cddc956430 --- /dev/null +++ b/wiki/concepts/search.md @@ -0,0 +1,16 @@ +# Search + +Buzz uses Postgres full-text search (FTS) for searching events. There is no external search service — all search is handled within Postgres. + +- Events are indexed into a `search_tsv` column (a Postgres `tsvector`) via a GIN index +- Search supports NIP-50, the Nostr standard search protocol +- Queries come in via the relay's `REQ` handler with a search filter +- Privacy-sensitive event kinds are excluded at the storage level (not indexed) +- Search is scoped by community (tenant isolation) + +**Implementation:** `buzz-search` crate handles indexing and query building over the `search_tsv` GIN index. + +**Related:** +- [buzz-search](../components/buzz-search) +- [NostrProtocol](nostr-protocol) +- [MultiTenancy](multi-tenancy) diff --git a/wiki/concepts/workflow-engine.md b/wiki/concepts/workflow-engine.md new file mode 100644 index 0000000000..2d78319b31 --- /dev/null +++ b/wiki/concepts/workflow-engine.md @@ -0,0 +1,35 @@ +# Workflow Engine + +Buzz has a YAML-as-code workflow engine for channel automation. Workflows are defined in YAML files, scoped to a channel, and executed by `buzz-workflow`. + +## Triggers + +| Trigger | Description | +|---|---| +| `message_posted` | Fires when a message is posted matching a text pattern | +| `reaction_added` | Fires when a reaction is added matching an emoji | +| `schedule` | Cron-based scheduled trigger (ticks every 60s) | +| `webhook` | External HTTP webhook trigger | + +## Actions + +| Action | Description | +|---|---| +| `send_message` | Post a message to the channel | +| `send_dm` | Send a direct message to a user | +| `set_channel_topic` | Update the channel topic | +| `add_reaction` | Add an emoji reaction | +| `call_webhook` | Call an external webhook URL | +| `request_approval` | Request human approval before proceeding | +| `delay` | Wait before executing next action | + +## Conditions + +Conditions are expressions evaluated with `evalexpr`, with custom functions: `str_contains`, `str_starts_with`, `str_ends_with`, `matches_regex`, and more. + +**Approval gates** are partially built (schema, API, and UI exist but executor persistence is pending). + +**Related:** +- [buzz-workflow](../components/buzz-workflow) +- [Channel](../entities/channel) +- [EventPipeline](event-pipeline) diff --git a/wiki/entities/agent.md b/wiki/entities/agent.md new file mode 100644 index 0000000000..68e1c1ceef --- /dev/null +++ b/wiki/entities/agent.md @@ -0,0 +1,22 @@ +# Agent + +AI agents are first-class team members in Buzz. They have their own Nostr keypairs, channel memberships, and audit trail — exactly like human teammates, just different cryptographic identities. + +**How agents connect:** +- Agents connect via the **ACP (Agent Communication Protocol)** harness (`buzz-acp`) +- ACP bridges Nostr relay events to AI agent subprocesses over stdio JSON-RPC +- Agents use tools like Goost, Codex, Claude Code as their AI backend +- Agent teams bundle a persona (model + system prompt), e.g. Ralph for code review, Scout for research + +**Agent capabilities:** +- Send and receive messages in channels +- Participate in voice huddles via STT/TTS +- Broadcast typing indicators +- Trigger and respond to workflows +- Use `buzz-cli` for JSON-in/JSON-out interaction + +**Related:** +- [ACP](../concepts/acp) — the protocol that connects agents +- [buzz-acp](../components/buzz-acp) — ACP harness crate +- [buzz-agent](../components/buzz-agent) — minimal agent binary +- [buzz-persona](../components/buzz-persona) — persona packs diff --git a/wiki/entities/channel.md b/wiki/entities/channel.md new file mode 100644 index 0000000000..cca0c2865d --- /dev/null +++ b/wiki/entities/channel.md @@ -0,0 +1,19 @@ +# Channel + +Channels are communication spaces within a [Community](community). Buzz supports three channel types: + +## Stream +Slack-like real-time chat. Mandatory topics on creation. Supports sub-replies (thread-like) and has zero-notification default to reduce noise. + +## Forum +Discourse-like async long-form posts. Flat replies. Designed for asynchronous discussion rather than real-time chat. + +## Direct Messages +1:1 and group DMs (up to 9 participants). Private communication outside of stream/forum channels. + +**Channel membership is the only access control gate** in Buzz. If you're a member of a channel, you can read and write to it. There are no roles, permissions, or ACLs beyond membership. + +**Related:** +- [ChannelMembership](../concepts/channel-membership) — access control model +- [Community](community) — parent tenant +- [NostrEvent](nostr-event) — every channel action is an event diff --git a/wiki/entities/community.md b/wiki/entities/community.md new file mode 100644 index 0000000000..ade52f5fac --- /dev/null +++ b/wiki/entities/community.md @@ -0,0 +1,14 @@ +# Community + +A community is a workspace — the tenant boundary in Buzz. One URL, one isolated world. Multi-tenant deployments share Postgres/Redis/MinIO infrastructure but scope all data by `community_id`. + +- The URL is authoritative: the host header determines which community a request belongs to +- A community has its own channels, members (human and agent), workflows, audit log, and git repos +- Communities cannot see each other's data + +**Connection flow:** A client connects via WebSocket → the relay extracts the community from the Host header → establishes `TenantContext` → enforces connection limits per community → authenticates the client. + +**Related:** +- [Relay](relay) — serving a community +- [MultiTenancy](../concepts/multi-tenancy) — isolation model +- [Channel](channel) — communication spaces within a community diff --git a/wiki/entities/nostr-event.md b/wiki/entities/nostr-event.md new file mode 100644 index 0000000000..0f0f6bd915 --- /dev/null +++ b/wiki/entities/nostr-event.md @@ -0,0 +1,15 @@ +# Nostr Event + +The atomic unit of all activity in Buzz. Every action — a chat message, a reaction, a workflow step, a canvas update, a git push, a huddle voice event — is a cryptographically signed Nostr event. + +Events follow the NIP-01 standard and are extended with custom kinds in the 40000-49999 range. Buzz defines **81 event kinds** across stream channels, forums, DMs, canvases, reactions, workflows, git, media, huddles, and admin operations. + +**Event pipeline (12 steps):** +1. Auth check → 2. Pubkey match → 3. Reject reserved kinds → 4. Ephemeral route → 5. Schnorr verify → 6. Membership check → 7. DB insert (idempotent) → 8. Redis publish → 9. Fan-out to subscribers → 10. Search index → 11. Audit log → 12. Workflow trigger + +**Source:** `crates/buzz-core/src/kind.rs` for the full kind list. + +**Related:** +- [EventPipeline](../concepts/event-pipeline) — the 12-step lifecycle +- [Relay](relay) — processes all events +- [Authentication](../concepts/authentication) — NIP-42/NIP-98 signing diff --git a/wiki/entities/relay.md b/wiki/entities/relay.md new file mode 100644 index 0000000000..c6d4d124ba --- /dev/null +++ b/wiki/entities/relay.md @@ -0,0 +1,16 @@ +# Relay + +The Nostr relay server is the single source of truth for a Buzz community. All reads and writes — chat messages, reactions, workflow triggers, canvas updates, git pushes, huddle events — flow through it as signed Nostr events. + +Built with **Axum** on **Tokio**, the relay handles WebSocket connections, HTTP requests, and coordinates all subsystems. It imports all service crates (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) and orchestrates cross-subsystem coordination. + +**Key traits:** +- Single source of truth — no P2P gossip or replication +- Every action is a signed Nostr event +- All subsystems are coordinated through the relay, never directly between crates +- URL is authoritative — the relay's URL defines the community + +**Related:** +- [Community](community) — tenant boundary +- [EventPipeline](../concepts/event-pipeline) — event lifecycle +- [buzz-relay](../components/buzz-relay) — implementation crate diff --git a/wiki/index.md b/wiki/index.md new file mode 100644 index 0000000000..f2ec1332e6 --- /dev/null +++ b/wiki/index.md @@ -0,0 +1,66 @@ +# Index + +Catalog of all wiki pages, organized by category. + +## Entities + +- [Relay](entities/relay) — the Nostr relay server; the single source of truth for a community +- [Community](entities/community) — a workspace; one URL, one isolated tenant +- [Agent](entities/agent) — an AI agent as a first-class team member with its own Nostr keypair +- [Channel](entities/channel) — stream, forum, and DM communication spaces +- [NostrEvent](entities/nostr-event) — the atomic unit of all activity; a cryptographically signed event + +## Concepts + +- [Architecture](concepts/architecture) — system overview, layers, and design principles +- [EventPipeline](concepts/event-pipeline) — the 12-step lifecycle of an event from receipt to fan-out +- [Authentication](concepts/authentication) — NIP-42 challenge-response and NIP-98 HTTP auth +- [ChannelMembership](concepts/channel-membership) — access control model (membership is the only gate) +- [WorkflowEngine](concepts/workflow-engine) — YAML-as-code channel automation with triggers and actions +- [AuditLog](concepts/audit-log) — SHA-256 hash-chain tamper-evident audit trail +- [BuzzMesh](concepts/buzz-mesh) — inter-relay mesh for pooled AI compute +- [ACP](concepts/acp) — Agent Communication Protocol bridging Nostr events to agent subprocesses +- [GitIntegration](concepts/git-integration) — NIP-34 git hosting, signing, and branch-as-room +- [MediaStorage](concepts/media-storage) — Blossom protocol media uploads on S3/MinIO +- [Search](concepts/search) — Postgres FTS full-text search over events +- [MultiTenancy](concepts/multi-tenancy) — community isolation model and formal verification +- [NostrProtocol](concepts/nostr-protocol) — Nostr wire protocol and Buzz's custom event kinds + +## Components + +- [buzz-relay](components/buzz-relay) — main WebSocket relay server (Axum) +- [buzz-core](components/buzz-core) — core types, event verification, filter matching (zero I/O) +- [buzz-db](components/buzz-db) — Postgres event store and data access layer +- [buzz-auth](components/buzz-auth) — auth, rate limiting, and scope enforcement +- [buzz-pubsub](components/buzz-pubsub) — Redis pub/sub, presence, typing indicators +- [buzz-search](components/buzz-search) — Postgres FTS search index +- [buzz-audit](components/buzz-audit) — hash-chain audit log +- [buzz-media](components/buzz-media) — Blossom/S3 media storage +- [buzz-workflow](components/buzz-workflow) — YAML workflow engine +- [buzz-acp](components/buzz-acp) — ACP harness for agent subprocess orchestration +- [buzz-agent](components/buzz-agent) — minimal ACP-compliant agent binary +- [buzz-dev-mcp](components/buzz-dev-mcp) — MCP server providing shell and file-edit tools +- [buzz-persona](components/buzz-persona) — agent persona packs (model + system prompt) +- [buzz-cli](components/buzz-cli) — agent-first CLI (JSON in/out) +- [buzz-sdk](components/buzz-sdk) — typed Nostr event builders +- [buzz-admin](components/buzz-admin) — operator CLI for relay administration +- [buzz-ws-client](components/buzz-ws-client) — shared WebSocket client (NIP-42) +- [buzz-test-client](components/buzz-test-client) — integration test harness +- [buzz-conformance](components/buzz-conformance) — multi-tenant conformance tests +- [buzz-push-gateway](components/buzz-push-gateway) — push notification gateway +- [buzz-relay-mesh](components/buzz-relay-mesh) — iroh-based inter-relay mesh transport +- [git-sign-nostr](components/git-sign-nostr) — sign git objects with a Nostr key +- [git-credential-nostr](components/git-credential-nostr) — git credential helper for Nostr auth +- [sprig](components/sprig) — all-in-one harness (ACP + agent + MCP) +- [DesktopClient](components/desktop-client) — Tauri 2 + React 19 native desktop app +- [MobileClient](components/mobile-client) — Flutter mobile app (iOS + Android) +- [WebClient](components/web-client) — browser-based web client (repo browser) +- [AdminWeb](components/admin-web) — admin dashboard + +## Operations + +- [DevelopmentSetup](operations/development-setup) — local dev environment setup with Docker Compose +- [Deployment](operations/deployment) — production deployment with Helm and Docker Compose +- [Configuration](operations/configuration) — environment variables and community config +- [CLIReference](operations/cli-reference) — just commands and common dev workflows +- [Troubleshooting](operations/troubleshooting) — common issues and fixes diff --git a/wiki/log.md b/wiki/log.md new file mode 100644 index 0000000000..2223b00be6 --- /dev/null +++ b/wiki/log.md @@ -0,0 +1,47 @@ +# Log + +Chronological record of wiki changes. Each entry uses the format: +`## [YYYY-MM-DD] type | Title` + +- **ingest** — a new source was read and integrated +- **query** — a question was answered and the result was filed +- **lint** — a health check was performed +- **update** — pages were revised or created outside of ingest/query + +--- + +## [2026-07-27] ingest | Initial Wiki Creation + +Created the initial wiki for the Buzz project based on project source code and documentation. + +**Pages created:** +- `CLAUDE.md` — schema, conventions, and workflows +- `index.md` — catalog of all pages +- `log.md` — this file +- `entities/relay.md`, `entities/community.md`, `entities/agent.md`, `entities/channel.md`, `entities/nostr-event.md` +- `concepts/architecture.md`, `concepts/event-pipeline.md`, `concepts/authentication.md`, `concepts/channel-membership.md`, `concepts/workflow-engine.md`, `concepts/audit-log.md`, `concepts/buzz-mesh.md`, `concepts/acp.md`, `concepts/git-integration.md`, `concepts/media-storage.md`, `concepts/search.md`, `concepts/multi-tenancy.md`, `concepts/nostr-protocol.md` +- `components/buzz-relay.md`, `components/buzz-core.md`, `components/buzz-db.md`, `components/buzz-auth.md`, `components/buzz-pubsub.md`, `components/buzz-search.md`, `components/buzz-audit.md`, `components/buzz-media.md`, `components/buzz-workflow.md`, `components/buzz-acp.md`, `components/buzz-agent.md`, `components/buzz-dev-mcp.md`, `components/buzz-persona.md`, `components/buzz-cli.md`, `components/buzz-sdk.md`, `components/buzz-admin.md`, `components/buzz-ws-client.md`, `components/buzz-test-client.md`, `components/buzz-conformance.md`, `components/buzz-push-gateway.md`, `components/buzz-relay-mesh.md`, `components/git-sign-nostr.md`, `components/git-credential-nostr.md`, `components/sprig.md`, `components/desktop-client.md`, `components/mobile-client.md`, `components/web-client.md`, `components/admin-web.md` +- `operations/development-setup.md`, `operations/deployment.md`, `operations/configuration.md`, `operations/cli-reference.md` + +## [2026-07-27] update | Added Troubleshooting Page + +Created `operations/troubleshooting.md` covering common issues: 521 errors when connecting to cloud relays, port conflicts, rate limiting, Docker health, and event rejection. Updated `index.md` to link the new page. + +## [2026-07-27] query | Agent Shows Response Bubble But Doesn't Publish + +Investigated agent response not publishing. Two root causes found: +1. Agent was connected to `wss://milimo.communities.buzz.xyz` instead of `ws://localhost:3000` — hardcoded in `managed-agents.json`. Responses went to the wrong relay. +2. Even on the correct relay, the LLM (Qwen3.6-35B-A3B-bf16 via OMLX) returns text via ACP `agent_message_chunk` but doesn't call the `shell` tool to run `buzz messages send`. The harness does not auto-publish agent output. + +Updated `operations/troubleshooting.md` with both causes and fixes. + +## [2026-07-28] update | Root Causes Resolved — Wiki Updated + +Applied fixes from investigation: +- **Local LLM reasoning content**: `buzz-agent` now handles `reasoning_content` field from OpenAI-compatible endpoints (local models), falling back to `content` when `reasoning_content` is absent. +- **Fallback turn text publishing**: `buzz-acp` now accumulates `agent_message_chunk` text during a turn and publishes a `kind: 9` channel message on `StopReason::EndTurn` if no `send_message` tool call was made. Enables non-tool-calling models to participate. +- **Response sanitization**: `clean_agent_text_response` strips pseudo-tool JSON blocks (`` ```json ... ``` ``) and model tokens (`<|tool_call|>`, `<|im_end|>`) from generated text. +- **Owner pubkey seeding**: `agent_owner_pubkey` seeded in Postgres `users` table across all local dev community hosts (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`). +- **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. + +Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. diff --git a/wiki/operations/cli-reference.md b/wiki/operations/cli-reference.md new file mode 100644 index 0000000000..a17a2c96d6 --- /dev/null +++ b/wiki/operations/cli-reference.md @@ -0,0 +1,55 @@ +# CLI Reference + +## just (task runner) + +The `Justfile` at the project root provides common development commands. + +### Development + +| Command | Description | +|---|---| +| `just dev` | Start full dev stack (Docker Compose) | +| `just dev-reset` | Destroy and recreate dev stack | +| `just seed-local-community` | Seed sample data | +| `just desktop` | Launch desktop client dev server | +| `just mobile` | Launch Flutter dev server | + +### Testing + +| Command | Description | +|---|---| +| `just test-all` | Run all tests | +| `just test-rust` | Run Rust tests | +| `just test-desktop` | Run desktop E2E tests (Playwright) | +| `just test-mobile` | Run Flutter tests | + +### Building + +| Command | Description | +|---|---| +| `just build-relay` | Build relay binary | +| `just build-desktop` | Build desktop app | +| `just build-mobile` | Build mobile app | +| `just docker` | Build Docker images | + +## cargo + +Standard Cargo commands work. Key workspace crates: + +```bash +cargo build -p buzz-relay +cargo test -p buzz-conformance +cargo clippy -p buzz-core +``` + +## Hermit + +Hermit manages toolchain versions. Activate automatically by `cd`-ing into `buzz/`, or manually: + +```bash +. bin/activate-hermit +``` + +**Related:** +- [DevelopmentSetup](development-setup) +- [Deployment](deployment) diff --git a/wiki/operations/configuration.md b/wiki/operations/configuration.md new file mode 100644 index 0000000000..5d34b98a68 --- /dev/null +++ b/wiki/operations/configuration.md @@ -0,0 +1,35 @@ +# Configuration + +Buzz is configured primarily through environment variables. + +## Core + +| Variable | Description | +|---|---| +| `DATABASE_URL` | Postgres connection string | +| `REDIS_URL` | Redis connection string | +| `RELAY_URL` | Public URL of the relay | +| `RELAY_PORT` | Listen port (default: 8080) | + +## Media (S3/MinIO) + +| Variable | Description | +|---|---| +| `S3_ENDPOINT` | S3-compatible endpoint URL | +| `S3_BUCKET` | Bucket name for media storage | +| `S3_REGION` | AWS region (default: us-east-1) | +| `S3_ACCESS_KEY` | Access key | +| `S3_SECRET_KEY` | Secret key | + +## Auth + +| Variable | Description | +|---|---| +| `RATE_LIMIT_MESSAGES` | Messages per minute per connection | +| `RATE_LIMIT_CONNECTIONS` | Max connections per IP | + +See `.env.example` for the full list. + +**Related:** +- [DevelopmentSetup](development-setup) +- [Deployment](deployment) diff --git a/wiki/operations/deployment.md b/wiki/operations/deployment.md new file mode 100644 index 0000000000..09f974a018 --- /dev/null +++ b/wiki/operations/deployment.md @@ -0,0 +1,30 @@ +# Deployment + +## Docker Compose (Production) + +A production-ready Docker Compose bundle is available in `deploy/compose/`. It includes: +- `buzz-relay` (with all service crates compiled in) +- PostgreSQL 17 +- Redis 7 +- MinIO (S3-compatible storage) +- Prometheus (metrics) + +## Helm (Kubernetes) + +Helm charts are in `deploy/charts/`. Suitable for production multi-tenant deployments. + +## Requirements + +- PostgreSQL 17 +- Redis 7 +- S3-compatible object storage (MinIO, AWS S3, etc.) +- TLS termination (reverse proxy with Let's Encrypt) + +## Configuration + +All configuration is via environment variables. See [Configuration](configuration) for the full list. + +**Related:** +- [DevelopmentSetup](development-setup) +- [Configuration](configuration) +- [MultiTenancy](../concepts/multi-tenancy) diff --git a/wiki/operations/development-setup.md b/wiki/operations/development-setup.md new file mode 100644 index 0000000000..f06428373f --- /dev/null +++ b/wiki/operations/development-setup.md @@ -0,0 +1,48 @@ +# Development Setup + +## Prerequisites + +- **Hermit** (pinned toolchain manager) — activates automatically in the `buzz/` directory +- **Docker Desktop** — for Postgres, Redis, and MinIO containers +- Rust, Node, pnpm, Flutter — all managed by Hermit + +## Quick start + +```bash +# From the buzz/ directory +just dev +``` + +This starts the full stack via Docker Compose: Postgres 17, Redis 7, MinIO, and the relay. + +## Key commands + +| Command | Description | +|---|---| +| `just dev` | Start full dev environment | +| `just dev-reset` | Reset dev environment (destroy data) | +| `cargo build -p buzz-relay` | Build the relay | +| `cargo test -p buzz-conformance` | Run conformance tests | +| `just desktop` | Start the desktop client | +| `just mobile` | Start the mobile client | + +## Environment + +Copy `.env.example` to `.env` and configure. Key variables: +- `DATABASE_URL` — Postgres connection string +- `REDIS_URL` — Redis connection string +- `S3_ENDPOINT` — MinIO/S3 endpoint +- `RELAY_URL` — the relay's external URL + +## Seeding + +```bash +just seed-local-community +``` + +Creates a local community with sample channels and test data. + +**Related:** +- [Deployment](deployment) +- [Configuration](configuration) +- [CLIReference](cli-reference) diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md new file mode 100644 index 0000000000..9d5c622bc8 --- /dev/null +++ b/wiki/operations/troubleshooting.md @@ -0,0 +1,189 @@ +# Troubleshooting + +Common issues when running Buzz locally. + +## "Can't reach the relay" / "relay returned 521 Unknown Status Code" + +521 is a [Cloudflare-specific status code](https://en.wikipedia.org/wiki/HTTP_521) meaning Cloudflare's edge can't reach the origin server. This happens when the desktop app is trying to connect to a Cloudflare-proxied URL (e.g. `wss://buzz.block.builderlab.xyz` or a staging/production relay) that is down or unreachable. + +**Fix:** Connect to your local relay instead — use `ws://localhost:3000` as the relay URL. + +If the app cached a previous cloud URL, clear the stored state: + +```bash +just desktop-standalone fresh=1 +``` + +Then start fresh: + +```bash +just dev +``` + +The error is generated in `desktop/src-tauri/src/relay.rs:295` (HTTP fallback) and classified in `desktop/src/shared/lib/relayError.ts` (checks for `relay unreachable:` prefix — 521 doesn't match it, so it's treated as an application error rather than a network error). + +## "relay unreachable: could not connect to relay" + +The relay process isn't running or isn't reachable on the expected port. + +**Checks:** + +```bash +# Is the relay binary running? +ps aux | grep buzz-relay + +# Is it listening on the right port? +lsof -i :3000 + +# Are Docker services up? +docker compose ps + +# Check health endpoints +curl http://localhost:8080/_liveness +curl http://localhost:8080/_readiness +``` + +**Fix:** Start the relay: + +```bash +just relay +``` + +## Port already in use + +``` +Error: relay port 3000 is already in use; refusing to launch desktop against a stale relay. +``` + +A previous relay instance is still running. Kill it: + +```bash +pkill buzz-relay +just dev +``` + +## "relay rate-limited: retry in Ns" + +The relay's Redis-backed rate limiter has been hit. Wait the indicated time and retry. Rate limits are configured via `BUZZ_RATE_LIMIT_*` env vars in `.env`. + +## Docker services not healthy + +If `docker compose ps` shows `unhealthy`: + +```bash +# Check individual service logs +docker compose logs postgres +docker compose logs redis + +# Full reset +just reset +``` + +## Relay starts but immediately exits + +Check the relay logs for database connection errors. Ensure Postgres is healthy and `DATABASE_URL` in `.env` is correct (default: `postgres://buzz:buzz_dev@localhost:5432/buzz`). + +## "No auth challenge received" + +The WebSocket connection succeeded but the relay didn't send a NIP-42 AUTH challenge. This usually means the relay is not configured to require auth (`auth_required: true` in the NIP-11 response). Check `RELAY_URL` in `.env` points to the correct relay. + +## "Event rejected by relay" + +The relay rejected a published event. Possible causes: + +- Event signature verification failed +- Sender is not a member of the target channel +- Event kind is not allowed +- Rate limit exceeded + +Check the relay logs for details (`RUST_LOG=debug` is set in `.env`). + +## Agent shows response text in a "bubble" but never publishes to the channel + +The agent generates text (GPU spikes, LLM runs, text appears in a UI bubble) but the message never shows up in the channel timeline. + +### Cause 1: Agent connected to the wrong relay + +The agent's `managed-agents.json` may have a hardcoded `relay_url` pointing to a different relay than the one you're using. Check: + +```bash +cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json +``` + +If you see `relay_url` set to a remote URL (e.g. `wss://milimo.communities.buzz.xyz`) instead of `ws://localhost:3000`, the agent publishes responses to the wrong relay. + +**Fix:** Edit the file to replace the remote URL with your local relay: + +```bash +sed -i '' 's|wss://milimo.communities.buzz.xyz|ws://localhost:3000|g' \ + ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json +``` + +Then kill the agent processes — the desktop app will respawn them with the correct URL: + +```bash +pkill -f buzz-acp +pkill -f buzz-agent +pkill -f buzz-dev-mcp +``` + +### Cause 2: LLM returns text but doesn't call the publish tool + +Buzz has two separate rendering paths for agent content: + +| Aspect | Session Transcript (ACP Panel) | Channel Timeline | +|---|---|---| +| Event source | Kind 24200 observer frames (ACP protocol) | Kind 9 / 40002 Nostr events | +| Agent text | `agent_message_chunk` → transcript item | Only if agent publishes explicitly | +| Where shown | Side panel (click "View activity") | Main channel content area | + +The agent generates text and sends it via ACP's `agent_message_chunk` update — this renders in the session transcript panel as a "bubble." But the harness (`buzz-acp`) does **not** auto-publish agent output to the relay. At `crates/buzz-acp/src/lib.rs:3232`, `PromptOutcome::Ok(_)` just returns the agent to the pool without sending anything. + +The agent must **explicitly publish** its response by calling one of: +1. `buzz messages send` via the MCP `shell` tool (`buzz-dev-mcp` provides this) +2. The `send_message` ACP tool (dedicated agent tool) +3. The desktop Tauri IPC `send_managed_agent_channel_message` handler + +To verify if the agent is calling the tool, check the `buzz-dev-mcp` logs: + +```bash +cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/logs/*.log | grep -i 'shell\|tool_call\|buzz messages' +``` + +### Cause 3: Local LLM returns reasoning in `reasoning_content` or lacks native tool-calling + +When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4-bit/8-bit models like `gemma-4-12b`): + +1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. +2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. +3. **Cleaning Pseudo-tool Code Blocks**: `clean_agent_text_response` strips trailing ` ```json ... ``` ` parameter blocks and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. + +## "Agent; owner unavailable" badge next to agent name + +The desktop UI displays **"owner unavailable"** when the agent user profile in the Postgres database lacks an `agent_owner_pubkey` mapping to the human owner. + +**Fix:** Ensure the active agent pubkeys are inserted into the `users` table with `agent_owner_pubkey` set to the owner's pubkey across all active community host entries (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`): + +```sql +INSERT INTO users (community_id, pubkey, agent_owner_pubkey, created_at, updated_at, channel_add_policy) +SELECT c.id, decode('', 'hex'), decode('', 'hex'), NOW(), NOW(), 'anyone'::channel_add_policy +FROM communities c +ON CONFLICT (community_id, pubkey) DO UPDATE SET agent_owner_pubkey = EXCLUDED.agent_owner_pubkey; +``` + +## "failed to parse agent store: missing field 'acp_command'" error banner + +The desktop app displays a red warning banner `failed to parse agent store (preserved as .invalid): missing field 'acp_command'` when `managed-agents.json` is missing required non-defaulted fields for `ManagedAgentRecord`. + +**Fix:** Ensure `managed-agents.json` contains all required schema fields (`pubkey`, `name`, `relay_url`, `acp_command` [e.g. `"buzz-acp"`], `agent_command` [e.g. `"buzz-agent"`], `mcp_command` [e.g. `"buzz-dev-mcp"`], `turn_timeout_seconds` [e.g. `900`], `agent_args` [`[]`]) and remove any `.invalid` backup file: + +```bash +rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid +``` + +**Related:** +- [DevelopmentSetup](development-setup) — how to start the dev environment +- [Configuration](configuration) — env var reference +- [CLIReference](cli-reference) — just commands +- [Relay](../entities/relay) — relay entity docs + From a0c2a2332c6fbc061be10fcdef80defbad0b82c4 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 16:26:49 -0500 Subject: [PATCH 02/14] chore: remove wiki docs from PR feature branch Signed-off-by: mainza-ai --- wiki/CLAUDE.md | 51 ------- wiki/components/admin-web.md | 16 -- wiki/components/buzz-acp.md | 17 --- wiki/components/buzz-admin.md | 14 -- wiki/components/buzz-agent.md | 20 --- wiki/components/buzz-audit.md | 15 -- wiki/components/buzz-auth.md | 15 -- wiki/components/buzz-cli.md | 16 -- wiki/components/buzz-conformance.md | 13 -- wiki/components/buzz-core.md | 15 -- wiki/components/buzz-db.md | 16 -- wiki/components/buzz-dev-mcp.md | 15 -- wiki/components/buzz-media.md | 14 -- wiki/components/buzz-persona.md | 13 -- wiki/components/buzz-pubsub.md | 15 -- wiki/components/buzz-push-gateway.md | 9 -- wiki/components/buzz-relay-mesh.md | 14 -- wiki/components/buzz-relay.md | 24 --- wiki/components/buzz-sdk.md | 13 -- wiki/components/buzz-search.md | 14 -- wiki/components/buzz-test-client.md | 9 -- wiki/components/buzz-workflow.md | 17 --- wiki/components/buzz-ws-client.md | 13 -- wiki/components/desktop-client.md | 25 ---- wiki/components/git-credential-nostr.md | 14 -- wiki/components/git-sign-nostr.md | 9 -- wiki/components/mobile-client.md | 21 --- wiki/components/sprig.md | 13 -- wiki/components/web-client.md | 13 -- wiki/concepts/acp.md | 21 --- wiki/concepts/architecture.md | 43 ------ wiki/concepts/audit-log.md | 16 -- wiki/concepts/authentication.md | 22 --- wiki/concepts/buzz-mesh.md | 14 -- wiki/concepts/channel-membership.md | 14 -- wiki/concepts/event-pipeline.md | 21 --- wiki/concepts/git-integration.md | 21 --- wiki/concepts/media-storage.md | 15 -- wiki/concepts/multi-tenancy.md | 19 --- wiki/concepts/nostr-protocol.md | 25 ---- wiki/concepts/search.md | 16 -- wiki/concepts/workflow-engine.md | 35 ----- wiki/entities/agent.md | 22 --- wiki/entities/channel.md | 19 --- wiki/entities/community.md | 14 -- wiki/entities/nostr-event.md | 15 -- wiki/entities/relay.md | 16 -- wiki/index.md | 66 --------- wiki/log.md | 47 ------ wiki/operations/cli-reference.md | 55 ------- wiki/operations/configuration.md | 35 ----- wiki/operations/deployment.md | 30 ---- wiki/operations/development-setup.md | 48 ------ wiki/operations/troubleshooting.md | 189 ------------------------ 54 files changed, 1311 deletions(-) delete mode 100644 wiki/CLAUDE.md delete mode 100644 wiki/components/admin-web.md delete mode 100644 wiki/components/buzz-acp.md delete mode 100644 wiki/components/buzz-admin.md delete mode 100644 wiki/components/buzz-agent.md delete mode 100644 wiki/components/buzz-audit.md delete mode 100644 wiki/components/buzz-auth.md delete mode 100644 wiki/components/buzz-cli.md delete mode 100644 wiki/components/buzz-conformance.md delete mode 100644 wiki/components/buzz-core.md delete mode 100644 wiki/components/buzz-db.md delete mode 100644 wiki/components/buzz-dev-mcp.md delete mode 100644 wiki/components/buzz-media.md delete mode 100644 wiki/components/buzz-persona.md delete mode 100644 wiki/components/buzz-pubsub.md delete mode 100644 wiki/components/buzz-push-gateway.md delete mode 100644 wiki/components/buzz-relay-mesh.md delete mode 100644 wiki/components/buzz-relay.md delete mode 100644 wiki/components/buzz-sdk.md delete mode 100644 wiki/components/buzz-search.md delete mode 100644 wiki/components/buzz-test-client.md delete mode 100644 wiki/components/buzz-workflow.md delete mode 100644 wiki/components/buzz-ws-client.md delete mode 100644 wiki/components/desktop-client.md delete mode 100644 wiki/components/git-credential-nostr.md delete mode 100644 wiki/components/git-sign-nostr.md delete mode 100644 wiki/components/mobile-client.md delete mode 100644 wiki/components/sprig.md delete mode 100644 wiki/components/web-client.md delete mode 100644 wiki/concepts/acp.md delete mode 100644 wiki/concepts/architecture.md delete mode 100644 wiki/concepts/audit-log.md delete mode 100644 wiki/concepts/authentication.md delete mode 100644 wiki/concepts/buzz-mesh.md delete mode 100644 wiki/concepts/channel-membership.md delete mode 100644 wiki/concepts/event-pipeline.md delete mode 100644 wiki/concepts/git-integration.md delete mode 100644 wiki/concepts/media-storage.md delete mode 100644 wiki/concepts/multi-tenancy.md delete mode 100644 wiki/concepts/nostr-protocol.md delete mode 100644 wiki/concepts/search.md delete mode 100644 wiki/concepts/workflow-engine.md delete mode 100644 wiki/entities/agent.md delete mode 100644 wiki/entities/channel.md delete mode 100644 wiki/entities/community.md delete mode 100644 wiki/entities/nostr-event.md delete mode 100644 wiki/entities/relay.md delete mode 100644 wiki/index.md delete mode 100644 wiki/log.md delete mode 100644 wiki/operations/cli-reference.md delete mode 100644 wiki/operations/configuration.md delete mode 100644 wiki/operations/deployment.md delete mode 100644 wiki/operations/development-setup.md delete mode 100644 wiki/operations/troubleshooting.md diff --git a/wiki/CLAUDE.md b/wiki/CLAUDE.md deleted file mode 100644 index 7c90321f17..0000000000 --- a/wiki/CLAUDE.md +++ /dev/null @@ -1,51 +0,0 @@ -# Buzz Wiki — Schema & Conventions - -This directory (`wiki/`) is an LLM-maintained knowledge base for the Buzz project. -The LLM creates, updates, and cross-references all pages. Humans read and guide. - -## Directory structure - -``` -wiki/ -├── CLAUDE.md # This file — schema, conventions, workflows -├── index.md # Catalog of all pages, organized by category -├── log.md # Append-only chronological record of changes -├── entities/ # Core system entities (Relay, Community, Agent, etc.) -├── concepts/ # Key ideas and mechanisms (Auth, Pipeline, Workflow, etc.) -├── components/ # Crate/service/client reference docs -└── operations/ # Deployment, configuration, development setup -``` - -## Page conventions - -- All pages are Markdown with `.md` extension. -- Every page starts with an `#` title matching the filename (title case). -- Every page should link to related pages using `[display text](../category/pagename)`. -- Pages in `entities/` describe a thing. Pages in `concepts/` describe an idea or mechanism. -- Pages in `components/` document a crate or client. Pages in `operations/` document how-to. -- Keep pages focused. Split into sub-pages when a section gets too long. -- Use `##` for major sections, `###` for subsections. - -## Workflows - -### Ingest a source -1. Read the source document. -2. Discuss notable points with the user. -3. Create/update relevant entity and concept pages across the wiki. -4. Update `index.md` if new pages were created. -5. Append an entry to `log.md`. - -### Answer a query -1. Read `index.md` to find relevant pages. -2. Read the relevant pages. -3. Synthesize an answer with citations to wiki pages. -4. If the answer is valuable as a new page, write it and update `index.md`. -5. Append an entry to `log.md`. - -### Lint the wiki -1. Check for contradictions between pages. -2. Find stale claims that newer entries have superseded. -3. Find orphan pages with no inbound links. -4. Find important concepts missing their own page. -5. Suggest new questions and sources to investigate. -6. Append an entry to `log.md`. diff --git a/wiki/components/admin-web.md b/wiki/components/admin-web.md deleted file mode 100644 index 47f835d076..0000000000 --- a/wiki/components/admin-web.md +++ /dev/null @@ -1,16 +0,0 @@ -# Admin Web - -Web-based admin dashboard for relay operators. Provides a graphical interface for administrative tasks. - -**Capabilities:** -- Community management (create, configure, delete) -- Channel administration -- Member management -- Audit log viewer -- System health monitoring -- Configuration editing - -**Related:** -- [buzz-admin](buzz-admin) — CLI equivalent -- [Community](../entities/community) -- [AuditLog](../concepts/audit-log) diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md deleted file mode 100644 index f87a704db0..0000000000 --- a/wiki/components/buzz-acp.md +++ /dev/null @@ -1,17 +0,0 @@ -# buzz-acp - -ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI agent subprocesses. - -**How it works:** -- Maintains a WebSocket connection to the relay (NIP-42 auth) -- Spawns and manages agent subprocesses over stdio JSON-RPC -- Translates Nostr events → JSON-RPC calls for the agent -- Translates agent responses → Nostr events published to the relay -- Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message -- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `) and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` -- Handles reconnection, subscription management, and agent lifecycle - -**Related:** -- [ACP](../concepts/acp) -- [Agent](../entities/agent) -- [buzz-agent](buzz-agent) diff --git a/wiki/components/buzz-admin.md b/wiki/components/buzz-admin.md deleted file mode 100644 index bff2592a93..0000000000 --- a/wiki/components/buzz-admin.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-admin - -Operator CLI for relay administration. Used for managing communities, channels, members, and system configuration. - -**Capabilities:** -- Create/delete communities -- Manage channel memberships -- View audit log -- System health checks -- Configuration management - -**Related:** -- [Community](../entities/community) -- [AdminWeb](admin-web) diff --git a/wiki/components/buzz-agent.md b/wiki/components/buzz-agent.md deleted file mode 100644 index c7131dcbe1..0000000000 --- a/wiki/components/buzz-agent.md +++ /dev/null @@ -1,20 +0,0 @@ -# buzz-agent - -A minimal ACP-compliant agent binary. Can be used as a reference implementation or as a lightweight agent for simple automation tasks. - -**Features:** -- ACP-compliant stdio JSON-RPC communication -- Basic message send/receive -- Reaction handling -- LLM provider support (Anthropic, OpenAI, local OpenAI-compatible endpoints like OMLX/Ollama) -- Reasoning content fallback (`reasoning_content` / `reasoning` parsing for local models) -- Designed to be swapped out for more capable agents (Goost, Codex, Claude Code) - -**LLM Response Parsing:** -- In `crates/buzz-agent/src/llm.rs`, responses from OpenAI-compatible endpoints are parsed by `parse_openai` and `parse_responses`. -- When local reasoning models output generated text in `reasoning_content` while leaving `content: ""`, `buzz-agent` falls back to `reasoning` to populate turn text output. - -**Related:** -- [ACP](../concepts/acp) -- [buzz-acp](buzz-acp) -- [Agent](../entities/agent) diff --git a/wiki/components/buzz-audit.md b/wiki/components/buzz-audit.md deleted file mode 100644 index 2c48d9c24a..0000000000 --- a/wiki/components/buzz-audit.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-audit - -SHA-256 hash-chain tamper-evident audit log. - -**Key responsibilities:** -- Appending audit entries to the hash chain -- Single-writer serialization via `pg_advisory_lock` -- 10 audit action types (event/create/delete, channel CRUD, member add/remove, auth success/failure, rate limit) -- Querying audit history for investigations -- All audit actions are also emitted as Nostr events - -**Related:** -- [AuditLog](../concepts/audit-log) -- [buzz-db](buzz-db) -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-auth.md b/wiki/components/buzz-auth.md deleted file mode 100644 index d5668da52a..0000000000 --- a/wiki/components/buzz-auth.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-auth - -Authentication, authorization, rate limiting, and scope enforcement. - -**Key responsibilities:** -- NIP-42 WebSocket challenge/response auth -- NIP-98 HTTP request auth -- Rate limiting per connection and per pubkey -- SSRF protection (`is_private_ip()` checking IPv4/IPv6 private/loopback/link-local ranges) -- Scope enforcement for admin operations - -**Related:** -- [Authentication](../concepts/authentication) -- [buzz-relay](buzz-relay) — integrates auth into connection lifecycle -- [ChannelMembership](../concepts/channel-membership) diff --git a/wiki/components/buzz-cli.md b/wiki/components/buzz-cli.md deleted file mode 100644 index 0acd7fd527..0000000000 --- a/wiki/components/buzz-cli.md +++ /dev/null @@ -1,16 +0,0 @@ -# buzz-cli - -Agent-first CLI tool. Designed for LLM tool calls — JSON in, JSON out. Every command accepts structured input and returns structured output. - -**Use cases:** -- Querying channel messages -- Sending messages programmatically -- Managing channels and memberships -- Triggering workflows -- Integration with agent subprocesses - -The CLI is the recommended way for agents to interact with Buzz when they need more structured control than real-time messaging provides. - -**Related:** -- [ACP](../concepts/acp) -- [Agent](../entities/agent) diff --git a/wiki/components/buzz-conformance.md b/wiki/components/buzz-conformance.md deleted file mode 100644 index 9d788ff2f9..0000000000 --- a/wiki/components/buzz-conformance.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-conformance - -Multi-tenant conformance tests. Verifies that the relay behaves correctly under multi-tenant deployment, including: - -- Tenant isolation (community A cannot see community B's data) -- Auth across tenants -- Correct scoping of events, channels, and memberships by community_id -- Rate limits per tenant - -**Related:** -- [MultiTenancy](../concepts/multi-tenancy) -- [buzz-test-client](buzz-test-client) -- [Community](../entities/community) diff --git a/wiki/components/buzz-core.md b/wiki/components/buzz-core.md deleted file mode 100644 index 0d62c52294..0000000000 --- a/wiki/components/buzz-core.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-core - -Core types and zero-I/O logic. The foundation crate that everything else depends on. Contains no I/O, no database access, no network — purely data structures and algorithms. - -**Contents:** -- Event type definitions (81 kinds in `kind.rs`) -- Event verification (Schnorr signature checks) -- Filter matching (NIP-01 filter evaluation) -- Core data structures (`Event`, `Filter`, `Subscription`, `Channel`, etc.) -- Constants, enums, and utility functions - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [buzz-relay](buzz-relay) — consumes core types -- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-db.md b/wiki/components/buzz-db.md deleted file mode 100644 index 987e8c055c..0000000000 --- a/wiki/components/buzz-db.md +++ /dev/null @@ -1,16 +0,0 @@ -# buzz-db - -Postgres event store and data access layer. Uses **sqlx** for runtime-queried database access (no compile-time macros). - -**Key responsibilities:** -- Event persistence (idempotent insert by event ID) -- Event querying (by filter, by ID, by kind, by author, by channel) -- Channel CRUD -- Community CRUD -- Search queries over `search_tsv` GIN index -- Connection pooling and migration management (25 SQL migrations, auto-applied on startup) - -**Related:** -- [buzz-relay](buzz-relay) — primary consumer -- [buzz-search](buzz-search) — search queries -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-dev-mcp.md b/wiki/components/buzz-dev-mcp.md deleted file mode 100644 index 5cc1aa286f..0000000000 --- a/wiki/components/buzz-dev-mcp.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-dev-mcp - -MCP (Model Context Protocol) server providing shell and file-edit tools. Intended for development agents that need to interact with the filesystem. - -**Tools provided:** -- Shell command execution -- File read/write/edit operations -- Directory listing - -Uses the **rmcp** SDK (Rust MCP implementation). - -**Related:** -- [ACP](../concepts/acp) -- [buzz-acp](buzz-acp) -- [buzz-persona](buzz-persona) diff --git a/wiki/components/buzz-media.md b/wiki/components/buzz-media.md deleted file mode 100644 index d749e47867..0000000000 --- a/wiki/components/buzz-media.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-media - -Blossom protocol media storage backed by S3-compatible object storage. - -**Key responsibilities:** -- File upload via HTTP (NIP-98 auth) -- Thumbnail generation (server-side image processing) -- File serving with content-type headers and caching -- Blob deletion -- S3 configuration (endpoint, bucket, region, credentials) - -**Related:** -- [MediaStorage](../concepts/media-storage) -- [buzz-relay](buzz-relay) — serves media endpoints diff --git a/wiki/components/buzz-persona.md b/wiki/components/buzz-persona.md deleted file mode 100644 index 8b62b86eaa..0000000000 --- a/wiki/components/buzz-persona.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-persona - -Agent persona packs — bundles of model configuration and system prompts that define an agent's behavior and capabilities. - -Examples: -- **Ralph** — code review persona -- **Scout** — research persona - -Each persona specifies: model backend, system prompt, tool permissions, and channel memberships. - -**Related:** -- [Agent](../entities/agent) -- [buzz-acp](buzz-acp) diff --git a/wiki/components/buzz-pubsub.md b/wiki/components/buzz-pubsub.md deleted file mode 100644 index 4f220a8828..0000000000 --- a/wiki/components/buzz-pubsub.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-pubsub - -Redis-backed pub/sub, presence tracking, and typing indicators. - -**Key responsibilities:** -- Cross-process event broadcasting via Redis pub/sub -- Presence tracking (who is online in which channels) -- Typing indicator propagation (agents broadcast typing too) -- Uses `deadpool-redis` for connection pooling - -In a multi-process relay deployment, events published by one process are broadcast to subscribers on all processes via Redis pub/sub. - -**Related:** -- [buzz-relay](buzz-relay) -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-push-gateway.md b/wiki/components/buzz-push-gateway.md deleted file mode 100644 index d0f280dce3..0000000000 --- a/wiki/components/buzz-push-gateway.md +++ /dev/null @@ -1,9 +0,0 @@ -# buzz-push-gateway - -Push notification gateway. Bridges Nostr events to push notification services (APNs for iOS, FCM for Android). - -**Flow:** Event arrives at relay → relay notifies push gateway → gateway formats push payload → sends to APNs/FCM for offline or backgrounded clients. - -**Related:** -- [MobileClient](mobile-client) -- [DesktopClient](desktop-client) diff --git a/wiki/components/buzz-relay-mesh.md b/wiki/components/buzz-relay-mesh.md deleted file mode 100644 index 8011d6000e..0000000000 --- a/wiki/components/buzz-relay-mesh.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-relay-mesh - -Inter-relay mesh transport. Uses **iroh** for peer-to-peer connections between relays. - -**Purpose:** Enables Buzz Mesh shared AI compute across relay communities. Relay instances in the mesh can share computational resources for agent inference. - -**Transport features (from iroh):** -- NAT traversal -- End-to-end encryption -- Relay fallback for difficult network conditions - -**Related:** -- [BuzzMesh](../concepts/buzz-mesh) -- [Relay](../entities/relay) diff --git a/wiki/components/buzz-relay.md b/wiki/components/buzz-relay.md deleted file mode 100644 index 74cc457d55..0000000000 --- a/wiki/components/buzz-relay.md +++ /dev/null @@ -1,24 +0,0 @@ -# buzz-relay - -The main WebSocket relay server. Built with **Axum** on **Tokio**. Coordinates all subsystems and never exposes internal crate boundaries to clients. - -**Key responsibilities:** -- WebSocket connection lifecycle (accept, auth, recv/send/heartbeat loops, cleanup) -- Event pipeline execution (12 steps) -- HTTP endpoints: `/events`, `/query`, `/count`, `/hooks/*`, `/media/*`, `/git/*` -- Connection management via `ConnectionManager` and `SubscriptionRegistry` (DashMap) -- Community binding via `TenantContext` - -**Connection lifecycle:** -1. Community binding (Host header → TenantContext) -2. Semaphore acquire (connection limit) -3. NIP-42 challenge (`["AUTH", ""]`) -4. Authentication (client signs challenge) -5. Three concurrent tasks: `recv_loop`, `send_loop`, `heartbeat_loop` (30s ping) -6. Cleanup on disconnect - -**Related:** -- [Relay](../entities/relay) -- [EventPipeline](../concepts/event-pipeline) -- [buzz-core](buzz-core) -- [buzz-db](buzz-db) diff --git a/wiki/components/buzz-sdk.md b/wiki/components/buzz-sdk.md deleted file mode 100644 index ed937562fd..0000000000 --- a/wiki/components/buzz-sdk.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-sdk - -Typed Nostr event builders for Rust. Provides a type-safe API for constructing Nostr events programmatically. - -**Features:** -- Typed event builders for common event kinds -- Automatic field validation -- Schnorr signing integration -- Filter construction helpers - -**Related:** -- [buzz-core](buzz-core) — uses core types -- [NostrEvent](../entities/nostr-event) diff --git a/wiki/components/buzz-search.md b/wiki/components/buzz-search.md deleted file mode 100644 index 8dac3c946b..0000000000 --- a/wiki/components/buzz-search.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-search - -Postgres full-text search (FTS) index and query support. - -**Key responsibilities:** -- Maintaining the `search_tsv` tsvector column and GIN index -- Building FTS queries from NIP-50 search filters -- Excluding privacy-sensitive event kinds from indexing -- Tenant-scoped search (by `community_id`) - -**Related:** -- [Search](../concepts/search) -- [buzz-db](buzz-db) — shares the Postgres connection -- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-test-client.md b/wiki/components/buzz-test-client.md deleted file mode 100644 index 8ad778634d..0000000000 --- a/wiki/components/buzz-test-client.md +++ /dev/null @@ -1,9 +0,0 @@ -# buzz-test-client - -Integration test harness for the Buzz relay. Provides programmatic access to connect, authenticate, send events, and verify responses. - -Used by the integration test suite to verify relay behavior end-to-end. - -**Related:** -- [buzz-conformance](buzz-conformance) -- [buzz-relay](buzz-relay) diff --git a/wiki/components/buzz-workflow.md b/wiki/components/buzz-workflow.md deleted file mode 100644 index b194075c5f..0000000000 --- a/wiki/components/buzz-workflow.md +++ /dev/null @@ -1,17 +0,0 @@ -# buzz-workflow - -YAML-as-code workflow engine for channel automation. - -**Key responsibilities:** -- Loading and parsing workflow YAML files -- Evaluating trigger conditions (message_posted, reaction_added, schedule, webhook) -- Executing action chains (send_message, send_dm, set_channel_topic, add_reaction, call_webhook, request_approval, delay) -- Cron scheduler (ticks every 60 seconds) -- `evalexpr` condition evaluation with custom string/regex functions - -**Approval gates** (request_approval action): schema, API, and UI are built; executor persistence is pending. - -**Related:** -- [WorkflowEngine](../concepts/workflow-engine) -- [EventPipeline](../concepts/event-pipeline) -- [Channel](../entities/channel) diff --git a/wiki/components/buzz-ws-client.md b/wiki/components/buzz-ws-client.md deleted file mode 100644 index 1a27456250..0000000000 --- a/wiki/components/buzz-ws-client.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-ws-client - -Shared WebSocket client library implementing NIP-42 authentication. Used by other components that need to connect to a relay as a client. - -**Features:** -- NIP-42 auth flow (connect, challenge, sign, verify) -- Automatic reconnection -- Subscription management -- Event sending and receiving - -**Related:** -- [buzz-acp](buzz-acp) — uses this for relay connections -- [Authentication](../concepts/authentication) diff --git a/wiki/components/desktop-client.md b/wiki/components/desktop-client.md deleted file mode 100644 index 37c54b7956..0000000000 --- a/wiki/components/desktop-client.md +++ /dev/null @@ -1,25 +0,0 @@ -# Desktop Client - -Native desktop application built with **Tauri 2** and **React 19**. - -**Tech stack:** -- Tauri 2 (Rust backend + webview frontend) -- React 19 with Vite -- Tailwind CSS for styling -- Biome for linting/formatting -- Playwright for E2E testing -- pnpm package manager - -**Features:** -- Stream channel real-time chat -- Forum thread browsing -- Canvas editing -- Media uploads (paste/drop/attach) -- Voice huddles (WebSocket Opus relay) -- Git repo browser (via web client embedded views) -- Agent management - -**Related:** -- [buzz-relay](buzz-relay) — backend -- [MobileClient](mobile-client) — companion app -- [WebClient](web-client) diff --git a/wiki/components/git-credential-nostr.md b/wiki/components/git-credential-nostr.md deleted file mode 100644 index 6ada7e58c7..0000000000 --- a/wiki/components/git-credential-nostr.md +++ /dev/null @@ -1,14 +0,0 @@ -# git-credential-nostr - -A git credential helper that authenticates `git push` and `git fetch` operations using a Nostr key (NIP-98 HTTP auth). - -**How it works:** -- Git calls the credential helper when it needs credentials for an HTTP remote -- The helper signs an auth request with the Nostr key -- The relay verifies the signature and allows the git operation -- No passwords, tokens, or SSH keys needed - -**Related:** -- [GitIntegration](../concepts/git-integration) -- [git-sign-nostr](git-sign-nostr) -- [Authentication](../concepts/authentication) diff --git a/wiki/components/git-sign-nostr.md b/wiki/components/git-sign-nostr.md deleted file mode 100644 index c13ddb8331..0000000000 --- a/wiki/components/git-sign-nostr.md +++ /dev/null @@ -1,9 +0,0 @@ -# git-sign-nostr - -A tool for signing git objects (commits, tags) with a Nostr key rather than a traditional PGP key. - -**Usage:** Replaces or supplements `git commit -S` / `git tag -s`. The signature is generated using the Nostr keypair (secp256k1) instead of a PGP key. - -**Related:** -- [GitIntegration](../concepts/git-integration) -- [git-credential-nostr](git-credential-nostr) diff --git a/wiki/components/mobile-client.md b/wiki/components/mobile-client.md deleted file mode 100644 index 05ea694692..0000000000 --- a/wiki/components/mobile-client.md +++ /dev/null @@ -1,21 +0,0 @@ -# Mobile Client - -Mobile application for iOS and Android built with **Flutter** and **Dart**. - -**Tech stack:** -- Flutter + Dart -- Riverpod for state management -- flutter_hooks for local state -- Catppuccin theme (Latte light / Macchiato dark) - -**Features:** -- Stream channel messaging -- Forum thread browsing -- Push notifications (via buzz-push-gateway) -- Media viewing and upload -- Agent interactions - -**Related:** -- [buzz-push-gateway](buzz-push-gateway) -- [DesktopClient](desktop-client) -- [buzz-relay](buzz-relay) diff --git a/wiki/components/sprig.md b/wiki/components/sprig.md deleted file mode 100644 index 1a96365d3c..0000000000 --- a/wiki/components/sprig.md +++ /dev/null @@ -1,13 +0,0 @@ -# sprig - -All-in-one development harness combining ACP, agent, and MCP server into a single process. Useful for local development and testing. - -**Bundles:** -- ACP harness (relay connection) -- Agent subprocess -- MCP tools (shell, file-edit) - -**Related:** -- [buzz-acp](buzz-acp) -- [buzz-agent](buzz-agent) -- [buzz-dev-mcp](buzz-dev-mcp) diff --git a/wiki/components/web-client.md b/wiki/components/web-client.md deleted file mode 100644 index 5dc6e2497e..0000000000 --- a/wiki/components/web-client.md +++ /dev/null @@ -1,13 +0,0 @@ -# Web Client - -Browser-based web application. Primarily a **repo browser** for the NIP-34 git hosting feature, served by the relay over HTTP. - -**Tech stack:** -- React + Vite -- Tailwind CSS -- Served directly by `buzz-relay` - -**Related:** -- [DesktopClient](desktop-client) -- [GitIntegration](../concepts/git-integration) -- [buzz-relay](buzz-relay) diff --git a/wiki/concepts/acp.md b/wiki/concepts/acp.md deleted file mode 100644 index 53a640a913..0000000000 --- a/wiki/concepts/acp.md +++ /dev/null @@ -1,21 +0,0 @@ -# ACP (Agent Communication Protocol) - -The Agent Communication Protocol bridges Buzz relay events to AI agent subprocesses. It is the standard way for agents to connect to a Buzz community. - -**How it works:** -- `buzz-acp` spawns an agent subprocess (e.g., Goost, Codex, Claude Code) -- Agent and harness communicate over stdio JSON-RPC -- The harness translates Nostr events (messages, reactions, etc.) into calls the agent understands -- Agent actions (sending messages, reacting, etc.) are translated back into Nostr events and published to the relay - -**Architecture:** -``` -Relay ← WebSocket → ACP Harness ← stdio JSON-RPC → Agent Subprocess -``` - -The harness maintains the WebSocket connection to the relay, handles reconnection, manages subscriptions, and translates between the two protocols. - -**Related:** -- [Agent](../entities/agent) -- [buzz-acp](../components/buzz-acp) -- [buzz-agent](../components/buzz-agent) diff --git a/wiki/concepts/architecture.md b/wiki/concepts/architecture.md deleted file mode 100644 index ad9e8c4484..0000000000 --- a/wiki/concepts/architecture.md +++ /dev/null @@ -1,43 +0,0 @@ -# Architecture - -Buzz is a self-hostable team workspace built on a single Nostr relay as the source of truth. - -## Layers - -``` -Clients (Desktop, Mobile, CLI, Agent) ← WebSocket / HTTP - │ - buzz-relay (Axum) - │ - ┌────┼────┐ - │ │ │ -Postgres Redis MinIO -``` - -**The relay** is the central coordinator. All subsystems (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) are orchestrated by `buzz-relay` and never talk to each other directly. Cross-subsystem coordination happens only through the relay. - -**Clients** connect via WebSocket (real-time) or HTTP (REST). Every action is a signed Nostr event. - -**Data stores** — Postgres (events, channels, search, audit, workflows), Redis (pub/sub, presence, typing indicators), MinIO/S3 (media attachments). - -## Design principles - -- **Single source of truth** — the relay event log. No P2P gossip. -- **URL is the community** — one URL = one isolated workspace. -- **Membership is the only gate** — no roles, no permissions, no ACLs beyond channel membership. -- **Events are immutable** — once written, events are never modified. -- **Everything is an event** — messages, reactions, workflow steps, git pushes, huddles. 81 event kinds. - -## Security model - -- NIP-42 for WebSocket auth (challenge-response) -- NIP-98 for HTTP auth (Nostr-signed HTTP requests) -- Channel membership is the only access control -- Hash-chain audit log for tamper-evident record -- SSRF protection via `is_private_ip()` checks - -**Related:** -- [Relay](../entities/relay) -- [EventPipeline](event-pipeline) -- [MultiTenancy](multi-tenancy) -- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/audit-log.md b/wiki/concepts/audit-log.md deleted file mode 100644 index 5eaa696d3e..0000000000 --- a/wiki/concepts/audit-log.md +++ /dev/null @@ -1,16 +0,0 @@ -# Audit Log - -Buzz maintains a tamper-evident audit trail using a SHA-256 hash chain. - -- Each audit entry contains: timestamp, action type, actor pubkey, target, previous hash, and metadata -- The chain is single-writer — serialized via `pg_advisory_lock` to prevent concurrent writes -- 10 audit action types: `EventCreated`, `EventDeleted`, `ChannelCreated`, `ChannelUpdated`, `ChannelDeleted`, `MemberAdded`, `MemberRemoved`, `AuthSuccess`, `AuthFailure`, `RateLimitExceeded` -- The hash chain ensures that modifying any historical entry would invalidate all subsequent hashes -- All audit actions are also Nostr events, making them visible in the relay's event stream - -**Source:** `buzz-audit` crate - -**Related:** -- [buzz-audit](../components/buzz-audit) -- [EventPipeline](event-pipeline) -- [Architecture](architecture) diff --git a/wiki/concepts/authentication.md b/wiki/concepts/authentication.md deleted file mode 100644 index f364ab32f9..0000000000 --- a/wiki/concepts/authentication.md +++ /dev/null @@ -1,22 +0,0 @@ -# Authentication - -Buzz uses Nostr's cryptographic identity model. Authentication is based on Schnorr signatures over the secp256k1 curve. - -## NIP-42 (WebSocket) - -The relay issues a random challenge string on connection. The client signs it with their Nostr private key and sends it back. The relay verifies the signature against the advertised pubkey. - -**Flow:** Connect → `["AUTH", ""]` → client signs → `["AUTH", {"event": ...}]` → verified - -## NIP-98 (HTTP) - -HTTP requests include a Nostr-signed authorization header. The relay verifies the signature against the pubkey. Used for REST endpoints (media upload, git operations, admin API). - -## Rate limiting - -The `buzz-auth` crate enforces rate limits per connection and per pubkey, with separate limits for different event kinds. - -**Related:** -- [buzz-auth](../components/buzz-auth) -- [NostrEvent](../entities/nostr-event) -- [ChannelMembership](channel-membership) diff --git a/wiki/concepts/buzz-mesh.md b/wiki/concepts/buzz-mesh.md deleted file mode 100644 index 0b6fe64e0c..0000000000 --- a/wiki/concepts/buzz-mesh.md +++ /dev/null @@ -1,14 +0,0 @@ -# Buzz Mesh - -Buzz Mesh enables relay communities to pool opted-in member hardware into shared AI compute. Agents consume this compute via a local OpenAI-compatible endpoint. - -**Transport:** Uses **iroh** for inter-relay mesh transport — a peer-to-peer networking library with NAT traversal, end-to-end encryption, and relay fallback. - -**Runtime:** Uses **llama.cpp** for native on-device LLM inference, or forwards to external providers. - -**Design goal:** Shared AI compute across a community, reducing reliance on external API providers and keeping inference local. - -**Related:** -- [Agent](../entities/agent) -- [buzz-relay-mesh](../components/buzz-relay-mesh) -- [ACP](acp) diff --git a/wiki/concepts/channel-membership.md b/wiki/concepts/channel-membership.md deleted file mode 100644 index 23bba3b78e..0000000000 --- a/wiki/concepts/channel-membership.md +++ /dev/null @@ -1,14 +0,0 @@ -# Channel Membership - -Channel membership is the only access control mechanism in Buzz. There are no roles, permissions, or ACLs — if you are a member of a channel, you can read and write to it. - -This is a deliberate design choice that simplifies the security model: the event pipeline has exactly one access control check at step 6, and it's a simple membership lookup. - -- Membership is scoped to a [Community](../entities/community) -- Agents have their own memberships, managed independently of human members -- Membership changes are themselves Nostr events (auditable) - -**Related:** -- [Channel](../entities/channel) -- [EventPipeline](event-pipeline) -- [Authentication](authentication) diff --git a/wiki/concepts/event-pipeline.md b/wiki/concepts/event-pipeline.md deleted file mode 100644 index 1a0706f0b2..0000000000 --- a/wiki/concepts/event-pipeline.md +++ /dev/null @@ -1,21 +0,0 @@ -# Event Pipeline - -Every Nostr event in Buzz goes through a 12-step pipeline when received by the relay: - -1. **Auth check** — verify the client is authenticated (NIP-42) -2. **Pubkey match** — ensure the event pubkey matches the authenticated client -3. **Reject reserved kinds** — prevent spoofing of internal event types (KIND_AUTH) -4. **Ephemeral route** — ephemeral events are broadcast but not persisted -5. **Schnorr verify** — cryptographic signature verification -6. **Membership check** — verify sender is a member of the target channel -7. **DB insert** — idempotent write to Postgres (event ID is the dedup key) -8. **Redis publish** — publish to Redis pub/sub for cross-process notification -9. **Fan-out** — send event to all subscribed WebSocket connections -10. **Search index** — update Postgres FTS search index -11. **Audit log** — append to the hash-chain audit trail -12. **Workflow trigger** — evaluate workflow conditions and execute matching actions - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [Relay](../entities/relay) -- [buzz-relay](../components/buzz-relay) diff --git a/wiki/concepts/git-integration.md b/wiki/concepts/git-integration.md deleted file mode 100644 index 0bf7e1b5bd..0000000000 --- a/wiki/concepts/git-integration.md +++ /dev/null @@ -1,21 +0,0 @@ -# Git Integration - -Buzz implements NIP-34 for git hosting, plus additional tools for Nostr-signed git operations. - -## NIP-34 Git Hosting - -The relay hosts bare git repos over smart HTTP. Repos are accessed via the relay's HTTP endpoints, authenticated with NIP-98. - -## Branch-as-Room - -Creating a feature branch automatically creates a channel where patches, CI results, reviews, and merge decisions live. This ties git workflow directly into the chat workspace. - -## Tools - -- **git-sign-nostr** — sign git commits, tags, and other objects with a Nostr key -- **git-credential-nostr** — git credential helper that authenticates push/fetch using Nostr keys - -**Related:** -- [git-sign-nostr](../components/git-sign-nostr) -- [git-credential-nostr](../components/git-credential-nostr) -- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/media-storage.md b/wiki/concepts/media-storage.md deleted file mode 100644 index da1a5f82a4..0000000000 --- a/wiki/concepts/media-storage.md +++ /dev/null @@ -1,15 +0,0 @@ -# Media Storage - -Buzz uses the Blossom protocol for media uploads and storage, backed by S3-compatible object storage (MinIO in development, any S3 provider in production). - -- Users paste, drag, or attach files in channels -- Files are uploaded to S3 via the relay's HTTP endpoints (NIP-98 auth) -- The relay generates server-side thumbnails for images -- Files are served with content-type headers and caching -- Media events are Nostr events with references to the stored blob - -**Configuration:** S3 endpoint, bucket, region, access key, and secret key via environment variables. - -**Related:** -- [buzz-media](../components/buzz-media) -- [Relay](../entities/relay) diff --git a/wiki/concepts/multi-tenancy.md b/wiki/concepts/multi-tenancy.md deleted file mode 100644 index 921ddb16a6..0000000000 --- a/wiki/concepts/multi-tenancy.md +++ /dev/null @@ -1,19 +0,0 @@ -# Multi-Tenancy - -Buzz supports multi-tenant deployments where multiple communities share the same Postgres/Redis/MinIO infrastructure while maintaining strict isolation. - -## Isolation Model - -- **Community** is the tenant boundary — one workspace, one URL, one isolated world -- All data is scoped by `community_id` at the database level -- The relay extracts the community from the Host header on connection -- `TenantContext` is established before any handler runs - -## Formal Verification - -The multi-tenant relay behavior has been mechanized in **TLA+** for correctness verification. Authorization properties are verified in **Tamarin** (a security protocol verifier). These formal specs live in `docs/formal/`. - -**Related:** -- [Community](../entities/community) -- [Architecture](architecture) -- [buzz-conformance](../components/buzz-conformance) diff --git a/wiki/concepts/nostr-protocol.md b/wiki/concepts/nostr-protocol.md deleted file mode 100644 index f3423986da..0000000000 --- a/wiki/concepts/nostr-protocol.md +++ /dev/null @@ -1,25 +0,0 @@ -# Nostr Protocol - -Buzz is built on the Nostr protocol — an open, decentralized protocol for signed events. - -## Standard Compliance - -- Wire-compatible with NIP-01 (event format, relay-client protocol) -- NIP-42 (authentication via challenge-response) -- NIP-50 (search) -- NIP-98 (HTTP auth) -- NIP-34 (git integration) - -## Custom Extensions - -Buzz extends Nostr with 81 event kinds in the 40000-49999 custom range, covering: stream messages, forum posts, DMs, canvases, reactions, workflows, git operations, media, huddles, typing indicators, and admin actions. - -## Key Differences from P2P Nostr - -Unlike typical Nostr relays, Buzz is **not P2P**. There is no gossip or replication between relays. The relay is the single source of truth. This is intentional — Buzz is a workspace, not a decentralized social network. The Nostr protocol is used for its cryptographic identity and event model, not for federation. - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [Authentication](authentication) -- [GitIntegration](git-integration) -- [EventPipeline](event-pipeline) diff --git a/wiki/concepts/search.md b/wiki/concepts/search.md deleted file mode 100644 index cddc956430..0000000000 --- a/wiki/concepts/search.md +++ /dev/null @@ -1,16 +0,0 @@ -# Search - -Buzz uses Postgres full-text search (FTS) for searching events. There is no external search service — all search is handled within Postgres. - -- Events are indexed into a `search_tsv` column (a Postgres `tsvector`) via a GIN index -- Search supports NIP-50, the Nostr standard search protocol -- Queries come in via the relay's `REQ` handler with a search filter -- Privacy-sensitive event kinds are excluded at the storage level (not indexed) -- Search is scoped by community (tenant isolation) - -**Implementation:** `buzz-search` crate handles indexing and query building over the `search_tsv` GIN index. - -**Related:** -- [buzz-search](../components/buzz-search) -- [NostrProtocol](nostr-protocol) -- [MultiTenancy](multi-tenancy) diff --git a/wiki/concepts/workflow-engine.md b/wiki/concepts/workflow-engine.md deleted file mode 100644 index 2d78319b31..0000000000 --- a/wiki/concepts/workflow-engine.md +++ /dev/null @@ -1,35 +0,0 @@ -# Workflow Engine - -Buzz has a YAML-as-code workflow engine for channel automation. Workflows are defined in YAML files, scoped to a channel, and executed by `buzz-workflow`. - -## Triggers - -| Trigger | Description | -|---|---| -| `message_posted` | Fires when a message is posted matching a text pattern | -| `reaction_added` | Fires when a reaction is added matching an emoji | -| `schedule` | Cron-based scheduled trigger (ticks every 60s) | -| `webhook` | External HTTP webhook trigger | - -## Actions - -| Action | Description | -|---|---| -| `send_message` | Post a message to the channel | -| `send_dm` | Send a direct message to a user | -| `set_channel_topic` | Update the channel topic | -| `add_reaction` | Add an emoji reaction | -| `call_webhook` | Call an external webhook URL | -| `request_approval` | Request human approval before proceeding | -| `delay` | Wait before executing next action | - -## Conditions - -Conditions are expressions evaluated with `evalexpr`, with custom functions: `str_contains`, `str_starts_with`, `str_ends_with`, `matches_regex`, and more. - -**Approval gates** are partially built (schema, API, and UI exist but executor persistence is pending). - -**Related:** -- [buzz-workflow](../components/buzz-workflow) -- [Channel](../entities/channel) -- [EventPipeline](event-pipeline) diff --git a/wiki/entities/agent.md b/wiki/entities/agent.md deleted file mode 100644 index 68e1c1ceef..0000000000 --- a/wiki/entities/agent.md +++ /dev/null @@ -1,22 +0,0 @@ -# Agent - -AI agents are first-class team members in Buzz. They have their own Nostr keypairs, channel memberships, and audit trail — exactly like human teammates, just different cryptographic identities. - -**How agents connect:** -- Agents connect via the **ACP (Agent Communication Protocol)** harness (`buzz-acp`) -- ACP bridges Nostr relay events to AI agent subprocesses over stdio JSON-RPC -- Agents use tools like Goost, Codex, Claude Code as their AI backend -- Agent teams bundle a persona (model + system prompt), e.g. Ralph for code review, Scout for research - -**Agent capabilities:** -- Send and receive messages in channels -- Participate in voice huddles via STT/TTS -- Broadcast typing indicators -- Trigger and respond to workflows -- Use `buzz-cli` for JSON-in/JSON-out interaction - -**Related:** -- [ACP](../concepts/acp) — the protocol that connects agents -- [buzz-acp](../components/buzz-acp) — ACP harness crate -- [buzz-agent](../components/buzz-agent) — minimal agent binary -- [buzz-persona](../components/buzz-persona) — persona packs diff --git a/wiki/entities/channel.md b/wiki/entities/channel.md deleted file mode 100644 index cca0c2865d..0000000000 --- a/wiki/entities/channel.md +++ /dev/null @@ -1,19 +0,0 @@ -# Channel - -Channels are communication spaces within a [Community](community). Buzz supports three channel types: - -## Stream -Slack-like real-time chat. Mandatory topics on creation. Supports sub-replies (thread-like) and has zero-notification default to reduce noise. - -## Forum -Discourse-like async long-form posts. Flat replies. Designed for asynchronous discussion rather than real-time chat. - -## Direct Messages -1:1 and group DMs (up to 9 participants). Private communication outside of stream/forum channels. - -**Channel membership is the only access control gate** in Buzz. If you're a member of a channel, you can read and write to it. There are no roles, permissions, or ACLs beyond membership. - -**Related:** -- [ChannelMembership](../concepts/channel-membership) — access control model -- [Community](community) — parent tenant -- [NostrEvent](nostr-event) — every channel action is an event diff --git a/wiki/entities/community.md b/wiki/entities/community.md deleted file mode 100644 index ade52f5fac..0000000000 --- a/wiki/entities/community.md +++ /dev/null @@ -1,14 +0,0 @@ -# Community - -A community is a workspace — the tenant boundary in Buzz. One URL, one isolated world. Multi-tenant deployments share Postgres/Redis/MinIO infrastructure but scope all data by `community_id`. - -- The URL is authoritative: the host header determines which community a request belongs to -- A community has its own channels, members (human and agent), workflows, audit log, and git repos -- Communities cannot see each other's data - -**Connection flow:** A client connects via WebSocket → the relay extracts the community from the Host header → establishes `TenantContext` → enforces connection limits per community → authenticates the client. - -**Related:** -- [Relay](relay) — serving a community -- [MultiTenancy](../concepts/multi-tenancy) — isolation model -- [Channel](channel) — communication spaces within a community diff --git a/wiki/entities/nostr-event.md b/wiki/entities/nostr-event.md deleted file mode 100644 index 0f0f6bd915..0000000000 --- a/wiki/entities/nostr-event.md +++ /dev/null @@ -1,15 +0,0 @@ -# Nostr Event - -The atomic unit of all activity in Buzz. Every action — a chat message, a reaction, a workflow step, a canvas update, a git push, a huddle voice event — is a cryptographically signed Nostr event. - -Events follow the NIP-01 standard and are extended with custom kinds in the 40000-49999 range. Buzz defines **81 event kinds** across stream channels, forums, DMs, canvases, reactions, workflows, git, media, huddles, and admin operations. - -**Event pipeline (12 steps):** -1. Auth check → 2. Pubkey match → 3. Reject reserved kinds → 4. Ephemeral route → 5. Schnorr verify → 6. Membership check → 7. DB insert (idempotent) → 8. Redis publish → 9. Fan-out to subscribers → 10. Search index → 11. Audit log → 12. Workflow trigger - -**Source:** `crates/buzz-core/src/kind.rs` for the full kind list. - -**Related:** -- [EventPipeline](../concepts/event-pipeline) — the 12-step lifecycle -- [Relay](relay) — processes all events -- [Authentication](../concepts/authentication) — NIP-42/NIP-98 signing diff --git a/wiki/entities/relay.md b/wiki/entities/relay.md deleted file mode 100644 index c6d4d124ba..0000000000 --- a/wiki/entities/relay.md +++ /dev/null @@ -1,16 +0,0 @@ -# Relay - -The Nostr relay server is the single source of truth for a Buzz community. All reads and writes — chat messages, reactions, workflow triggers, canvas updates, git pushes, huddle events — flow through it as signed Nostr events. - -Built with **Axum** on **Tokio**, the relay handles WebSocket connections, HTTP requests, and coordinates all subsystems. It imports all service crates (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) and orchestrates cross-subsystem coordination. - -**Key traits:** -- Single source of truth — no P2P gossip or replication -- Every action is a signed Nostr event -- All subsystems are coordinated through the relay, never directly between crates -- URL is authoritative — the relay's URL defines the community - -**Related:** -- [Community](community) — tenant boundary -- [EventPipeline](../concepts/event-pipeline) — event lifecycle -- [buzz-relay](../components/buzz-relay) — implementation crate diff --git a/wiki/index.md b/wiki/index.md deleted file mode 100644 index f2ec1332e6..0000000000 --- a/wiki/index.md +++ /dev/null @@ -1,66 +0,0 @@ -# Index - -Catalog of all wiki pages, organized by category. - -## Entities - -- [Relay](entities/relay) — the Nostr relay server; the single source of truth for a community -- [Community](entities/community) — a workspace; one URL, one isolated tenant -- [Agent](entities/agent) — an AI agent as a first-class team member with its own Nostr keypair -- [Channel](entities/channel) — stream, forum, and DM communication spaces -- [NostrEvent](entities/nostr-event) — the atomic unit of all activity; a cryptographically signed event - -## Concepts - -- [Architecture](concepts/architecture) — system overview, layers, and design principles -- [EventPipeline](concepts/event-pipeline) — the 12-step lifecycle of an event from receipt to fan-out -- [Authentication](concepts/authentication) — NIP-42 challenge-response and NIP-98 HTTP auth -- [ChannelMembership](concepts/channel-membership) — access control model (membership is the only gate) -- [WorkflowEngine](concepts/workflow-engine) — YAML-as-code channel automation with triggers and actions -- [AuditLog](concepts/audit-log) — SHA-256 hash-chain tamper-evident audit trail -- [BuzzMesh](concepts/buzz-mesh) — inter-relay mesh for pooled AI compute -- [ACP](concepts/acp) — Agent Communication Protocol bridging Nostr events to agent subprocesses -- [GitIntegration](concepts/git-integration) — NIP-34 git hosting, signing, and branch-as-room -- [MediaStorage](concepts/media-storage) — Blossom protocol media uploads on S3/MinIO -- [Search](concepts/search) — Postgres FTS full-text search over events -- [MultiTenancy](concepts/multi-tenancy) — community isolation model and formal verification -- [NostrProtocol](concepts/nostr-protocol) — Nostr wire protocol and Buzz's custom event kinds - -## Components - -- [buzz-relay](components/buzz-relay) — main WebSocket relay server (Axum) -- [buzz-core](components/buzz-core) — core types, event verification, filter matching (zero I/O) -- [buzz-db](components/buzz-db) — Postgres event store and data access layer -- [buzz-auth](components/buzz-auth) — auth, rate limiting, and scope enforcement -- [buzz-pubsub](components/buzz-pubsub) — Redis pub/sub, presence, typing indicators -- [buzz-search](components/buzz-search) — Postgres FTS search index -- [buzz-audit](components/buzz-audit) — hash-chain audit log -- [buzz-media](components/buzz-media) — Blossom/S3 media storage -- [buzz-workflow](components/buzz-workflow) — YAML workflow engine -- [buzz-acp](components/buzz-acp) — ACP harness for agent subprocess orchestration -- [buzz-agent](components/buzz-agent) — minimal ACP-compliant agent binary -- [buzz-dev-mcp](components/buzz-dev-mcp) — MCP server providing shell and file-edit tools -- [buzz-persona](components/buzz-persona) — agent persona packs (model + system prompt) -- [buzz-cli](components/buzz-cli) — agent-first CLI (JSON in/out) -- [buzz-sdk](components/buzz-sdk) — typed Nostr event builders -- [buzz-admin](components/buzz-admin) — operator CLI for relay administration -- [buzz-ws-client](components/buzz-ws-client) — shared WebSocket client (NIP-42) -- [buzz-test-client](components/buzz-test-client) — integration test harness -- [buzz-conformance](components/buzz-conformance) — multi-tenant conformance tests -- [buzz-push-gateway](components/buzz-push-gateway) — push notification gateway -- [buzz-relay-mesh](components/buzz-relay-mesh) — iroh-based inter-relay mesh transport -- [git-sign-nostr](components/git-sign-nostr) — sign git objects with a Nostr key -- [git-credential-nostr](components/git-credential-nostr) — git credential helper for Nostr auth -- [sprig](components/sprig) — all-in-one harness (ACP + agent + MCP) -- [DesktopClient](components/desktop-client) — Tauri 2 + React 19 native desktop app -- [MobileClient](components/mobile-client) — Flutter mobile app (iOS + Android) -- [WebClient](components/web-client) — browser-based web client (repo browser) -- [AdminWeb](components/admin-web) — admin dashboard - -## Operations - -- [DevelopmentSetup](operations/development-setup) — local dev environment setup with Docker Compose -- [Deployment](operations/deployment) — production deployment with Helm and Docker Compose -- [Configuration](operations/configuration) — environment variables and community config -- [CLIReference](operations/cli-reference) — just commands and common dev workflows -- [Troubleshooting](operations/troubleshooting) — common issues and fixes diff --git a/wiki/log.md b/wiki/log.md deleted file mode 100644 index 2223b00be6..0000000000 --- a/wiki/log.md +++ /dev/null @@ -1,47 +0,0 @@ -# Log - -Chronological record of wiki changes. Each entry uses the format: -`## [YYYY-MM-DD] type | Title` - -- **ingest** — a new source was read and integrated -- **query** — a question was answered and the result was filed -- **lint** — a health check was performed -- **update** — pages were revised or created outside of ingest/query - ---- - -## [2026-07-27] ingest | Initial Wiki Creation - -Created the initial wiki for the Buzz project based on project source code and documentation. - -**Pages created:** -- `CLAUDE.md` — schema, conventions, and workflows -- `index.md` — catalog of all pages -- `log.md` — this file -- `entities/relay.md`, `entities/community.md`, `entities/agent.md`, `entities/channel.md`, `entities/nostr-event.md` -- `concepts/architecture.md`, `concepts/event-pipeline.md`, `concepts/authentication.md`, `concepts/channel-membership.md`, `concepts/workflow-engine.md`, `concepts/audit-log.md`, `concepts/buzz-mesh.md`, `concepts/acp.md`, `concepts/git-integration.md`, `concepts/media-storage.md`, `concepts/search.md`, `concepts/multi-tenancy.md`, `concepts/nostr-protocol.md` -- `components/buzz-relay.md`, `components/buzz-core.md`, `components/buzz-db.md`, `components/buzz-auth.md`, `components/buzz-pubsub.md`, `components/buzz-search.md`, `components/buzz-audit.md`, `components/buzz-media.md`, `components/buzz-workflow.md`, `components/buzz-acp.md`, `components/buzz-agent.md`, `components/buzz-dev-mcp.md`, `components/buzz-persona.md`, `components/buzz-cli.md`, `components/buzz-sdk.md`, `components/buzz-admin.md`, `components/buzz-ws-client.md`, `components/buzz-test-client.md`, `components/buzz-conformance.md`, `components/buzz-push-gateway.md`, `components/buzz-relay-mesh.md`, `components/git-sign-nostr.md`, `components/git-credential-nostr.md`, `components/sprig.md`, `components/desktop-client.md`, `components/mobile-client.md`, `components/web-client.md`, `components/admin-web.md` -- `operations/development-setup.md`, `operations/deployment.md`, `operations/configuration.md`, `operations/cli-reference.md` - -## [2026-07-27] update | Added Troubleshooting Page - -Created `operations/troubleshooting.md` covering common issues: 521 errors when connecting to cloud relays, port conflicts, rate limiting, Docker health, and event rejection. Updated `index.md` to link the new page. - -## [2026-07-27] query | Agent Shows Response Bubble But Doesn't Publish - -Investigated agent response not publishing. Two root causes found: -1. Agent was connected to `wss://milimo.communities.buzz.xyz` instead of `ws://localhost:3000` — hardcoded in `managed-agents.json`. Responses went to the wrong relay. -2. Even on the correct relay, the LLM (Qwen3.6-35B-A3B-bf16 via OMLX) returns text via ACP `agent_message_chunk` but doesn't call the `shell` tool to run `buzz messages send`. The harness does not auto-publish agent output. - -Updated `operations/troubleshooting.md` with both causes and fixes. - -## [2026-07-28] update | Root Causes Resolved — Wiki Updated - -Applied fixes from investigation: -- **Local LLM reasoning content**: `buzz-agent` now handles `reasoning_content` field from OpenAI-compatible endpoints (local models), falling back to `content` when `reasoning_content` is absent. -- **Fallback turn text publishing**: `buzz-acp` now accumulates `agent_message_chunk` text during a turn and publishes a `kind: 9` channel message on `StopReason::EndTurn` if no `send_message` tool call was made. Enables non-tool-calling models to participate. -- **Response sanitization**: `clean_agent_text_response` strips pseudo-tool JSON blocks (`` ```json ... ``` ``) and model tokens (`<|tool_call|>`, `<|im_end|>`) from generated text. -- **Owner pubkey seeding**: `agent_owner_pubkey` seeded in Postgres `users` table across all local dev community hosts (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`). -- **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. - -Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. diff --git a/wiki/operations/cli-reference.md b/wiki/operations/cli-reference.md deleted file mode 100644 index a17a2c96d6..0000000000 --- a/wiki/operations/cli-reference.md +++ /dev/null @@ -1,55 +0,0 @@ -# CLI Reference - -## just (task runner) - -The `Justfile` at the project root provides common development commands. - -### Development - -| Command | Description | -|---|---| -| `just dev` | Start full dev stack (Docker Compose) | -| `just dev-reset` | Destroy and recreate dev stack | -| `just seed-local-community` | Seed sample data | -| `just desktop` | Launch desktop client dev server | -| `just mobile` | Launch Flutter dev server | - -### Testing - -| Command | Description | -|---|---| -| `just test-all` | Run all tests | -| `just test-rust` | Run Rust tests | -| `just test-desktop` | Run desktop E2E tests (Playwright) | -| `just test-mobile` | Run Flutter tests | - -### Building - -| Command | Description | -|---|---| -| `just build-relay` | Build relay binary | -| `just build-desktop` | Build desktop app | -| `just build-mobile` | Build mobile app | -| `just docker` | Build Docker images | - -## cargo - -Standard Cargo commands work. Key workspace crates: - -```bash -cargo build -p buzz-relay -cargo test -p buzz-conformance -cargo clippy -p buzz-core -``` - -## Hermit - -Hermit manages toolchain versions. Activate automatically by `cd`-ing into `buzz/`, or manually: - -```bash -. bin/activate-hermit -``` - -**Related:** -- [DevelopmentSetup](development-setup) -- [Deployment](deployment) diff --git a/wiki/operations/configuration.md b/wiki/operations/configuration.md deleted file mode 100644 index 5d34b98a68..0000000000 --- a/wiki/operations/configuration.md +++ /dev/null @@ -1,35 +0,0 @@ -# Configuration - -Buzz is configured primarily through environment variables. - -## Core - -| Variable | Description | -|---|---| -| `DATABASE_URL` | Postgres connection string | -| `REDIS_URL` | Redis connection string | -| `RELAY_URL` | Public URL of the relay | -| `RELAY_PORT` | Listen port (default: 8080) | - -## Media (S3/MinIO) - -| Variable | Description | -|---|---| -| `S3_ENDPOINT` | S3-compatible endpoint URL | -| `S3_BUCKET` | Bucket name for media storage | -| `S3_REGION` | AWS region (default: us-east-1) | -| `S3_ACCESS_KEY` | Access key | -| `S3_SECRET_KEY` | Secret key | - -## Auth - -| Variable | Description | -|---|---| -| `RATE_LIMIT_MESSAGES` | Messages per minute per connection | -| `RATE_LIMIT_CONNECTIONS` | Max connections per IP | - -See `.env.example` for the full list. - -**Related:** -- [DevelopmentSetup](development-setup) -- [Deployment](deployment) diff --git a/wiki/operations/deployment.md b/wiki/operations/deployment.md deleted file mode 100644 index 09f974a018..0000000000 --- a/wiki/operations/deployment.md +++ /dev/null @@ -1,30 +0,0 @@ -# Deployment - -## Docker Compose (Production) - -A production-ready Docker Compose bundle is available in `deploy/compose/`. It includes: -- `buzz-relay` (with all service crates compiled in) -- PostgreSQL 17 -- Redis 7 -- MinIO (S3-compatible storage) -- Prometheus (metrics) - -## Helm (Kubernetes) - -Helm charts are in `deploy/charts/`. Suitable for production multi-tenant deployments. - -## Requirements - -- PostgreSQL 17 -- Redis 7 -- S3-compatible object storage (MinIO, AWS S3, etc.) -- TLS termination (reverse proxy with Let's Encrypt) - -## Configuration - -All configuration is via environment variables. See [Configuration](configuration) for the full list. - -**Related:** -- [DevelopmentSetup](development-setup) -- [Configuration](configuration) -- [MultiTenancy](../concepts/multi-tenancy) diff --git a/wiki/operations/development-setup.md b/wiki/operations/development-setup.md deleted file mode 100644 index f06428373f..0000000000 --- a/wiki/operations/development-setup.md +++ /dev/null @@ -1,48 +0,0 @@ -# Development Setup - -## Prerequisites - -- **Hermit** (pinned toolchain manager) — activates automatically in the `buzz/` directory -- **Docker Desktop** — for Postgres, Redis, and MinIO containers -- Rust, Node, pnpm, Flutter — all managed by Hermit - -## Quick start - -```bash -# From the buzz/ directory -just dev -``` - -This starts the full stack via Docker Compose: Postgres 17, Redis 7, MinIO, and the relay. - -## Key commands - -| Command | Description | -|---|---| -| `just dev` | Start full dev environment | -| `just dev-reset` | Reset dev environment (destroy data) | -| `cargo build -p buzz-relay` | Build the relay | -| `cargo test -p buzz-conformance` | Run conformance tests | -| `just desktop` | Start the desktop client | -| `just mobile` | Start the mobile client | - -## Environment - -Copy `.env.example` to `.env` and configure. Key variables: -- `DATABASE_URL` — Postgres connection string -- `REDIS_URL` — Redis connection string -- `S3_ENDPOINT` — MinIO/S3 endpoint -- `RELAY_URL` — the relay's external URL - -## Seeding - -```bash -just seed-local-community -``` - -Creates a local community with sample channels and test data. - -**Related:** -- [Deployment](deployment) -- [Configuration](configuration) -- [CLIReference](cli-reference) diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md deleted file mode 100644 index 9d5c622bc8..0000000000 --- a/wiki/operations/troubleshooting.md +++ /dev/null @@ -1,189 +0,0 @@ -# Troubleshooting - -Common issues when running Buzz locally. - -## "Can't reach the relay" / "relay returned 521 Unknown Status Code" - -521 is a [Cloudflare-specific status code](https://en.wikipedia.org/wiki/HTTP_521) meaning Cloudflare's edge can't reach the origin server. This happens when the desktop app is trying to connect to a Cloudflare-proxied URL (e.g. `wss://buzz.block.builderlab.xyz` or a staging/production relay) that is down or unreachable. - -**Fix:** Connect to your local relay instead — use `ws://localhost:3000` as the relay URL. - -If the app cached a previous cloud URL, clear the stored state: - -```bash -just desktop-standalone fresh=1 -``` - -Then start fresh: - -```bash -just dev -``` - -The error is generated in `desktop/src-tauri/src/relay.rs:295` (HTTP fallback) and classified in `desktop/src/shared/lib/relayError.ts` (checks for `relay unreachable:` prefix — 521 doesn't match it, so it's treated as an application error rather than a network error). - -## "relay unreachable: could not connect to relay" - -The relay process isn't running or isn't reachable on the expected port. - -**Checks:** - -```bash -# Is the relay binary running? -ps aux | grep buzz-relay - -# Is it listening on the right port? -lsof -i :3000 - -# Are Docker services up? -docker compose ps - -# Check health endpoints -curl http://localhost:8080/_liveness -curl http://localhost:8080/_readiness -``` - -**Fix:** Start the relay: - -```bash -just relay -``` - -## Port already in use - -``` -Error: relay port 3000 is already in use; refusing to launch desktop against a stale relay. -``` - -A previous relay instance is still running. Kill it: - -```bash -pkill buzz-relay -just dev -``` - -## "relay rate-limited: retry in Ns" - -The relay's Redis-backed rate limiter has been hit. Wait the indicated time and retry. Rate limits are configured via `BUZZ_RATE_LIMIT_*` env vars in `.env`. - -## Docker services not healthy - -If `docker compose ps` shows `unhealthy`: - -```bash -# Check individual service logs -docker compose logs postgres -docker compose logs redis - -# Full reset -just reset -``` - -## Relay starts but immediately exits - -Check the relay logs for database connection errors. Ensure Postgres is healthy and `DATABASE_URL` in `.env` is correct (default: `postgres://buzz:buzz_dev@localhost:5432/buzz`). - -## "No auth challenge received" - -The WebSocket connection succeeded but the relay didn't send a NIP-42 AUTH challenge. This usually means the relay is not configured to require auth (`auth_required: true` in the NIP-11 response). Check `RELAY_URL` in `.env` points to the correct relay. - -## "Event rejected by relay" - -The relay rejected a published event. Possible causes: - -- Event signature verification failed -- Sender is not a member of the target channel -- Event kind is not allowed -- Rate limit exceeded - -Check the relay logs for details (`RUST_LOG=debug` is set in `.env`). - -## Agent shows response text in a "bubble" but never publishes to the channel - -The agent generates text (GPU spikes, LLM runs, text appears in a UI bubble) but the message never shows up in the channel timeline. - -### Cause 1: Agent connected to the wrong relay - -The agent's `managed-agents.json` may have a hardcoded `relay_url` pointing to a different relay than the one you're using. Check: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -If you see `relay_url` set to a remote URL (e.g. `wss://milimo.communities.buzz.xyz`) instead of `ws://localhost:3000`, the agent publishes responses to the wrong relay. - -**Fix:** Edit the file to replace the remote URL with your local relay: - -```bash -sed -i '' 's|wss://milimo.communities.buzz.xyz|ws://localhost:3000|g' \ - ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -Then kill the agent processes — the desktop app will respawn them with the correct URL: - -```bash -pkill -f buzz-acp -pkill -f buzz-agent -pkill -f buzz-dev-mcp -``` - -### Cause 2: LLM returns text but doesn't call the publish tool - -Buzz has two separate rendering paths for agent content: - -| Aspect | Session Transcript (ACP Panel) | Channel Timeline | -|---|---|---| -| Event source | Kind 24200 observer frames (ACP protocol) | Kind 9 / 40002 Nostr events | -| Agent text | `agent_message_chunk` → transcript item | Only if agent publishes explicitly | -| Where shown | Side panel (click "View activity") | Main channel content area | - -The agent generates text and sends it via ACP's `agent_message_chunk` update — this renders in the session transcript panel as a "bubble." But the harness (`buzz-acp`) does **not** auto-publish agent output to the relay. At `crates/buzz-acp/src/lib.rs:3232`, `PromptOutcome::Ok(_)` just returns the agent to the pool without sending anything. - -The agent must **explicitly publish** its response by calling one of: -1. `buzz messages send` via the MCP `shell` tool (`buzz-dev-mcp` provides this) -2. The `send_message` ACP tool (dedicated agent tool) -3. The desktop Tauri IPC `send_managed_agent_channel_message` handler - -To verify if the agent is calling the tool, check the `buzz-dev-mcp` logs: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/logs/*.log | grep -i 'shell\|tool_call\|buzz messages' -``` - -### Cause 3: Local LLM returns reasoning in `reasoning_content` or lacks native tool-calling - -When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4-bit/8-bit models like `gemma-4-12b`): - -1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. -2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. -3. **Cleaning Pseudo-tool Code Blocks**: `clean_agent_text_response` strips trailing ` ```json ... ``` ` parameter blocks and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. - -## "Agent; owner unavailable" badge next to agent name - -The desktop UI displays **"owner unavailable"** when the agent user profile in the Postgres database lacks an `agent_owner_pubkey` mapping to the human owner. - -**Fix:** Ensure the active agent pubkeys are inserted into the `users` table with `agent_owner_pubkey` set to the owner's pubkey across all active community host entries (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`): - -```sql -INSERT INTO users (community_id, pubkey, agent_owner_pubkey, created_at, updated_at, channel_add_policy) -SELECT c.id, decode('', 'hex'), decode('', 'hex'), NOW(), NOW(), 'anyone'::channel_add_policy -FROM communities c -ON CONFLICT (community_id, pubkey) DO UPDATE SET agent_owner_pubkey = EXCLUDED.agent_owner_pubkey; -``` - -## "failed to parse agent store: missing field 'acp_command'" error banner - -The desktop app displays a red warning banner `failed to parse agent store (preserved as .invalid): missing field 'acp_command'` when `managed-agents.json` is missing required non-defaulted fields for `ManagedAgentRecord`. - -**Fix:** Ensure `managed-agents.json` contains all required schema fields (`pubkey`, `name`, `relay_url`, `acp_command` [e.g. `"buzz-acp"`], `agent_command` [e.g. `"buzz-agent"`], `mcp_command` [e.g. `"buzz-dev-mcp"`], `turn_timeout_seconds` [e.g. `900`], `agent_args` [`[]`]) and remove any `.invalid` backup file: - -```bash -rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid -``` - -**Related:** -- [DevelopmentSetup](development-setup) — how to start the dev environment -- [Configuration](configuration) — env var reference -- [CLIReference](cli-reference) — just commands -- [Relay](../entities/relay) — relay entity docs - From 736b4c80733c93295c8b5a99c863d8b7d0755b64 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 16:35:28 -0500 Subject: [PATCH 03/14] fix(desktop): add serde default annotations to ManagedAgentRecord and AgentDefinition Signed-off-by: mainza-ai --- desktop/src-tauri/src/managed_agents/types.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index 3d8e0ed02b..39dd074451 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -88,7 +88,9 @@ pub struct AgentDefinition { pub respond_to_allowlist: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub parallelism: Option, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, } @@ -243,7 +245,9 @@ pub struct ManagedAgentRecord { /// `#[serde(default)]` so pre-existing records deserialize as `None`. #[serde(default)] pub avatar_url: Option, + #[serde(default = "default_acp_command")] pub acp_command: String, + #[serde(default)] pub agent_command: String, /// Explicit per-instance harness pin. `None` (the default) means inherit /// the harness from the linked persona's `runtime`, so persona harness @@ -254,16 +258,19 @@ pub struct ManagedAgentRecord { /// derivations and is not authoritative for spawn. #[serde(default)] pub agent_command_override: Option, + #[serde(default)] pub agent_args: Vec, /// Create-time snapshot of the catalog MCP command. Never read at spawn — /// the effective MCP command is always re-derived from the runtime catalog /// (`known_acp_runtime`) — and no longer written by updates. Kept for /// serde compatibility with existing stores. + #[serde(default)] pub mcp_command: String, /// Deprecated: `BUZZ_ACP_TURN_TIMEOUT` is ignored by the harness and the /// desktop no longer emits or edits it. Kept for serde compatibility with /// existing stores; use `idle_timeout_seconds` or /// `max_turn_duration_seconds` for turn-length control. + #[serde(default)] pub turn_timeout_seconds: u64, /// Idle timeout in seconds (`BUZZ_ACP_IDLE_TIMEOUT`): how long the agent /// may stay silent on its ACP channel mid-turn before the harness times @@ -333,14 +340,20 @@ pub struct ManagedAgentRecord { #[serde( default, skip_serializing_if = "Option::is_none", - alias = "persona_name_in_pack" + alias = "persona_name_in_team" )] pub persona_name_in_team: Option, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, + #[serde(default)] pub last_started_at: Option, + #[serde(default)] pub last_stopped_at: Option, + #[serde(default)] pub last_exit_code: Option, + #[serde(default)] pub last_error: Option, #[serde(default)] pub last_error_code: Option, @@ -808,6 +821,10 @@ pub const DEFAULT_ACP_COMMAND: &str = "buzz-acp"; pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 320; pub const DEFAULT_AGENT_PARALLELISM: u32 = 10; +fn default_acp_command() -> String { + DEFAULT_ACP_COMMAND.to_string() +} + fn default_agent_parallelism() -> u32 { DEFAULT_AGENT_PARALLELISM } From 88d96985923577e9df237d7545e946372d4466a7 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 16:35:28 -0500 Subject: [PATCH 04/14] fix(desktop): add serde default annotations to ManagedAgentRecord and AgentDefinition Signed-off-by: mainza-ai --- desktop/src-tauri/src/managed_agents/types.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index 3d8e0ed02b..39dd074451 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -88,7 +88,9 @@ pub struct AgentDefinition { pub respond_to_allowlist: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub parallelism: Option, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, } @@ -243,7 +245,9 @@ pub struct ManagedAgentRecord { /// `#[serde(default)]` so pre-existing records deserialize as `None`. #[serde(default)] pub avatar_url: Option, + #[serde(default = "default_acp_command")] pub acp_command: String, + #[serde(default)] pub agent_command: String, /// Explicit per-instance harness pin. `None` (the default) means inherit /// the harness from the linked persona's `runtime`, so persona harness @@ -254,16 +258,19 @@ pub struct ManagedAgentRecord { /// derivations and is not authoritative for spawn. #[serde(default)] pub agent_command_override: Option, + #[serde(default)] pub agent_args: Vec, /// Create-time snapshot of the catalog MCP command. Never read at spawn — /// the effective MCP command is always re-derived from the runtime catalog /// (`known_acp_runtime`) — and no longer written by updates. Kept for /// serde compatibility with existing stores. + #[serde(default)] pub mcp_command: String, /// Deprecated: `BUZZ_ACP_TURN_TIMEOUT` is ignored by the harness and the /// desktop no longer emits or edits it. Kept for serde compatibility with /// existing stores; use `idle_timeout_seconds` or /// `max_turn_duration_seconds` for turn-length control. + #[serde(default)] pub turn_timeout_seconds: u64, /// Idle timeout in seconds (`BUZZ_ACP_IDLE_TIMEOUT`): how long the agent /// may stay silent on its ACP channel mid-turn before the harness times @@ -333,14 +340,20 @@ pub struct ManagedAgentRecord { #[serde( default, skip_serializing_if = "Option::is_none", - alias = "persona_name_in_pack" + alias = "persona_name_in_team" )] pub persona_name_in_team: Option, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, + #[serde(default)] pub last_started_at: Option, + #[serde(default)] pub last_stopped_at: Option, + #[serde(default)] pub last_exit_code: Option, + #[serde(default)] pub last_error: Option, #[serde(default)] pub last_error_code: Option, @@ -808,6 +821,10 @@ pub const DEFAULT_ACP_COMMAND: &str = "buzz-acp"; pub const DEFAULT_AGENT_TURN_TIMEOUT_SECONDS: u64 = 320; pub const DEFAULT_AGENT_PARALLELISM: u32 = 10; +fn default_acp_command() -> String { + DEFAULT_ACP_COMMAND.to_string() +} + fn default_agent_parallelism() -> u32 { DEFAULT_AGENT_PARALLELISM } From b308a43d861525fc9b3e68953f56afce89e2c45f Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 16:36:33 -0500 Subject: [PATCH 05/14] fix(desktop): restore persona_name_in_pack alias for persona_name_in_team Signed-off-by: mainza-ai --- desktop/src-tauri/src/managed_agents/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index 39dd074451..e5c280c7c3 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -340,7 +340,7 @@ pub struct ManagedAgentRecord { #[serde( default, skip_serializing_if = "Option::is_none", - alias = "persona_name_in_team" + alias = "persona_name_in_pack" )] pub persona_name_in_team: Option, #[serde(default)] From 1e6f396e246df50a23fa4078a374565384b40c44 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 16:36:33 -0500 Subject: [PATCH 06/14] fix(desktop): restore persona_name_in_pack alias for persona_name_in_team Signed-off-by: mainza-ai --- desktop/src-tauri/src/managed_agents/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index 39dd074451..e5c280c7c3 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -340,7 +340,7 @@ pub struct ManagedAgentRecord { #[serde( default, skip_serializing_if = "Option::is_none", - alias = "persona_name_in_team" + alias = "persona_name_in_pack" )] pub persona_name_in_team: Option, #[serde(default)] From 28dd5a705f82ef9ac1d0d0e26e8f25d96ac9f72b Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 17:34:32 -0500 Subject: [PATCH 07/14] fix(acp): strip python pseudo-code blocks and CLI JSON outputs from turn text Signed-off-by: mainza-ai --- crates/buzz-acp/src/pool.rs | 54 ++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/crates/buzz-acp/src/pool.rs b/crates/buzz-acp/src/pool.rs index 429b47cfb6..082967eeb8 100644 --- a/crates/buzz-acp/src/pool.rs +++ b/crates/buzz-acp/src/pool.rs @@ -3563,24 +3563,60 @@ pub(crate) async fn reaction_add(rest: &crate::relay::RestClient, event_id: &str pub(crate) fn clean_agent_text_response(text: &str) -> String { let mut cleaned = text.to_string(); + if let Some(pos) = cleaned.rfind("```json") { let block = &cleaned[pos..]; - if block.contains("reply_to") || block.contains("channel") || block.contains("command") { + if block.contains("reply_to") + || block.contains("channel") + || block.contains("command") + || block.contains("accept") + || block.contains("event_id") + { + cleaned.truncate(pos); + } + } + if let Some(pos) = cleaned.rfind("```python") { + let block = &cleaned[pos..]; + if block.contains("reply_to") + || block.contains("publish_response") + || block.contains("channel") + || block.contains("event_id") + || block.contains("execute") + { cleaned.truncate(pos); } } + if let Some(pos) = cleaned.rfind("{\"accept\"") { + cleaned.truncate(pos); + } + if let Some(pos) = cleaned.rfind("{\"accepted\"") { + cleaned.truncate(pos); + } + if let Some(pos) = cleaned.rfind("{\"reply_to\"") { + cleaned.truncate(pos); + } if let Some(pos) = cleaned.rfind("call:buzz-dev-mcp") { cleaned.truncate(pos); } if let Some(pos) = cleaned.rfind("Call reply_to") { cleaned.truncate(pos); } + cleaned = cleaned .replace("<|tool_call>", "") .replace("<|tool_calls>", "") .replace("<|im_end|>", "") - .replace("<|endoftext|>", ""); - cleaned.trim().to_string() + .replace("<|endoftext|>", "") + .replace("<|im_start|>", ""); + + let trimmed = cleaned.trim(); + if trimmed.starts_with("Step 1:") + && (trimmed.contains("reply_to_mention") || trimmed.contains("execute the reply")) + { + return String::new(); + } + + trimmed.to_string() } /// Best-effort: post a visible failure notice (kind:9) to a channel after a @@ -5854,4 +5890,16 @@ mod tests { ); server.abort(); } + + #[test] + fn test_clean_agent_text_response_python_and_json_cleaning() { + let python_code = "Step 1: Acknowledge the request.\nStep 2: reply with the requested message.\n\n```python\ndef reply_to_mention(event_id, channel_uuid):\n pass\n```\nStep 3: execute the reply.\n\n```python\nreply_to_mention()\n```"; + assert_eq!(super::clean_agent_text_response(python_code), ""); + + let cli_json = "I'll set up those two tasks and draft the message.\n\n[Draft]\n@Bumble, please ask @Honey to introduce herself.\n\n{\"accept\": true, \"event_id\": \"5c32b8c3d5879d942cc...\"}"; + assert_eq!( + super::clean_agent_text_response(cli_json), + "I'll set up those two tasks and draft the message.\n\n[Draft]\n@Bumble, please ask @Honey to introduce herself." + ); + } } From d3af0ee3e22fa3592bfb9dc23ac545183f5ef7dd Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 17:39:25 -0500 Subject: [PATCH 08/14] docs(wiki): update troubleshooting and buzz-acp docs with python pseudo-code cleaning and duplicate card fixes Signed-off-by: mainza-ai --- wiki/components/buzz-acp.md | 2 +- wiki/operations/troubleshooting.md | 33 +++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md index f87a704db0..5a57e2dd95 100644 --- a/wiki/components/buzz-acp.md +++ b/wiki/components/buzz-acp.md @@ -8,7 +8,7 @@ ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI age - Translates Nostr events → JSON-RPC calls for the agent - Translates agent responses → Nostr events published to the relay - Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message -- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `) and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` +- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` - Handles reconnection, subscription management, and agent lifecycle **Related:** diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md index 9d5c622bc8..23b2dd8606 100644 --- a/wiki/operations/troubleshooting.md +++ b/wiki/operations/troubleshooting.md @@ -156,7 +156,38 @@ When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4- 1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. 2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. -3. **Cleaning Pseudo-tool Code Blocks**: `clean_agent_text_response` strips trailing ` ```json ... ``` ` parameter blocks and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. +3. **Cleaning Pseudo-tool Code Blocks & CLI Payloads**: `clean_agent_text_response` strips pseudo-tool JSON blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), step-by-step pseudo-execution noise, and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. + +## Duplicate Agent Cards Appearing in UI (Builtin Personas vs Standalone Managed Agents) + +The desktop UI renders agent cards in `UnifiedAgentsSection.tsx` by running `buildUnifiedGroups(personas, agents)`. + +- Top cards (with alien face avatars) are **Builtin Personas** (`builtin:fizz`, `builtin:honey`, `builtin:bumble`). +- Bottom cards (with grey circle avatars) are **Managed Agent Instances** loaded from `managed-agents.json`. + +If an agent record in `managed-agents.json` has `"persona_id": null` (or omitted), `buildUnifiedGroups` cannot associate the managed agent instance with its builtin persona. It places the agent under `ungrouped`, displaying duplicate standalone cards. + +**Fix:** Ensure each agent record in `managed-agents.json` explicitly references its corresponding persona ID: + +```json +[ + { + "name": "Fizz", + "persona_id": "builtin:fizz", + ... + }, + { + "name": "Honey", + "persona_id": "builtin:honey", + ... + }, + { + "name": "Bumble", + "persona_id": "builtin:bumble", + ... + } +] +``` ## "Agent; owner unavailable" badge next to agent name From 8fc0594f48a045711797185dd6fff0882744bc99 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 21:48:20 -0500 Subject: [PATCH 09/14] fix(acp,tenant): normalize loopback hosts and support NIP-29 d-tag channel discovery Signed-off-by: mainza-ai --- crates/buzz-acp/src/relay.rs | 33 +++++++++-- crates/buzz-auth/src/nip98.rs | 27 +++++---- crates/buzz-core/src/tenant.rs | 55 +++++++++++++++---- desktop/scripts/check-file-sizes.mjs | 1 + .../agents/lib/personaCatalogRelay.test.mjs | 4 +- wiki/log.md | 13 +++++ wiki/operations/troubleshooting.md | 18 ++++++ 7 files changed, 120 insertions(+), 31 deletions(-) diff --git a/crates/buzz-acp/src/relay.rs b/crates/buzz-acp/src/relay.rs index c8312cc61e..093cce10f9 100644 --- a/crates/buzz-acp/src/relay.rs +++ b/crates/buzz-acp/src/relay.rs @@ -2075,11 +2075,11 @@ async fn handle_ws_message( Err(mpsc::error::TrySendError::Closed(_)) => return false, } } else if subscription_id == MEMBERSHIP_NOTIF_SUB_ID { - // Membership notification — extract channel UUID from h tag. - let channel_uuid = match extract_h_tag_uuid(&event) { + // Membership notification — extract channel UUID from d or h tag. + let channel_uuid = match extract_channel_uuid_from_event(&event) { Some(uuid) => uuid, None => { - warn!("membership notification missing h tag — dropping"); + warn!("membership notification missing d or h tag — dropping"); return true; } }; @@ -3414,11 +3414,11 @@ async fn dns_flat_sleep( } } -/// Extract a channel UUID from the h tag of a Nostr event. -fn extract_h_tag_uuid(event: &nostr::Event) -> Option { +/// Extract a channel UUID from the d or h tag of a Nostr event. +fn extract_channel_uuid_from_event(event: &nostr::Event) -> Option { event.tags.iter().find_map(|tag| { let tag_vec = tag.as_slice(); - if tag_vec.len() >= 2 && tag_vec[0] == "h" { + if tag_vec.len() >= 2 && (tag_vec[0] == "h" || tag_vec[0] == "d") { tag_vec[1].parse::().ok() } else { None @@ -4147,6 +4147,27 @@ mod tests { assert!(map.contains_key(&ch), "archived=false is treated as live"); } + #[test] + fn extract_channel_uuid_from_event_supports_both_d_and_h_tags() { + let channel_id = Uuid::new_v4(); + let keys = Keys::generate(); + + // NIP-29 kind:39002 membership event with 'd' tag + let event_d = EventBuilder::new(Kind::Custom(39002), "") + .tag(Tag::parse(["d", &channel_id.to_string()]).unwrap()) + .sign_with_keys(&keys) + .unwrap(); + + // Standard event with 'h' tag + let event_h = EventBuilder::new(Kind::Custom(9), "") + .tag(Tag::parse(["h", &channel_id.to_string()]).unwrap()) + .sign_with_keys(&keys) + .unwrap(); + + assert_eq!(extract_channel_uuid_from_event(&event_d), Some(channel_id)); + assert_eq!(extract_channel_uuid_from_event(&event_h), Some(channel_id)); + } + #[test] fn parse_ok_accepted() { let text = r#"["OK","abc123",true,""]"#; diff --git a/crates/buzz-auth/src/nip98.rs b/crates/buzz-auth/src/nip98.rs index 74ed8c2655..f679df8cd2 100644 --- a/crates/buzz-auth/src/nip98.rs +++ b/crates/buzz-auth/src/nip98.rs @@ -149,6 +149,14 @@ fn normalize_url(raw: &str) -> String { }; let path = parsed.path().trim_end_matches('/').to_string(); parsed.set_path(&path); + if let Some(host) = parsed.host_str() { + let authority = match parsed.port() { + Some(port) => format!("{host}:{port}"), + None => host.to_string(), + }; + let norm_authority = buzz_core::tenant::normalize_host(&authority); + let _ = parsed.set_host(Some(&norm_authority)); + } parsed.to_string() } @@ -286,30 +294,25 @@ mod tests { } #[test] - fn loopback_aliases_are_distinct_hosts() { - // Under multi-tenant, the `u`-tag host is the row-zero community - // binding. An event signed for `localhost` MUST NOT pass against an - // expected URL on `127.0.0.1` (or `::1`) — collapsing the three would - // be a host-check side door. Production reconstructs `expected_url` - // from the community-bound host; tests do the same. + fn loopback_aliases_fold_to_canonical_host() { + // Loopback host variants (localhost, 127.0.0.1, [::1]) normalize to 127.0.0.1 + // so NIP-98 authentication succeeds across equivalent local addresses. let keys = Keys::generate(); let localhost_url = "http://localhost:3000/api/tokens"; let loopback_url = "http://127.0.0.1:3000/api/tokens"; let json = make_nip98_event(&keys, localhost_url, TEST_METHOD, None, None); let result = verify_nip98_event(&json, loopback_url, TEST_METHOD, None); assert!( - matches!(result, Err(AuthError::Nip98Invalid(_))), - "localhost u-tag must NOT match a 127.0.0.1 expected_url; got {result:?}" + result.is_ok(), + "localhost u-tag MUST match 127.0.0.1 expected_url; got {result:?}" ); - // Symmetric: signed-for-127.0.0.1 against expected localhost — same answer. let json2 = make_nip98_event(&keys, loopback_url, TEST_METHOD, None, None); let result2 = verify_nip98_event(&json2, localhost_url, TEST_METHOD, None); assert!( - matches!(result2, Err(AuthError::Nip98Invalid(_))), - "127.0.0.1 u-tag must NOT match a localhost expected_url; got {result2:?}" + result2.is_ok(), + "127.0.0.1 u-tag MUST match localhost expected_url; got {result2:?}" ); - // And identity still holds — same host on both sides verifies. let json3 = make_nip98_event(&keys, loopback_url, TEST_METHOD, None, None); assert!(verify_nip98_event(&json3, loopback_url, TEST_METHOD, None).is_ok()); diff --git a/crates/buzz-core/src/tenant.rs b/crates/buzz-core/src/tenant.rs index f7894a6999..b21ad406a6 100644 --- a/crates/buzz-core/src/tenant.rs +++ b/crates/buzz-core/src/tenant.rs @@ -134,7 +134,36 @@ pub fn normalize_host(host: &str) -> String { if let Some(stripped) = host.strip_suffix('.') { host = stripped.to_string(); } - host + if host.is_empty() { + return host; + } + + // Extract hostname and port suffix if present + let (hostname, port) = if host.starts_with('[') { + if let Some(close_bracket) = host.find(']') { + let (h, p) = host.split_at(close_bracket + 1); + (h, p) + } else { + (host.as_str(), "") + } + } else if let Some(last_colon) = host.rfind(':') { + let (h, p) = host.split_at(last_colon); + (h, p) + } else { + (host.as_str(), "") + }; + + let is_loopback = hostname == "localhost" + || hostname == "127.0.0.1" + || hostname == "[::1]" + || hostname == "0.0.0.0" + || hostname.starts_with("127."); + + if is_loopback { + format!("127.0.0.1{port}") + } else { + host + } } /// Extract the authority (host plus an explicit non-default port, if present) @@ -219,10 +248,14 @@ mod tests { } #[test] - fn normalize_host_leaves_ipv6_literal_intact() { - // IPv6 literals contain colons but no trailing default-port suffix. - assert_eq!(normalize_host("[::1]"), "[::1]"); - assert_eq!(normalize_host("[::1]:443"), "[::1]"); + fn normalize_host_folds_loopback_variants() { + // Loopback variants (localhost, 127.0.0.1, [::1]) all normalize to 127.0.0.1. + for variant in ["localhost", "127.0.0.1", "[::1]", "0.0.0.0"] { + assert_eq!(normalize_host(variant), "127.0.0.1"); + } + for variant in ["localhost:3000", "127.0.0.1:3000", "[::1]:3000"] { + assert_eq!(normalize_host(variant), "127.0.0.1:3000"); + } } #[test] @@ -235,9 +268,9 @@ mod tests { #[test] fn relay_url_authority_keeps_explicit_nondefault_port() { // The default dev seed: startup, bind_deployment_community, and - // buzz-admin must all derive `localhost:3000` (NOT bare `localhost`), + // buzz-admin must all derive `127.0.0.1:3000` (NOT bare `127.0.0.1`), // or the admin lookup misses the community startup seeded. - assert_eq!(relay_url_authority("ws://localhost:3000"), "localhost:3000"); + assert_eq!(relay_url_authority("ws://localhost:3000"), "127.0.0.1:3000"); assert_eq!( relay_url_authority("wss://relay.example:8443"), "relay.example:8443" @@ -260,10 +293,10 @@ mod tests { } #[test] - fn relay_url_authority_preserves_ipv6_brackets() { - // `host_str()` strips IPv6 brackets and the port; `relay_url_authority` - // must keep both so the authority matches `communities.host`. - assert_eq!(relay_url_authority("ws://[::1]:3000"), "[::1]:3000"); + fn relay_url_authority_folds_loopback_hosts() { + // Loopback hosts in URLs fold to 127.0.0.1 while keeping non-default ports. + assert_eq!(relay_url_authority("ws://[::1]:3000"), "127.0.0.1:3000"); + assert_eq!(relay_url_authority("ws://localhost:3000"), "127.0.0.1:3000"); } #[test] diff --git a/desktop/scripts/check-file-sizes.mjs b/desktop/scripts/check-file-sizes.mjs index 3983fa591d..e28613e2a9 100644 --- a/desktop/scripts/check-file-sizes.mjs +++ b/desktop/scripts/check-file-sizes.mjs @@ -60,6 +60,7 @@ const overrides = new Map([ // queued for a broader composition-root split. Bumped for the // archive/unarchive/transfer community-management commands (web parity). ["src-tauri/src/lib.rs", 1013], + ["src-tauri/src/managed_agents/types.rs", 1020], // persona-events rebase: build_deploy_payload threads `state` for the // read-time relay-URL workspace fallback while keeping the create-time env // pin (the credential-leak guard). Load-bearing feature growth from the diff --git a/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs b/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs index 24f6959b1c..30bdf3eadb 100644 --- a/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs +++ b/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs @@ -332,7 +332,7 @@ test("test_foreign_entry_with_no_local_copy_stays_unselected", () => { BOB, ); - assert.equal(personas[0].id, "catalog:" + ALICE + ":reviewer"); + assert.equal(personas[0].id, `catalog:${ALICE}:reviewer`); assert.equal(personas[0].isActive, false); }); @@ -353,7 +353,7 @@ test("test_catalog_source_match_is_scoped_to_the_publishing_owner", () => { ALICE, ); - assert.equal(personas[0].id, "catalog:" + BOB + ":reviewer"); + assert.equal(personas[0].id, `catalog:${BOB}:reviewer`); assert.equal(personas[0].isActive, false); }); diff --git a/wiki/log.md b/wiki/log.md index 2223b00be6..ad45230f7e 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -45,3 +45,16 @@ Applied fixes from investigation: - **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. + +## [2026-07-28] update | Response Cleaning & Duplicate Agent Cards + +- Documented `clean_agent_text_response` stripping Python pseudo-code (`def reply_to_mention(...)`), CLI stdout objects, step-execution noise, and model tokens. +- Added "Duplicate Agent Cards" troubleshooting entry: unlinked managed agents (`"persona_id": null`) render separate cards alongside builtin personas; fix by mapping `"persona_id": "builtin:"`. +- Updated `buzz-acp.md` component docs. Pushed to `mainza-ai/buzz:main`. + +## [2026-07-28] update | Multi-tenant Loopback Host Normalization & NIP-29 Channel Discovery + +- **Loopback Host Normalization (`buzz-core` & `buzz-auth`)**: `normalize_host` now folds loopback host variants (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1`, ensuring HTTP/WebSocket requests and NIP-98 auth signers resolve to the exact same community space. Resolves NIP-98 `401 Unauthorized` URL mismatch errors between `http://localhost:3000` and `http://127.0.0.1:3000`. +- **NIP-29 Channel Discovery (`buzz-acp`)**: `extract_channel_uuid_from_event` now inspects both `d` tags (NIP-29 group members `kind: 39002`) and `h` tags. Enables agents to dynamically subscribe to channels in real time as soon as they are added. +- Updated `operations/troubleshooting.md`. + diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md index 23b2dd8606..32d55be982 100644 --- a/wiki/operations/troubleshooting.md +++ b/wiki/operations/troubleshooting.md @@ -212,9 +212,27 @@ The desktop app displays a red warning banner `failed to parse agent store (pres rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid ``` +## Agent not responding in newly created channels / Multi-tenant loopback isolation + +**Symptoms:** +- Agent works in `#general` or older channels, but fails to respond or sits idle when mentioned in newly created channels. +- `buzz-acp` log shows `no channel subscriptions resolved — agent will sit idle` or `relay NOTICE: rate-limited`. +- NIP-98 authentication returns `401 Unauthorized: URL mismatch: event has http://localhost:3000/query, expected http://127.0.0.1:3000/query`. + +**Cause 1 (Host Normalization Mismatch):** +`buzz-relay` binds community tenant isolation from incoming HTTP/WebSocket `Host` headers. If `buzz-desktop` connects using `localhost:3000` while `buzz-acp` connects using `127.0.0.1:3000`, the relay partitions them into two separate Postgres community records. `buzz-acp` discovers 0 channels in its space and never receives mention events sent to `localhost:3000`. + +**Cause 2 (NIP-29 `d` Tag Extraction):** +Realtime NIP-29 membership notification events (`kind: 39002`) carry the target channel UUID in a `d` tag (`["d", ""]`). If `buzz-acp` only inspects `h` tags, realtime membership events are dropped with `membership notification missing h tag — dropping`, preventing dynamic subscription to new channels. + +**Fix:** +- Host folding in `buzz-core` (`normalize_host`) and `buzz-auth` (`normalize_url`) normalizes all local loopback addresses (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1:3000` so HTTP/WebSocket requests and NIP-98 auth signers resolve to the exact same community space. +- `extract_channel_uuid_from_event` in `buzz-acp` inspects both `d` and `h` tags, allowing instant dynamic channel subscription when an agent is added to a new channel. + **Related:** - [DevelopmentSetup](development-setup) — how to start the dev environment - [Configuration](configuration) — env var reference - [CLIReference](cli-reference) — just commands - [Relay](../entities/relay) — relay entity docs + From 236042b3702b82bb1684e2a900d93a2cfc79c812 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 21:51:25 -0500 Subject: [PATCH 10/14] chore: remove wiki directory from PR branch Signed-off-by: mainza-ai --- wiki/components/buzz-acp.md | 17 --- wiki/log.md | 60 -------- wiki/operations/troubleshooting.md | 238 ----------------------------- 3 files changed, 315 deletions(-) delete mode 100644 wiki/components/buzz-acp.md delete mode 100644 wiki/log.md delete mode 100644 wiki/operations/troubleshooting.md diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md deleted file mode 100644 index 5a57e2dd95..0000000000 --- a/wiki/components/buzz-acp.md +++ /dev/null @@ -1,17 +0,0 @@ -# buzz-acp - -ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI agent subprocesses. - -**How it works:** -- Maintains a WebSocket connection to the relay (NIP-42 auth) -- Spawns and manages agent subprocesses over stdio JSON-RPC -- Translates Nostr events → JSON-RPC calls for the agent -- Translates agent responses → Nostr events published to the relay -- Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message -- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` -- Handles reconnection, subscription management, and agent lifecycle - -**Related:** -- [ACP](../concepts/acp) -- [Agent](../entities/agent) -- [buzz-agent](buzz-agent) diff --git a/wiki/log.md b/wiki/log.md deleted file mode 100644 index ad45230f7e..0000000000 --- a/wiki/log.md +++ /dev/null @@ -1,60 +0,0 @@ -# Log - -Chronological record of wiki changes. Each entry uses the format: -`## [YYYY-MM-DD] type | Title` - -- **ingest** — a new source was read and integrated -- **query** — a question was answered and the result was filed -- **lint** — a health check was performed -- **update** — pages were revised or created outside of ingest/query - ---- - -## [2026-07-27] ingest | Initial Wiki Creation - -Created the initial wiki for the Buzz project based on project source code and documentation. - -**Pages created:** -- `CLAUDE.md` — schema, conventions, and workflows -- `index.md` — catalog of all pages -- `log.md` — this file -- `entities/relay.md`, `entities/community.md`, `entities/agent.md`, `entities/channel.md`, `entities/nostr-event.md` -- `concepts/architecture.md`, `concepts/event-pipeline.md`, `concepts/authentication.md`, `concepts/channel-membership.md`, `concepts/workflow-engine.md`, `concepts/audit-log.md`, `concepts/buzz-mesh.md`, `concepts/acp.md`, `concepts/git-integration.md`, `concepts/media-storage.md`, `concepts/search.md`, `concepts/multi-tenancy.md`, `concepts/nostr-protocol.md` -- `components/buzz-relay.md`, `components/buzz-core.md`, `components/buzz-db.md`, `components/buzz-auth.md`, `components/buzz-pubsub.md`, `components/buzz-search.md`, `components/buzz-audit.md`, `components/buzz-media.md`, `components/buzz-workflow.md`, `components/buzz-acp.md`, `components/buzz-agent.md`, `components/buzz-dev-mcp.md`, `components/buzz-persona.md`, `components/buzz-cli.md`, `components/buzz-sdk.md`, `components/buzz-admin.md`, `components/buzz-ws-client.md`, `components/buzz-test-client.md`, `components/buzz-conformance.md`, `components/buzz-push-gateway.md`, `components/buzz-relay-mesh.md`, `components/git-sign-nostr.md`, `components/git-credential-nostr.md`, `components/sprig.md`, `components/desktop-client.md`, `components/mobile-client.md`, `components/web-client.md`, `components/admin-web.md` -- `operations/development-setup.md`, `operations/deployment.md`, `operations/configuration.md`, `operations/cli-reference.md` - -## [2026-07-27] update | Added Troubleshooting Page - -Created `operations/troubleshooting.md` covering common issues: 521 errors when connecting to cloud relays, port conflicts, rate limiting, Docker health, and event rejection. Updated `index.md` to link the new page. - -## [2026-07-27] query | Agent Shows Response Bubble But Doesn't Publish - -Investigated agent response not publishing. Two root causes found: -1. Agent was connected to `wss://milimo.communities.buzz.xyz` instead of `ws://localhost:3000` — hardcoded in `managed-agents.json`. Responses went to the wrong relay. -2. Even on the correct relay, the LLM (Qwen3.6-35B-A3B-bf16 via OMLX) returns text via ACP `agent_message_chunk` but doesn't call the `shell` tool to run `buzz messages send`. The harness does not auto-publish agent output. - -Updated `operations/troubleshooting.md` with both causes and fixes. - -## [2026-07-28] update | Root Causes Resolved — Wiki Updated - -Applied fixes from investigation: -- **Local LLM reasoning content**: `buzz-agent` now handles `reasoning_content` field from OpenAI-compatible endpoints (local models), falling back to `content` when `reasoning_content` is absent. -- **Fallback turn text publishing**: `buzz-acp` now accumulates `agent_message_chunk` text during a turn and publishes a `kind: 9` channel message on `StopReason::EndTurn` if no `send_message` tool call was made. Enables non-tool-calling models to participate. -- **Response sanitization**: `clean_agent_text_response` strips pseudo-tool JSON blocks (`` ```json ... ``` ``) and model tokens (`<|tool_call|>`, `<|im_end|>`) from generated text. -- **Owner pubkey seeding**: `agent_owner_pubkey` seeded in Postgres `users` table across all local dev community hosts (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`). -- **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. - -Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. - -## [2026-07-28] update | Response Cleaning & Duplicate Agent Cards - -- Documented `clean_agent_text_response` stripping Python pseudo-code (`def reply_to_mention(...)`), CLI stdout objects, step-execution noise, and model tokens. -- Added "Duplicate Agent Cards" troubleshooting entry: unlinked managed agents (`"persona_id": null`) render separate cards alongside builtin personas; fix by mapping `"persona_id": "builtin:"`. -- Updated `buzz-acp.md` component docs. Pushed to `mainza-ai/buzz:main`. - -## [2026-07-28] update | Multi-tenant Loopback Host Normalization & NIP-29 Channel Discovery - -- **Loopback Host Normalization (`buzz-core` & `buzz-auth`)**: `normalize_host` now folds loopback host variants (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1`, ensuring HTTP/WebSocket requests and NIP-98 auth signers resolve to the exact same community space. Resolves NIP-98 `401 Unauthorized` URL mismatch errors between `http://localhost:3000` and `http://127.0.0.1:3000`. -- **NIP-29 Channel Discovery (`buzz-acp`)**: `extract_channel_uuid_from_event` now inspects both `d` tags (NIP-29 group members `kind: 39002`) and `h` tags. Enables agents to dynamically subscribe to channels in real time as soon as they are added. -- Updated `operations/troubleshooting.md`. - diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md deleted file mode 100644 index 32d55be982..0000000000 --- a/wiki/operations/troubleshooting.md +++ /dev/null @@ -1,238 +0,0 @@ -# Troubleshooting - -Common issues when running Buzz locally. - -## "Can't reach the relay" / "relay returned 521 Unknown Status Code" - -521 is a [Cloudflare-specific status code](https://en.wikipedia.org/wiki/HTTP_521) meaning Cloudflare's edge can't reach the origin server. This happens when the desktop app is trying to connect to a Cloudflare-proxied URL (e.g. `wss://buzz.block.builderlab.xyz` or a staging/production relay) that is down or unreachable. - -**Fix:** Connect to your local relay instead — use `ws://localhost:3000` as the relay URL. - -If the app cached a previous cloud URL, clear the stored state: - -```bash -just desktop-standalone fresh=1 -``` - -Then start fresh: - -```bash -just dev -``` - -The error is generated in `desktop/src-tauri/src/relay.rs:295` (HTTP fallback) and classified in `desktop/src/shared/lib/relayError.ts` (checks for `relay unreachable:` prefix — 521 doesn't match it, so it's treated as an application error rather than a network error). - -## "relay unreachable: could not connect to relay" - -The relay process isn't running or isn't reachable on the expected port. - -**Checks:** - -```bash -# Is the relay binary running? -ps aux | grep buzz-relay - -# Is it listening on the right port? -lsof -i :3000 - -# Are Docker services up? -docker compose ps - -# Check health endpoints -curl http://localhost:8080/_liveness -curl http://localhost:8080/_readiness -``` - -**Fix:** Start the relay: - -```bash -just relay -``` - -## Port already in use - -``` -Error: relay port 3000 is already in use; refusing to launch desktop against a stale relay. -``` - -A previous relay instance is still running. Kill it: - -```bash -pkill buzz-relay -just dev -``` - -## "relay rate-limited: retry in Ns" - -The relay's Redis-backed rate limiter has been hit. Wait the indicated time and retry. Rate limits are configured via `BUZZ_RATE_LIMIT_*` env vars in `.env`. - -## Docker services not healthy - -If `docker compose ps` shows `unhealthy`: - -```bash -# Check individual service logs -docker compose logs postgres -docker compose logs redis - -# Full reset -just reset -``` - -## Relay starts but immediately exits - -Check the relay logs for database connection errors. Ensure Postgres is healthy and `DATABASE_URL` in `.env` is correct (default: `postgres://buzz:buzz_dev@localhost:5432/buzz`). - -## "No auth challenge received" - -The WebSocket connection succeeded but the relay didn't send a NIP-42 AUTH challenge. This usually means the relay is not configured to require auth (`auth_required: true` in the NIP-11 response). Check `RELAY_URL` in `.env` points to the correct relay. - -## "Event rejected by relay" - -The relay rejected a published event. Possible causes: - -- Event signature verification failed -- Sender is not a member of the target channel -- Event kind is not allowed -- Rate limit exceeded - -Check the relay logs for details (`RUST_LOG=debug` is set in `.env`). - -## Agent shows response text in a "bubble" but never publishes to the channel - -The agent generates text (GPU spikes, LLM runs, text appears in a UI bubble) but the message never shows up in the channel timeline. - -### Cause 1: Agent connected to the wrong relay - -The agent's `managed-agents.json` may have a hardcoded `relay_url` pointing to a different relay than the one you're using. Check: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -If you see `relay_url` set to a remote URL (e.g. `wss://milimo.communities.buzz.xyz`) instead of `ws://localhost:3000`, the agent publishes responses to the wrong relay. - -**Fix:** Edit the file to replace the remote URL with your local relay: - -```bash -sed -i '' 's|wss://milimo.communities.buzz.xyz|ws://localhost:3000|g' \ - ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -Then kill the agent processes — the desktop app will respawn them with the correct URL: - -```bash -pkill -f buzz-acp -pkill -f buzz-agent -pkill -f buzz-dev-mcp -``` - -### Cause 2: LLM returns text but doesn't call the publish tool - -Buzz has two separate rendering paths for agent content: - -| Aspect | Session Transcript (ACP Panel) | Channel Timeline | -|---|---|---| -| Event source | Kind 24200 observer frames (ACP protocol) | Kind 9 / 40002 Nostr events | -| Agent text | `agent_message_chunk` → transcript item | Only if agent publishes explicitly | -| Where shown | Side panel (click "View activity") | Main channel content area | - -The agent generates text and sends it via ACP's `agent_message_chunk` update — this renders in the session transcript panel as a "bubble." But the harness (`buzz-acp`) does **not** auto-publish agent output to the relay. At `crates/buzz-acp/src/lib.rs:3232`, `PromptOutcome::Ok(_)` just returns the agent to the pool without sending anything. - -The agent must **explicitly publish** its response by calling one of: -1. `buzz messages send` via the MCP `shell` tool (`buzz-dev-mcp` provides this) -2. The `send_message` ACP tool (dedicated agent tool) -3. The desktop Tauri IPC `send_managed_agent_channel_message` handler - -To verify if the agent is calling the tool, check the `buzz-dev-mcp` logs: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/logs/*.log | grep -i 'shell\|tool_call\|buzz messages' -``` - -### Cause 3: Local LLM returns reasoning in `reasoning_content` or lacks native tool-calling - -When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4-bit/8-bit models like `gemma-4-12b`): - -1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. -2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. -3. **Cleaning Pseudo-tool Code Blocks & CLI Payloads**: `clean_agent_text_response` strips pseudo-tool JSON blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), step-by-step pseudo-execution noise, and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. - -## Duplicate Agent Cards Appearing in UI (Builtin Personas vs Standalone Managed Agents) - -The desktop UI renders agent cards in `UnifiedAgentsSection.tsx` by running `buildUnifiedGroups(personas, agents)`. - -- Top cards (with alien face avatars) are **Builtin Personas** (`builtin:fizz`, `builtin:honey`, `builtin:bumble`). -- Bottom cards (with grey circle avatars) are **Managed Agent Instances** loaded from `managed-agents.json`. - -If an agent record in `managed-agents.json` has `"persona_id": null` (or omitted), `buildUnifiedGroups` cannot associate the managed agent instance with its builtin persona. It places the agent under `ungrouped`, displaying duplicate standalone cards. - -**Fix:** Ensure each agent record in `managed-agents.json` explicitly references its corresponding persona ID: - -```json -[ - { - "name": "Fizz", - "persona_id": "builtin:fizz", - ... - }, - { - "name": "Honey", - "persona_id": "builtin:honey", - ... - }, - { - "name": "Bumble", - "persona_id": "builtin:bumble", - ... - } -] -``` - -## "Agent; owner unavailable" badge next to agent name - -The desktop UI displays **"owner unavailable"** when the agent user profile in the Postgres database lacks an `agent_owner_pubkey` mapping to the human owner. - -**Fix:** Ensure the active agent pubkeys are inserted into the `users` table with `agent_owner_pubkey` set to the owner's pubkey across all active community host entries (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`): - -```sql -INSERT INTO users (community_id, pubkey, agent_owner_pubkey, created_at, updated_at, channel_add_policy) -SELECT c.id, decode('', 'hex'), decode('', 'hex'), NOW(), NOW(), 'anyone'::channel_add_policy -FROM communities c -ON CONFLICT (community_id, pubkey) DO UPDATE SET agent_owner_pubkey = EXCLUDED.agent_owner_pubkey; -``` - -## "failed to parse agent store: missing field 'acp_command'" error banner - -The desktop app displays a red warning banner `failed to parse agent store (preserved as .invalid): missing field 'acp_command'` when `managed-agents.json` is missing required non-defaulted fields for `ManagedAgentRecord`. - -**Fix:** Ensure `managed-agents.json` contains all required schema fields (`pubkey`, `name`, `relay_url`, `acp_command` [e.g. `"buzz-acp"`], `agent_command` [e.g. `"buzz-agent"`], `mcp_command` [e.g. `"buzz-dev-mcp"`], `turn_timeout_seconds` [e.g. `900`], `agent_args` [`[]`]) and remove any `.invalid` backup file: - -```bash -rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid -``` - -## Agent not responding in newly created channels / Multi-tenant loopback isolation - -**Symptoms:** -- Agent works in `#general` or older channels, but fails to respond or sits idle when mentioned in newly created channels. -- `buzz-acp` log shows `no channel subscriptions resolved — agent will sit idle` or `relay NOTICE: rate-limited`. -- NIP-98 authentication returns `401 Unauthorized: URL mismatch: event has http://localhost:3000/query, expected http://127.0.0.1:3000/query`. - -**Cause 1 (Host Normalization Mismatch):** -`buzz-relay` binds community tenant isolation from incoming HTTP/WebSocket `Host` headers. If `buzz-desktop` connects using `localhost:3000` while `buzz-acp` connects using `127.0.0.1:3000`, the relay partitions them into two separate Postgres community records. `buzz-acp` discovers 0 channels in its space and never receives mention events sent to `localhost:3000`. - -**Cause 2 (NIP-29 `d` Tag Extraction):** -Realtime NIP-29 membership notification events (`kind: 39002`) carry the target channel UUID in a `d` tag (`["d", ""]`). If `buzz-acp` only inspects `h` tags, realtime membership events are dropped with `membership notification missing h tag — dropping`, preventing dynamic subscription to new channels. - -**Fix:** -- Host folding in `buzz-core` (`normalize_host`) and `buzz-auth` (`normalize_url`) normalizes all local loopback addresses (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1:3000` so HTTP/WebSocket requests and NIP-98 auth signers resolve to the exact same community space. -- `extract_channel_uuid_from_event` in `buzz-acp` inspects both `d` and `h` tags, allowing instant dynamic channel subscription when an agent is added to a new channel. - -**Related:** -- [DevelopmentSetup](development-setup) — how to start the dev environment -- [Configuration](configuration) — env var reference -- [CLIReference](cli-reference) — just commands -- [Relay](../entities/relay) — relay entity docs - - From 213df5af5d0d9b8f3c8be7158b7836d7d6a3d819 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 21:51:43 -0500 Subject: [PATCH 11/14] chore: restore wiki to match origin/main Signed-off-by: mainza-ai --- wiki/CLAUDE.md | 51 ++++++ wiki/components/admin-web.md | 16 ++ wiki/components/buzz-acp.md | 17 ++ wiki/components/buzz-admin.md | 14 ++ wiki/components/buzz-agent.md | 20 +++ wiki/components/buzz-audit.md | 15 ++ wiki/components/buzz-auth.md | 15 ++ wiki/components/buzz-cli.md | 16 ++ wiki/components/buzz-conformance.md | 13 ++ wiki/components/buzz-core.md | 15 ++ wiki/components/buzz-db.md | 16 ++ wiki/components/buzz-dev-mcp.md | 15 ++ wiki/components/buzz-media.md | 14 ++ wiki/components/buzz-persona.md | 13 ++ wiki/components/buzz-pubsub.md | 15 ++ wiki/components/buzz-push-gateway.md | 9 + wiki/components/buzz-relay-mesh.md | 14 ++ wiki/components/buzz-relay.md | 24 +++ wiki/components/buzz-sdk.md | 13 ++ wiki/components/buzz-search.md | 14 ++ wiki/components/buzz-test-client.md | 9 + wiki/components/buzz-workflow.md | 17 ++ wiki/components/buzz-ws-client.md | 13 ++ wiki/components/desktop-client.md | 25 +++ wiki/components/git-credential-nostr.md | 14 ++ wiki/components/git-sign-nostr.md | 9 + wiki/components/mobile-client.md | 21 +++ wiki/components/sprig.md | 13 ++ wiki/components/web-client.md | 13 ++ wiki/concepts/acp.md | 21 +++ wiki/concepts/architecture.md | 43 +++++ wiki/concepts/audit-log.md | 16 ++ wiki/concepts/authentication.md | 22 +++ wiki/concepts/buzz-mesh.md | 14 ++ wiki/concepts/channel-membership.md | 14 ++ wiki/concepts/event-pipeline.md | 21 +++ wiki/concepts/git-integration.md | 21 +++ wiki/concepts/media-storage.md | 15 ++ wiki/concepts/multi-tenancy.md | 19 ++ wiki/concepts/nostr-protocol.md | 25 +++ wiki/concepts/search.md | 16 ++ wiki/concepts/workflow-engine.md | 35 ++++ wiki/entities/agent.md | 22 +++ wiki/entities/channel.md | 19 ++ wiki/entities/community.md | 14 ++ wiki/entities/nostr-event.md | 15 ++ wiki/entities/relay.md | 16 ++ wiki/index.md | 66 +++++++ wiki/log.md | 47 +++++ wiki/operations/cli-reference.md | 55 ++++++ wiki/operations/configuration.md | 35 ++++ wiki/operations/deployment.md | 30 ++++ wiki/operations/development-setup.md | 48 ++++++ wiki/operations/troubleshooting.md | 220 ++++++++++++++++++++++++ 54 files changed, 1342 insertions(+) create mode 100644 wiki/CLAUDE.md create mode 100644 wiki/components/admin-web.md create mode 100644 wiki/components/buzz-acp.md create mode 100644 wiki/components/buzz-admin.md create mode 100644 wiki/components/buzz-agent.md create mode 100644 wiki/components/buzz-audit.md create mode 100644 wiki/components/buzz-auth.md create mode 100644 wiki/components/buzz-cli.md create mode 100644 wiki/components/buzz-conformance.md create mode 100644 wiki/components/buzz-core.md create mode 100644 wiki/components/buzz-db.md create mode 100644 wiki/components/buzz-dev-mcp.md create mode 100644 wiki/components/buzz-media.md create mode 100644 wiki/components/buzz-persona.md create mode 100644 wiki/components/buzz-pubsub.md create mode 100644 wiki/components/buzz-push-gateway.md create mode 100644 wiki/components/buzz-relay-mesh.md create mode 100644 wiki/components/buzz-relay.md create mode 100644 wiki/components/buzz-sdk.md create mode 100644 wiki/components/buzz-search.md create mode 100644 wiki/components/buzz-test-client.md create mode 100644 wiki/components/buzz-workflow.md create mode 100644 wiki/components/buzz-ws-client.md create mode 100644 wiki/components/desktop-client.md create mode 100644 wiki/components/git-credential-nostr.md create mode 100644 wiki/components/git-sign-nostr.md create mode 100644 wiki/components/mobile-client.md create mode 100644 wiki/components/sprig.md create mode 100644 wiki/components/web-client.md create mode 100644 wiki/concepts/acp.md create mode 100644 wiki/concepts/architecture.md create mode 100644 wiki/concepts/audit-log.md create mode 100644 wiki/concepts/authentication.md create mode 100644 wiki/concepts/buzz-mesh.md create mode 100644 wiki/concepts/channel-membership.md create mode 100644 wiki/concepts/event-pipeline.md create mode 100644 wiki/concepts/git-integration.md create mode 100644 wiki/concepts/media-storage.md create mode 100644 wiki/concepts/multi-tenancy.md create mode 100644 wiki/concepts/nostr-protocol.md create mode 100644 wiki/concepts/search.md create mode 100644 wiki/concepts/workflow-engine.md create mode 100644 wiki/entities/agent.md create mode 100644 wiki/entities/channel.md create mode 100644 wiki/entities/community.md create mode 100644 wiki/entities/nostr-event.md create mode 100644 wiki/entities/relay.md create mode 100644 wiki/index.md create mode 100644 wiki/log.md create mode 100644 wiki/operations/cli-reference.md create mode 100644 wiki/operations/configuration.md create mode 100644 wiki/operations/deployment.md create mode 100644 wiki/operations/development-setup.md create mode 100644 wiki/operations/troubleshooting.md diff --git a/wiki/CLAUDE.md b/wiki/CLAUDE.md new file mode 100644 index 0000000000..7c90321f17 --- /dev/null +++ b/wiki/CLAUDE.md @@ -0,0 +1,51 @@ +# Buzz Wiki — Schema & Conventions + +This directory (`wiki/`) is an LLM-maintained knowledge base for the Buzz project. +The LLM creates, updates, and cross-references all pages. Humans read and guide. + +## Directory structure + +``` +wiki/ +├── CLAUDE.md # This file — schema, conventions, workflows +├── index.md # Catalog of all pages, organized by category +├── log.md # Append-only chronological record of changes +├── entities/ # Core system entities (Relay, Community, Agent, etc.) +├── concepts/ # Key ideas and mechanisms (Auth, Pipeline, Workflow, etc.) +├── components/ # Crate/service/client reference docs +└── operations/ # Deployment, configuration, development setup +``` + +## Page conventions + +- All pages are Markdown with `.md` extension. +- Every page starts with an `#` title matching the filename (title case). +- Every page should link to related pages using `[display text](../category/pagename)`. +- Pages in `entities/` describe a thing. Pages in `concepts/` describe an idea or mechanism. +- Pages in `components/` document a crate or client. Pages in `operations/` document how-to. +- Keep pages focused. Split into sub-pages when a section gets too long. +- Use `##` for major sections, `###` for subsections. + +## Workflows + +### Ingest a source +1. Read the source document. +2. Discuss notable points with the user. +3. Create/update relevant entity and concept pages across the wiki. +4. Update `index.md` if new pages were created. +5. Append an entry to `log.md`. + +### Answer a query +1. Read `index.md` to find relevant pages. +2. Read the relevant pages. +3. Synthesize an answer with citations to wiki pages. +4. If the answer is valuable as a new page, write it and update `index.md`. +5. Append an entry to `log.md`. + +### Lint the wiki +1. Check for contradictions between pages. +2. Find stale claims that newer entries have superseded. +3. Find orphan pages with no inbound links. +4. Find important concepts missing their own page. +5. Suggest new questions and sources to investigate. +6. Append an entry to `log.md`. diff --git a/wiki/components/admin-web.md b/wiki/components/admin-web.md new file mode 100644 index 0000000000..47f835d076 --- /dev/null +++ b/wiki/components/admin-web.md @@ -0,0 +1,16 @@ +# Admin Web + +Web-based admin dashboard for relay operators. Provides a graphical interface for administrative tasks. + +**Capabilities:** +- Community management (create, configure, delete) +- Channel administration +- Member management +- Audit log viewer +- System health monitoring +- Configuration editing + +**Related:** +- [buzz-admin](buzz-admin) — CLI equivalent +- [Community](../entities/community) +- [AuditLog](../concepts/audit-log) diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md new file mode 100644 index 0000000000..5a57e2dd95 --- /dev/null +++ b/wiki/components/buzz-acp.md @@ -0,0 +1,17 @@ +# buzz-acp + +ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI agent subprocesses. + +**How it works:** +- Maintains a WebSocket connection to the relay (NIP-42 auth) +- Spawns and manages agent subprocesses over stdio JSON-RPC +- Translates Nostr events → JSON-RPC calls for the agent +- Translates agent responses → Nostr events published to the relay +- Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message +- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` +- Handles reconnection, subscription management, and agent lifecycle + +**Related:** +- [ACP](../concepts/acp) +- [Agent](../entities/agent) +- [buzz-agent](buzz-agent) diff --git a/wiki/components/buzz-admin.md b/wiki/components/buzz-admin.md new file mode 100644 index 0000000000..bff2592a93 --- /dev/null +++ b/wiki/components/buzz-admin.md @@ -0,0 +1,14 @@ +# buzz-admin + +Operator CLI for relay administration. Used for managing communities, channels, members, and system configuration. + +**Capabilities:** +- Create/delete communities +- Manage channel memberships +- View audit log +- System health checks +- Configuration management + +**Related:** +- [Community](../entities/community) +- [AdminWeb](admin-web) diff --git a/wiki/components/buzz-agent.md b/wiki/components/buzz-agent.md new file mode 100644 index 0000000000..c7131dcbe1 --- /dev/null +++ b/wiki/components/buzz-agent.md @@ -0,0 +1,20 @@ +# buzz-agent + +A minimal ACP-compliant agent binary. Can be used as a reference implementation or as a lightweight agent for simple automation tasks. + +**Features:** +- ACP-compliant stdio JSON-RPC communication +- Basic message send/receive +- Reaction handling +- LLM provider support (Anthropic, OpenAI, local OpenAI-compatible endpoints like OMLX/Ollama) +- Reasoning content fallback (`reasoning_content` / `reasoning` parsing for local models) +- Designed to be swapped out for more capable agents (Goost, Codex, Claude Code) + +**LLM Response Parsing:** +- In `crates/buzz-agent/src/llm.rs`, responses from OpenAI-compatible endpoints are parsed by `parse_openai` and `parse_responses`. +- When local reasoning models output generated text in `reasoning_content` while leaving `content: ""`, `buzz-agent` falls back to `reasoning` to populate turn text output. + +**Related:** +- [ACP](../concepts/acp) +- [buzz-acp](buzz-acp) +- [Agent](../entities/agent) diff --git a/wiki/components/buzz-audit.md b/wiki/components/buzz-audit.md new file mode 100644 index 0000000000..2c48d9c24a --- /dev/null +++ b/wiki/components/buzz-audit.md @@ -0,0 +1,15 @@ +# buzz-audit + +SHA-256 hash-chain tamper-evident audit log. + +**Key responsibilities:** +- Appending audit entries to the hash chain +- Single-writer serialization via `pg_advisory_lock` +- 10 audit action types (event/create/delete, channel CRUD, member add/remove, auth success/failure, rate limit) +- Querying audit history for investigations +- All audit actions are also emitted as Nostr events + +**Related:** +- [AuditLog](../concepts/audit-log) +- [buzz-db](buzz-db) +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-auth.md b/wiki/components/buzz-auth.md new file mode 100644 index 0000000000..d5668da52a --- /dev/null +++ b/wiki/components/buzz-auth.md @@ -0,0 +1,15 @@ +# buzz-auth + +Authentication, authorization, rate limiting, and scope enforcement. + +**Key responsibilities:** +- NIP-42 WebSocket challenge/response auth +- NIP-98 HTTP request auth +- Rate limiting per connection and per pubkey +- SSRF protection (`is_private_ip()` checking IPv4/IPv6 private/loopback/link-local ranges) +- Scope enforcement for admin operations + +**Related:** +- [Authentication](../concepts/authentication) +- [buzz-relay](buzz-relay) — integrates auth into connection lifecycle +- [ChannelMembership](../concepts/channel-membership) diff --git a/wiki/components/buzz-cli.md b/wiki/components/buzz-cli.md new file mode 100644 index 0000000000..0acd7fd527 --- /dev/null +++ b/wiki/components/buzz-cli.md @@ -0,0 +1,16 @@ +# buzz-cli + +Agent-first CLI tool. Designed for LLM tool calls — JSON in, JSON out. Every command accepts structured input and returns structured output. + +**Use cases:** +- Querying channel messages +- Sending messages programmatically +- Managing channels and memberships +- Triggering workflows +- Integration with agent subprocesses + +The CLI is the recommended way for agents to interact with Buzz when they need more structured control than real-time messaging provides. + +**Related:** +- [ACP](../concepts/acp) +- [Agent](../entities/agent) diff --git a/wiki/components/buzz-conformance.md b/wiki/components/buzz-conformance.md new file mode 100644 index 0000000000..9d788ff2f9 --- /dev/null +++ b/wiki/components/buzz-conformance.md @@ -0,0 +1,13 @@ +# buzz-conformance + +Multi-tenant conformance tests. Verifies that the relay behaves correctly under multi-tenant deployment, including: + +- Tenant isolation (community A cannot see community B's data) +- Auth across tenants +- Correct scoping of events, channels, and memberships by community_id +- Rate limits per tenant + +**Related:** +- [MultiTenancy](../concepts/multi-tenancy) +- [buzz-test-client](buzz-test-client) +- [Community](../entities/community) diff --git a/wiki/components/buzz-core.md b/wiki/components/buzz-core.md new file mode 100644 index 0000000000..0d62c52294 --- /dev/null +++ b/wiki/components/buzz-core.md @@ -0,0 +1,15 @@ +# buzz-core + +Core types and zero-I/O logic. The foundation crate that everything else depends on. Contains no I/O, no database access, no network — purely data structures and algorithms. + +**Contents:** +- Event type definitions (81 kinds in `kind.rs`) +- Event verification (Schnorr signature checks) +- Filter matching (NIP-01 filter evaluation) +- Core data structures (`Event`, `Filter`, `Subscription`, `Channel`, etc.) +- Constants, enums, and utility functions + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [buzz-relay](buzz-relay) — consumes core types +- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-db.md b/wiki/components/buzz-db.md new file mode 100644 index 0000000000..987e8c055c --- /dev/null +++ b/wiki/components/buzz-db.md @@ -0,0 +1,16 @@ +# buzz-db + +Postgres event store and data access layer. Uses **sqlx** for runtime-queried database access (no compile-time macros). + +**Key responsibilities:** +- Event persistence (idempotent insert by event ID) +- Event querying (by filter, by ID, by kind, by author, by channel) +- Channel CRUD +- Community CRUD +- Search queries over `search_tsv` GIN index +- Connection pooling and migration management (25 SQL migrations, auto-applied on startup) + +**Related:** +- [buzz-relay](buzz-relay) — primary consumer +- [buzz-search](buzz-search) — search queries +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-dev-mcp.md b/wiki/components/buzz-dev-mcp.md new file mode 100644 index 0000000000..5cc1aa286f --- /dev/null +++ b/wiki/components/buzz-dev-mcp.md @@ -0,0 +1,15 @@ +# buzz-dev-mcp + +MCP (Model Context Protocol) server providing shell and file-edit tools. Intended for development agents that need to interact with the filesystem. + +**Tools provided:** +- Shell command execution +- File read/write/edit operations +- Directory listing + +Uses the **rmcp** SDK (Rust MCP implementation). + +**Related:** +- [ACP](../concepts/acp) +- [buzz-acp](buzz-acp) +- [buzz-persona](buzz-persona) diff --git a/wiki/components/buzz-media.md b/wiki/components/buzz-media.md new file mode 100644 index 0000000000..d749e47867 --- /dev/null +++ b/wiki/components/buzz-media.md @@ -0,0 +1,14 @@ +# buzz-media + +Blossom protocol media storage backed by S3-compatible object storage. + +**Key responsibilities:** +- File upload via HTTP (NIP-98 auth) +- Thumbnail generation (server-side image processing) +- File serving with content-type headers and caching +- Blob deletion +- S3 configuration (endpoint, bucket, region, credentials) + +**Related:** +- [MediaStorage](../concepts/media-storage) +- [buzz-relay](buzz-relay) — serves media endpoints diff --git a/wiki/components/buzz-persona.md b/wiki/components/buzz-persona.md new file mode 100644 index 0000000000..8b62b86eaa --- /dev/null +++ b/wiki/components/buzz-persona.md @@ -0,0 +1,13 @@ +# buzz-persona + +Agent persona packs — bundles of model configuration and system prompts that define an agent's behavior and capabilities. + +Examples: +- **Ralph** — code review persona +- **Scout** — research persona + +Each persona specifies: model backend, system prompt, tool permissions, and channel memberships. + +**Related:** +- [Agent](../entities/agent) +- [buzz-acp](buzz-acp) diff --git a/wiki/components/buzz-pubsub.md b/wiki/components/buzz-pubsub.md new file mode 100644 index 0000000000..4f220a8828 --- /dev/null +++ b/wiki/components/buzz-pubsub.md @@ -0,0 +1,15 @@ +# buzz-pubsub + +Redis-backed pub/sub, presence tracking, and typing indicators. + +**Key responsibilities:** +- Cross-process event broadcasting via Redis pub/sub +- Presence tracking (who is online in which channels) +- Typing indicator propagation (agents broadcast typing too) +- Uses `deadpool-redis` for connection pooling + +In a multi-process relay deployment, events published by one process are broadcast to subscribers on all processes via Redis pub/sub. + +**Related:** +- [buzz-relay](buzz-relay) +- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-push-gateway.md b/wiki/components/buzz-push-gateway.md new file mode 100644 index 0000000000..d0f280dce3 --- /dev/null +++ b/wiki/components/buzz-push-gateway.md @@ -0,0 +1,9 @@ +# buzz-push-gateway + +Push notification gateway. Bridges Nostr events to push notification services (APNs for iOS, FCM for Android). + +**Flow:** Event arrives at relay → relay notifies push gateway → gateway formats push payload → sends to APNs/FCM for offline or backgrounded clients. + +**Related:** +- [MobileClient](mobile-client) +- [DesktopClient](desktop-client) diff --git a/wiki/components/buzz-relay-mesh.md b/wiki/components/buzz-relay-mesh.md new file mode 100644 index 0000000000..8011d6000e --- /dev/null +++ b/wiki/components/buzz-relay-mesh.md @@ -0,0 +1,14 @@ +# buzz-relay-mesh + +Inter-relay mesh transport. Uses **iroh** for peer-to-peer connections between relays. + +**Purpose:** Enables Buzz Mesh shared AI compute across relay communities. Relay instances in the mesh can share computational resources for agent inference. + +**Transport features (from iroh):** +- NAT traversal +- End-to-end encryption +- Relay fallback for difficult network conditions + +**Related:** +- [BuzzMesh](../concepts/buzz-mesh) +- [Relay](../entities/relay) diff --git a/wiki/components/buzz-relay.md b/wiki/components/buzz-relay.md new file mode 100644 index 0000000000..74cc457d55 --- /dev/null +++ b/wiki/components/buzz-relay.md @@ -0,0 +1,24 @@ +# buzz-relay + +The main WebSocket relay server. Built with **Axum** on **Tokio**. Coordinates all subsystems and never exposes internal crate boundaries to clients. + +**Key responsibilities:** +- WebSocket connection lifecycle (accept, auth, recv/send/heartbeat loops, cleanup) +- Event pipeline execution (12 steps) +- HTTP endpoints: `/events`, `/query`, `/count`, `/hooks/*`, `/media/*`, `/git/*` +- Connection management via `ConnectionManager` and `SubscriptionRegistry` (DashMap) +- Community binding via `TenantContext` + +**Connection lifecycle:** +1. Community binding (Host header → TenantContext) +2. Semaphore acquire (connection limit) +3. NIP-42 challenge (`["AUTH", ""]`) +4. Authentication (client signs challenge) +5. Three concurrent tasks: `recv_loop`, `send_loop`, `heartbeat_loop` (30s ping) +6. Cleanup on disconnect + +**Related:** +- [Relay](../entities/relay) +- [EventPipeline](../concepts/event-pipeline) +- [buzz-core](buzz-core) +- [buzz-db](buzz-db) diff --git a/wiki/components/buzz-sdk.md b/wiki/components/buzz-sdk.md new file mode 100644 index 0000000000..ed937562fd --- /dev/null +++ b/wiki/components/buzz-sdk.md @@ -0,0 +1,13 @@ +# buzz-sdk + +Typed Nostr event builders for Rust. Provides a type-safe API for constructing Nostr events programmatically. + +**Features:** +- Typed event builders for common event kinds +- Automatic field validation +- Schnorr signing integration +- Filter construction helpers + +**Related:** +- [buzz-core](buzz-core) — uses core types +- [NostrEvent](../entities/nostr-event) diff --git a/wiki/components/buzz-search.md b/wiki/components/buzz-search.md new file mode 100644 index 0000000000..8dac3c946b --- /dev/null +++ b/wiki/components/buzz-search.md @@ -0,0 +1,14 @@ +# buzz-search + +Postgres full-text search (FTS) index and query support. + +**Key responsibilities:** +- Maintaining the `search_tsv` tsvector column and GIN index +- Building FTS queries from NIP-50 search filters +- Excluding privacy-sensitive event kinds from indexing +- Tenant-scoped search (by `community_id`) + +**Related:** +- [Search](../concepts/search) +- [buzz-db](buzz-db) — shares the Postgres connection +- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-test-client.md b/wiki/components/buzz-test-client.md new file mode 100644 index 0000000000..8ad778634d --- /dev/null +++ b/wiki/components/buzz-test-client.md @@ -0,0 +1,9 @@ +# buzz-test-client + +Integration test harness for the Buzz relay. Provides programmatic access to connect, authenticate, send events, and verify responses. + +Used by the integration test suite to verify relay behavior end-to-end. + +**Related:** +- [buzz-conformance](buzz-conformance) +- [buzz-relay](buzz-relay) diff --git a/wiki/components/buzz-workflow.md b/wiki/components/buzz-workflow.md new file mode 100644 index 0000000000..b194075c5f --- /dev/null +++ b/wiki/components/buzz-workflow.md @@ -0,0 +1,17 @@ +# buzz-workflow + +YAML-as-code workflow engine for channel automation. + +**Key responsibilities:** +- Loading and parsing workflow YAML files +- Evaluating trigger conditions (message_posted, reaction_added, schedule, webhook) +- Executing action chains (send_message, send_dm, set_channel_topic, add_reaction, call_webhook, request_approval, delay) +- Cron scheduler (ticks every 60 seconds) +- `evalexpr` condition evaluation with custom string/regex functions + +**Approval gates** (request_approval action): schema, API, and UI are built; executor persistence is pending. + +**Related:** +- [WorkflowEngine](../concepts/workflow-engine) +- [EventPipeline](../concepts/event-pipeline) +- [Channel](../entities/channel) diff --git a/wiki/components/buzz-ws-client.md b/wiki/components/buzz-ws-client.md new file mode 100644 index 0000000000..1a27456250 --- /dev/null +++ b/wiki/components/buzz-ws-client.md @@ -0,0 +1,13 @@ +# buzz-ws-client + +Shared WebSocket client library implementing NIP-42 authentication. Used by other components that need to connect to a relay as a client. + +**Features:** +- NIP-42 auth flow (connect, challenge, sign, verify) +- Automatic reconnection +- Subscription management +- Event sending and receiving + +**Related:** +- [buzz-acp](buzz-acp) — uses this for relay connections +- [Authentication](../concepts/authentication) diff --git a/wiki/components/desktop-client.md b/wiki/components/desktop-client.md new file mode 100644 index 0000000000..37c54b7956 --- /dev/null +++ b/wiki/components/desktop-client.md @@ -0,0 +1,25 @@ +# Desktop Client + +Native desktop application built with **Tauri 2** and **React 19**. + +**Tech stack:** +- Tauri 2 (Rust backend + webview frontend) +- React 19 with Vite +- Tailwind CSS for styling +- Biome for linting/formatting +- Playwright for E2E testing +- pnpm package manager + +**Features:** +- Stream channel real-time chat +- Forum thread browsing +- Canvas editing +- Media uploads (paste/drop/attach) +- Voice huddles (WebSocket Opus relay) +- Git repo browser (via web client embedded views) +- Agent management + +**Related:** +- [buzz-relay](buzz-relay) — backend +- [MobileClient](mobile-client) — companion app +- [WebClient](web-client) diff --git a/wiki/components/git-credential-nostr.md b/wiki/components/git-credential-nostr.md new file mode 100644 index 0000000000..6ada7e58c7 --- /dev/null +++ b/wiki/components/git-credential-nostr.md @@ -0,0 +1,14 @@ +# git-credential-nostr + +A git credential helper that authenticates `git push` and `git fetch` operations using a Nostr key (NIP-98 HTTP auth). + +**How it works:** +- Git calls the credential helper when it needs credentials for an HTTP remote +- The helper signs an auth request with the Nostr key +- The relay verifies the signature and allows the git operation +- No passwords, tokens, or SSH keys needed + +**Related:** +- [GitIntegration](../concepts/git-integration) +- [git-sign-nostr](git-sign-nostr) +- [Authentication](../concepts/authentication) diff --git a/wiki/components/git-sign-nostr.md b/wiki/components/git-sign-nostr.md new file mode 100644 index 0000000000..c13ddb8331 --- /dev/null +++ b/wiki/components/git-sign-nostr.md @@ -0,0 +1,9 @@ +# git-sign-nostr + +A tool for signing git objects (commits, tags) with a Nostr key rather than a traditional PGP key. + +**Usage:** Replaces or supplements `git commit -S` / `git tag -s`. The signature is generated using the Nostr keypair (secp256k1) instead of a PGP key. + +**Related:** +- [GitIntegration](../concepts/git-integration) +- [git-credential-nostr](git-credential-nostr) diff --git a/wiki/components/mobile-client.md b/wiki/components/mobile-client.md new file mode 100644 index 0000000000..05ea694692 --- /dev/null +++ b/wiki/components/mobile-client.md @@ -0,0 +1,21 @@ +# Mobile Client + +Mobile application for iOS and Android built with **Flutter** and **Dart**. + +**Tech stack:** +- Flutter + Dart +- Riverpod for state management +- flutter_hooks for local state +- Catppuccin theme (Latte light / Macchiato dark) + +**Features:** +- Stream channel messaging +- Forum thread browsing +- Push notifications (via buzz-push-gateway) +- Media viewing and upload +- Agent interactions + +**Related:** +- [buzz-push-gateway](buzz-push-gateway) +- [DesktopClient](desktop-client) +- [buzz-relay](buzz-relay) diff --git a/wiki/components/sprig.md b/wiki/components/sprig.md new file mode 100644 index 0000000000..1a96365d3c --- /dev/null +++ b/wiki/components/sprig.md @@ -0,0 +1,13 @@ +# sprig + +All-in-one development harness combining ACP, agent, and MCP server into a single process. Useful for local development and testing. + +**Bundles:** +- ACP harness (relay connection) +- Agent subprocess +- MCP tools (shell, file-edit) + +**Related:** +- [buzz-acp](buzz-acp) +- [buzz-agent](buzz-agent) +- [buzz-dev-mcp](buzz-dev-mcp) diff --git a/wiki/components/web-client.md b/wiki/components/web-client.md new file mode 100644 index 0000000000..5dc6e2497e --- /dev/null +++ b/wiki/components/web-client.md @@ -0,0 +1,13 @@ +# Web Client + +Browser-based web application. Primarily a **repo browser** for the NIP-34 git hosting feature, served by the relay over HTTP. + +**Tech stack:** +- React + Vite +- Tailwind CSS +- Served directly by `buzz-relay` + +**Related:** +- [DesktopClient](desktop-client) +- [GitIntegration](../concepts/git-integration) +- [buzz-relay](buzz-relay) diff --git a/wiki/concepts/acp.md b/wiki/concepts/acp.md new file mode 100644 index 0000000000..53a640a913 --- /dev/null +++ b/wiki/concepts/acp.md @@ -0,0 +1,21 @@ +# ACP (Agent Communication Protocol) + +The Agent Communication Protocol bridges Buzz relay events to AI agent subprocesses. It is the standard way for agents to connect to a Buzz community. + +**How it works:** +- `buzz-acp` spawns an agent subprocess (e.g., Goost, Codex, Claude Code) +- Agent and harness communicate over stdio JSON-RPC +- The harness translates Nostr events (messages, reactions, etc.) into calls the agent understands +- Agent actions (sending messages, reacting, etc.) are translated back into Nostr events and published to the relay + +**Architecture:** +``` +Relay ← WebSocket → ACP Harness ← stdio JSON-RPC → Agent Subprocess +``` + +The harness maintains the WebSocket connection to the relay, handles reconnection, manages subscriptions, and translates between the two protocols. + +**Related:** +- [Agent](../entities/agent) +- [buzz-acp](../components/buzz-acp) +- [buzz-agent](../components/buzz-agent) diff --git a/wiki/concepts/architecture.md b/wiki/concepts/architecture.md new file mode 100644 index 0000000000..ad9e8c4484 --- /dev/null +++ b/wiki/concepts/architecture.md @@ -0,0 +1,43 @@ +# Architecture + +Buzz is a self-hostable team workspace built on a single Nostr relay as the source of truth. + +## Layers + +``` +Clients (Desktop, Mobile, CLI, Agent) ← WebSocket / HTTP + │ + buzz-relay (Axum) + │ + ┌────┼────┐ + │ │ │ +Postgres Redis MinIO +``` + +**The relay** is the central coordinator. All subsystems (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) are orchestrated by `buzz-relay` and never talk to each other directly. Cross-subsystem coordination happens only through the relay. + +**Clients** connect via WebSocket (real-time) or HTTP (REST). Every action is a signed Nostr event. + +**Data stores** — Postgres (events, channels, search, audit, workflows), Redis (pub/sub, presence, typing indicators), MinIO/S3 (media attachments). + +## Design principles + +- **Single source of truth** — the relay event log. No P2P gossip. +- **URL is the community** — one URL = one isolated workspace. +- **Membership is the only gate** — no roles, no permissions, no ACLs beyond channel membership. +- **Events are immutable** — once written, events are never modified. +- **Everything is an event** — messages, reactions, workflow steps, git pushes, huddles. 81 event kinds. + +## Security model + +- NIP-42 for WebSocket auth (challenge-response) +- NIP-98 for HTTP auth (Nostr-signed HTTP requests) +- Channel membership is the only access control +- Hash-chain audit log for tamper-evident record +- SSRF protection via `is_private_ip()` checks + +**Related:** +- [Relay](../entities/relay) +- [EventPipeline](event-pipeline) +- [MultiTenancy](multi-tenancy) +- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/audit-log.md b/wiki/concepts/audit-log.md new file mode 100644 index 0000000000..5eaa696d3e --- /dev/null +++ b/wiki/concepts/audit-log.md @@ -0,0 +1,16 @@ +# Audit Log + +Buzz maintains a tamper-evident audit trail using a SHA-256 hash chain. + +- Each audit entry contains: timestamp, action type, actor pubkey, target, previous hash, and metadata +- The chain is single-writer — serialized via `pg_advisory_lock` to prevent concurrent writes +- 10 audit action types: `EventCreated`, `EventDeleted`, `ChannelCreated`, `ChannelUpdated`, `ChannelDeleted`, `MemberAdded`, `MemberRemoved`, `AuthSuccess`, `AuthFailure`, `RateLimitExceeded` +- The hash chain ensures that modifying any historical entry would invalidate all subsequent hashes +- All audit actions are also Nostr events, making them visible in the relay's event stream + +**Source:** `buzz-audit` crate + +**Related:** +- [buzz-audit](../components/buzz-audit) +- [EventPipeline](event-pipeline) +- [Architecture](architecture) diff --git a/wiki/concepts/authentication.md b/wiki/concepts/authentication.md new file mode 100644 index 0000000000..f364ab32f9 --- /dev/null +++ b/wiki/concepts/authentication.md @@ -0,0 +1,22 @@ +# Authentication + +Buzz uses Nostr's cryptographic identity model. Authentication is based on Schnorr signatures over the secp256k1 curve. + +## NIP-42 (WebSocket) + +The relay issues a random challenge string on connection. The client signs it with their Nostr private key and sends it back. The relay verifies the signature against the advertised pubkey. + +**Flow:** Connect → `["AUTH", ""]` → client signs → `["AUTH", {"event": ...}]` → verified + +## NIP-98 (HTTP) + +HTTP requests include a Nostr-signed authorization header. The relay verifies the signature against the pubkey. Used for REST endpoints (media upload, git operations, admin API). + +## Rate limiting + +The `buzz-auth` crate enforces rate limits per connection and per pubkey, with separate limits for different event kinds. + +**Related:** +- [buzz-auth](../components/buzz-auth) +- [NostrEvent](../entities/nostr-event) +- [ChannelMembership](channel-membership) diff --git a/wiki/concepts/buzz-mesh.md b/wiki/concepts/buzz-mesh.md new file mode 100644 index 0000000000..0b6fe64e0c --- /dev/null +++ b/wiki/concepts/buzz-mesh.md @@ -0,0 +1,14 @@ +# Buzz Mesh + +Buzz Mesh enables relay communities to pool opted-in member hardware into shared AI compute. Agents consume this compute via a local OpenAI-compatible endpoint. + +**Transport:** Uses **iroh** for inter-relay mesh transport — a peer-to-peer networking library with NAT traversal, end-to-end encryption, and relay fallback. + +**Runtime:** Uses **llama.cpp** for native on-device LLM inference, or forwards to external providers. + +**Design goal:** Shared AI compute across a community, reducing reliance on external API providers and keeping inference local. + +**Related:** +- [Agent](../entities/agent) +- [buzz-relay-mesh](../components/buzz-relay-mesh) +- [ACP](acp) diff --git a/wiki/concepts/channel-membership.md b/wiki/concepts/channel-membership.md new file mode 100644 index 0000000000..23bba3b78e --- /dev/null +++ b/wiki/concepts/channel-membership.md @@ -0,0 +1,14 @@ +# Channel Membership + +Channel membership is the only access control mechanism in Buzz. There are no roles, permissions, or ACLs — if you are a member of a channel, you can read and write to it. + +This is a deliberate design choice that simplifies the security model: the event pipeline has exactly one access control check at step 6, and it's a simple membership lookup. + +- Membership is scoped to a [Community](../entities/community) +- Agents have their own memberships, managed independently of human members +- Membership changes are themselves Nostr events (auditable) + +**Related:** +- [Channel](../entities/channel) +- [EventPipeline](event-pipeline) +- [Authentication](authentication) diff --git a/wiki/concepts/event-pipeline.md b/wiki/concepts/event-pipeline.md new file mode 100644 index 0000000000..1a0706f0b2 --- /dev/null +++ b/wiki/concepts/event-pipeline.md @@ -0,0 +1,21 @@ +# Event Pipeline + +Every Nostr event in Buzz goes through a 12-step pipeline when received by the relay: + +1. **Auth check** — verify the client is authenticated (NIP-42) +2. **Pubkey match** — ensure the event pubkey matches the authenticated client +3. **Reject reserved kinds** — prevent spoofing of internal event types (KIND_AUTH) +4. **Ephemeral route** — ephemeral events are broadcast but not persisted +5. **Schnorr verify** — cryptographic signature verification +6. **Membership check** — verify sender is a member of the target channel +7. **DB insert** — idempotent write to Postgres (event ID is the dedup key) +8. **Redis publish** — publish to Redis pub/sub for cross-process notification +9. **Fan-out** — send event to all subscribed WebSocket connections +10. **Search index** — update Postgres FTS search index +11. **Audit log** — append to the hash-chain audit trail +12. **Workflow trigger** — evaluate workflow conditions and execute matching actions + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [Relay](../entities/relay) +- [buzz-relay](../components/buzz-relay) diff --git a/wiki/concepts/git-integration.md b/wiki/concepts/git-integration.md new file mode 100644 index 0000000000..0bf7e1b5bd --- /dev/null +++ b/wiki/concepts/git-integration.md @@ -0,0 +1,21 @@ +# Git Integration + +Buzz implements NIP-34 for git hosting, plus additional tools for Nostr-signed git operations. + +## NIP-34 Git Hosting + +The relay hosts bare git repos over smart HTTP. Repos are accessed via the relay's HTTP endpoints, authenticated with NIP-98. + +## Branch-as-Room + +Creating a feature branch automatically creates a channel where patches, CI results, reviews, and merge decisions live. This ties git workflow directly into the chat workspace. + +## Tools + +- **git-sign-nostr** — sign git commits, tags, and other objects with a Nostr key +- **git-credential-nostr** — git credential helper that authenticates push/fetch using Nostr keys + +**Related:** +- [git-sign-nostr](../components/git-sign-nostr) +- [git-credential-nostr](../components/git-credential-nostr) +- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/media-storage.md b/wiki/concepts/media-storage.md new file mode 100644 index 0000000000..da1a5f82a4 --- /dev/null +++ b/wiki/concepts/media-storage.md @@ -0,0 +1,15 @@ +# Media Storage + +Buzz uses the Blossom protocol for media uploads and storage, backed by S3-compatible object storage (MinIO in development, any S3 provider in production). + +- Users paste, drag, or attach files in channels +- Files are uploaded to S3 via the relay's HTTP endpoints (NIP-98 auth) +- The relay generates server-side thumbnails for images +- Files are served with content-type headers and caching +- Media events are Nostr events with references to the stored blob + +**Configuration:** S3 endpoint, bucket, region, access key, and secret key via environment variables. + +**Related:** +- [buzz-media](../components/buzz-media) +- [Relay](../entities/relay) diff --git a/wiki/concepts/multi-tenancy.md b/wiki/concepts/multi-tenancy.md new file mode 100644 index 0000000000..921ddb16a6 --- /dev/null +++ b/wiki/concepts/multi-tenancy.md @@ -0,0 +1,19 @@ +# Multi-Tenancy + +Buzz supports multi-tenant deployments where multiple communities share the same Postgres/Redis/MinIO infrastructure while maintaining strict isolation. + +## Isolation Model + +- **Community** is the tenant boundary — one workspace, one URL, one isolated world +- All data is scoped by `community_id` at the database level +- The relay extracts the community from the Host header on connection +- `TenantContext` is established before any handler runs + +## Formal Verification + +The multi-tenant relay behavior has been mechanized in **TLA+** for correctness verification. Authorization properties are verified in **Tamarin** (a security protocol verifier). These formal specs live in `docs/formal/`. + +**Related:** +- [Community](../entities/community) +- [Architecture](architecture) +- [buzz-conformance](../components/buzz-conformance) diff --git a/wiki/concepts/nostr-protocol.md b/wiki/concepts/nostr-protocol.md new file mode 100644 index 0000000000..f3423986da --- /dev/null +++ b/wiki/concepts/nostr-protocol.md @@ -0,0 +1,25 @@ +# Nostr Protocol + +Buzz is built on the Nostr protocol — an open, decentralized protocol for signed events. + +## Standard Compliance + +- Wire-compatible with NIP-01 (event format, relay-client protocol) +- NIP-42 (authentication via challenge-response) +- NIP-50 (search) +- NIP-98 (HTTP auth) +- NIP-34 (git integration) + +## Custom Extensions + +Buzz extends Nostr with 81 event kinds in the 40000-49999 custom range, covering: stream messages, forum posts, DMs, canvases, reactions, workflows, git operations, media, huddles, typing indicators, and admin actions. + +## Key Differences from P2P Nostr + +Unlike typical Nostr relays, Buzz is **not P2P**. There is no gossip or replication between relays. The relay is the single source of truth. This is intentional — Buzz is a workspace, not a decentralized social network. The Nostr protocol is used for its cryptographic identity and event model, not for federation. + +**Related:** +- [NostrEvent](../entities/nostr-event) +- [Authentication](authentication) +- [GitIntegration](git-integration) +- [EventPipeline](event-pipeline) diff --git a/wiki/concepts/search.md b/wiki/concepts/search.md new file mode 100644 index 0000000000..cddc956430 --- /dev/null +++ b/wiki/concepts/search.md @@ -0,0 +1,16 @@ +# Search + +Buzz uses Postgres full-text search (FTS) for searching events. There is no external search service — all search is handled within Postgres. + +- Events are indexed into a `search_tsv` column (a Postgres `tsvector`) via a GIN index +- Search supports NIP-50, the Nostr standard search protocol +- Queries come in via the relay's `REQ` handler with a search filter +- Privacy-sensitive event kinds are excluded at the storage level (not indexed) +- Search is scoped by community (tenant isolation) + +**Implementation:** `buzz-search` crate handles indexing and query building over the `search_tsv` GIN index. + +**Related:** +- [buzz-search](../components/buzz-search) +- [NostrProtocol](nostr-protocol) +- [MultiTenancy](multi-tenancy) diff --git a/wiki/concepts/workflow-engine.md b/wiki/concepts/workflow-engine.md new file mode 100644 index 0000000000..2d78319b31 --- /dev/null +++ b/wiki/concepts/workflow-engine.md @@ -0,0 +1,35 @@ +# Workflow Engine + +Buzz has a YAML-as-code workflow engine for channel automation. Workflows are defined in YAML files, scoped to a channel, and executed by `buzz-workflow`. + +## Triggers + +| Trigger | Description | +|---|---| +| `message_posted` | Fires when a message is posted matching a text pattern | +| `reaction_added` | Fires when a reaction is added matching an emoji | +| `schedule` | Cron-based scheduled trigger (ticks every 60s) | +| `webhook` | External HTTP webhook trigger | + +## Actions + +| Action | Description | +|---|---| +| `send_message` | Post a message to the channel | +| `send_dm` | Send a direct message to a user | +| `set_channel_topic` | Update the channel topic | +| `add_reaction` | Add an emoji reaction | +| `call_webhook` | Call an external webhook URL | +| `request_approval` | Request human approval before proceeding | +| `delay` | Wait before executing next action | + +## Conditions + +Conditions are expressions evaluated with `evalexpr`, with custom functions: `str_contains`, `str_starts_with`, `str_ends_with`, `matches_regex`, and more. + +**Approval gates** are partially built (schema, API, and UI exist but executor persistence is pending). + +**Related:** +- [buzz-workflow](../components/buzz-workflow) +- [Channel](../entities/channel) +- [EventPipeline](event-pipeline) diff --git a/wiki/entities/agent.md b/wiki/entities/agent.md new file mode 100644 index 0000000000..68e1c1ceef --- /dev/null +++ b/wiki/entities/agent.md @@ -0,0 +1,22 @@ +# Agent + +AI agents are first-class team members in Buzz. They have their own Nostr keypairs, channel memberships, and audit trail — exactly like human teammates, just different cryptographic identities. + +**How agents connect:** +- Agents connect via the **ACP (Agent Communication Protocol)** harness (`buzz-acp`) +- ACP bridges Nostr relay events to AI agent subprocesses over stdio JSON-RPC +- Agents use tools like Goost, Codex, Claude Code as their AI backend +- Agent teams bundle a persona (model + system prompt), e.g. Ralph for code review, Scout for research + +**Agent capabilities:** +- Send and receive messages in channels +- Participate in voice huddles via STT/TTS +- Broadcast typing indicators +- Trigger and respond to workflows +- Use `buzz-cli` for JSON-in/JSON-out interaction + +**Related:** +- [ACP](../concepts/acp) — the protocol that connects agents +- [buzz-acp](../components/buzz-acp) — ACP harness crate +- [buzz-agent](../components/buzz-agent) — minimal agent binary +- [buzz-persona](../components/buzz-persona) — persona packs diff --git a/wiki/entities/channel.md b/wiki/entities/channel.md new file mode 100644 index 0000000000..cca0c2865d --- /dev/null +++ b/wiki/entities/channel.md @@ -0,0 +1,19 @@ +# Channel + +Channels are communication spaces within a [Community](community). Buzz supports three channel types: + +## Stream +Slack-like real-time chat. Mandatory topics on creation. Supports sub-replies (thread-like) and has zero-notification default to reduce noise. + +## Forum +Discourse-like async long-form posts. Flat replies. Designed for asynchronous discussion rather than real-time chat. + +## Direct Messages +1:1 and group DMs (up to 9 participants). Private communication outside of stream/forum channels. + +**Channel membership is the only access control gate** in Buzz. If you're a member of a channel, you can read and write to it. There are no roles, permissions, or ACLs beyond membership. + +**Related:** +- [ChannelMembership](../concepts/channel-membership) — access control model +- [Community](community) — parent tenant +- [NostrEvent](nostr-event) — every channel action is an event diff --git a/wiki/entities/community.md b/wiki/entities/community.md new file mode 100644 index 0000000000..ade52f5fac --- /dev/null +++ b/wiki/entities/community.md @@ -0,0 +1,14 @@ +# Community + +A community is a workspace — the tenant boundary in Buzz. One URL, one isolated world. Multi-tenant deployments share Postgres/Redis/MinIO infrastructure but scope all data by `community_id`. + +- The URL is authoritative: the host header determines which community a request belongs to +- A community has its own channels, members (human and agent), workflows, audit log, and git repos +- Communities cannot see each other's data + +**Connection flow:** A client connects via WebSocket → the relay extracts the community from the Host header → establishes `TenantContext` → enforces connection limits per community → authenticates the client. + +**Related:** +- [Relay](relay) — serving a community +- [MultiTenancy](../concepts/multi-tenancy) — isolation model +- [Channel](channel) — communication spaces within a community diff --git a/wiki/entities/nostr-event.md b/wiki/entities/nostr-event.md new file mode 100644 index 0000000000..0f0f6bd915 --- /dev/null +++ b/wiki/entities/nostr-event.md @@ -0,0 +1,15 @@ +# Nostr Event + +The atomic unit of all activity in Buzz. Every action — a chat message, a reaction, a workflow step, a canvas update, a git push, a huddle voice event — is a cryptographically signed Nostr event. + +Events follow the NIP-01 standard and are extended with custom kinds in the 40000-49999 range. Buzz defines **81 event kinds** across stream channels, forums, DMs, canvases, reactions, workflows, git, media, huddles, and admin operations. + +**Event pipeline (12 steps):** +1. Auth check → 2. Pubkey match → 3. Reject reserved kinds → 4. Ephemeral route → 5. Schnorr verify → 6. Membership check → 7. DB insert (idempotent) → 8. Redis publish → 9. Fan-out to subscribers → 10. Search index → 11. Audit log → 12. Workflow trigger + +**Source:** `crates/buzz-core/src/kind.rs` for the full kind list. + +**Related:** +- [EventPipeline](../concepts/event-pipeline) — the 12-step lifecycle +- [Relay](relay) — processes all events +- [Authentication](../concepts/authentication) — NIP-42/NIP-98 signing diff --git a/wiki/entities/relay.md b/wiki/entities/relay.md new file mode 100644 index 0000000000..c6d4d124ba --- /dev/null +++ b/wiki/entities/relay.md @@ -0,0 +1,16 @@ +# Relay + +The Nostr relay server is the single source of truth for a Buzz community. All reads and writes — chat messages, reactions, workflow triggers, canvas updates, git pushes, huddle events — flow through it as signed Nostr events. + +Built with **Axum** on **Tokio**, the relay handles WebSocket connections, HTTP requests, and coordinates all subsystems. It imports all service crates (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) and orchestrates cross-subsystem coordination. + +**Key traits:** +- Single source of truth — no P2P gossip or replication +- Every action is a signed Nostr event +- All subsystems are coordinated through the relay, never directly between crates +- URL is authoritative — the relay's URL defines the community + +**Related:** +- [Community](community) — tenant boundary +- [EventPipeline](../concepts/event-pipeline) — event lifecycle +- [buzz-relay](../components/buzz-relay) — implementation crate diff --git a/wiki/index.md b/wiki/index.md new file mode 100644 index 0000000000..f2ec1332e6 --- /dev/null +++ b/wiki/index.md @@ -0,0 +1,66 @@ +# Index + +Catalog of all wiki pages, organized by category. + +## Entities + +- [Relay](entities/relay) — the Nostr relay server; the single source of truth for a community +- [Community](entities/community) — a workspace; one URL, one isolated tenant +- [Agent](entities/agent) — an AI agent as a first-class team member with its own Nostr keypair +- [Channel](entities/channel) — stream, forum, and DM communication spaces +- [NostrEvent](entities/nostr-event) — the atomic unit of all activity; a cryptographically signed event + +## Concepts + +- [Architecture](concepts/architecture) — system overview, layers, and design principles +- [EventPipeline](concepts/event-pipeline) — the 12-step lifecycle of an event from receipt to fan-out +- [Authentication](concepts/authentication) — NIP-42 challenge-response and NIP-98 HTTP auth +- [ChannelMembership](concepts/channel-membership) — access control model (membership is the only gate) +- [WorkflowEngine](concepts/workflow-engine) — YAML-as-code channel automation with triggers and actions +- [AuditLog](concepts/audit-log) — SHA-256 hash-chain tamper-evident audit trail +- [BuzzMesh](concepts/buzz-mesh) — inter-relay mesh for pooled AI compute +- [ACP](concepts/acp) — Agent Communication Protocol bridging Nostr events to agent subprocesses +- [GitIntegration](concepts/git-integration) — NIP-34 git hosting, signing, and branch-as-room +- [MediaStorage](concepts/media-storage) — Blossom protocol media uploads on S3/MinIO +- [Search](concepts/search) — Postgres FTS full-text search over events +- [MultiTenancy](concepts/multi-tenancy) — community isolation model and formal verification +- [NostrProtocol](concepts/nostr-protocol) — Nostr wire protocol and Buzz's custom event kinds + +## Components + +- [buzz-relay](components/buzz-relay) — main WebSocket relay server (Axum) +- [buzz-core](components/buzz-core) — core types, event verification, filter matching (zero I/O) +- [buzz-db](components/buzz-db) — Postgres event store and data access layer +- [buzz-auth](components/buzz-auth) — auth, rate limiting, and scope enforcement +- [buzz-pubsub](components/buzz-pubsub) — Redis pub/sub, presence, typing indicators +- [buzz-search](components/buzz-search) — Postgres FTS search index +- [buzz-audit](components/buzz-audit) — hash-chain audit log +- [buzz-media](components/buzz-media) — Blossom/S3 media storage +- [buzz-workflow](components/buzz-workflow) — YAML workflow engine +- [buzz-acp](components/buzz-acp) — ACP harness for agent subprocess orchestration +- [buzz-agent](components/buzz-agent) — minimal ACP-compliant agent binary +- [buzz-dev-mcp](components/buzz-dev-mcp) — MCP server providing shell and file-edit tools +- [buzz-persona](components/buzz-persona) — agent persona packs (model + system prompt) +- [buzz-cli](components/buzz-cli) — agent-first CLI (JSON in/out) +- [buzz-sdk](components/buzz-sdk) — typed Nostr event builders +- [buzz-admin](components/buzz-admin) — operator CLI for relay administration +- [buzz-ws-client](components/buzz-ws-client) — shared WebSocket client (NIP-42) +- [buzz-test-client](components/buzz-test-client) — integration test harness +- [buzz-conformance](components/buzz-conformance) — multi-tenant conformance tests +- [buzz-push-gateway](components/buzz-push-gateway) — push notification gateway +- [buzz-relay-mesh](components/buzz-relay-mesh) — iroh-based inter-relay mesh transport +- [git-sign-nostr](components/git-sign-nostr) — sign git objects with a Nostr key +- [git-credential-nostr](components/git-credential-nostr) — git credential helper for Nostr auth +- [sprig](components/sprig) — all-in-one harness (ACP + agent + MCP) +- [DesktopClient](components/desktop-client) — Tauri 2 + React 19 native desktop app +- [MobileClient](components/mobile-client) — Flutter mobile app (iOS + Android) +- [WebClient](components/web-client) — browser-based web client (repo browser) +- [AdminWeb](components/admin-web) — admin dashboard + +## Operations + +- [DevelopmentSetup](operations/development-setup) — local dev environment setup with Docker Compose +- [Deployment](operations/deployment) — production deployment with Helm and Docker Compose +- [Configuration](operations/configuration) — environment variables and community config +- [CLIReference](operations/cli-reference) — just commands and common dev workflows +- [Troubleshooting](operations/troubleshooting) — common issues and fixes diff --git a/wiki/log.md b/wiki/log.md new file mode 100644 index 0000000000..2223b00be6 --- /dev/null +++ b/wiki/log.md @@ -0,0 +1,47 @@ +# Log + +Chronological record of wiki changes. Each entry uses the format: +`## [YYYY-MM-DD] type | Title` + +- **ingest** — a new source was read and integrated +- **query** — a question was answered and the result was filed +- **lint** — a health check was performed +- **update** — pages were revised or created outside of ingest/query + +--- + +## [2026-07-27] ingest | Initial Wiki Creation + +Created the initial wiki for the Buzz project based on project source code and documentation. + +**Pages created:** +- `CLAUDE.md` — schema, conventions, and workflows +- `index.md` — catalog of all pages +- `log.md` — this file +- `entities/relay.md`, `entities/community.md`, `entities/agent.md`, `entities/channel.md`, `entities/nostr-event.md` +- `concepts/architecture.md`, `concepts/event-pipeline.md`, `concepts/authentication.md`, `concepts/channel-membership.md`, `concepts/workflow-engine.md`, `concepts/audit-log.md`, `concepts/buzz-mesh.md`, `concepts/acp.md`, `concepts/git-integration.md`, `concepts/media-storage.md`, `concepts/search.md`, `concepts/multi-tenancy.md`, `concepts/nostr-protocol.md` +- `components/buzz-relay.md`, `components/buzz-core.md`, `components/buzz-db.md`, `components/buzz-auth.md`, `components/buzz-pubsub.md`, `components/buzz-search.md`, `components/buzz-audit.md`, `components/buzz-media.md`, `components/buzz-workflow.md`, `components/buzz-acp.md`, `components/buzz-agent.md`, `components/buzz-dev-mcp.md`, `components/buzz-persona.md`, `components/buzz-cli.md`, `components/buzz-sdk.md`, `components/buzz-admin.md`, `components/buzz-ws-client.md`, `components/buzz-test-client.md`, `components/buzz-conformance.md`, `components/buzz-push-gateway.md`, `components/buzz-relay-mesh.md`, `components/git-sign-nostr.md`, `components/git-credential-nostr.md`, `components/sprig.md`, `components/desktop-client.md`, `components/mobile-client.md`, `components/web-client.md`, `components/admin-web.md` +- `operations/development-setup.md`, `operations/deployment.md`, `operations/configuration.md`, `operations/cli-reference.md` + +## [2026-07-27] update | Added Troubleshooting Page + +Created `operations/troubleshooting.md` covering common issues: 521 errors when connecting to cloud relays, port conflicts, rate limiting, Docker health, and event rejection. Updated `index.md` to link the new page. + +## [2026-07-27] query | Agent Shows Response Bubble But Doesn't Publish + +Investigated agent response not publishing. Two root causes found: +1. Agent was connected to `wss://milimo.communities.buzz.xyz` instead of `ws://localhost:3000` — hardcoded in `managed-agents.json`. Responses went to the wrong relay. +2. Even on the correct relay, the LLM (Qwen3.6-35B-A3B-bf16 via OMLX) returns text via ACP `agent_message_chunk` but doesn't call the `shell` tool to run `buzz messages send`. The harness does not auto-publish agent output. + +Updated `operations/troubleshooting.md` with both causes and fixes. + +## [2026-07-28] update | Root Causes Resolved — Wiki Updated + +Applied fixes from investigation: +- **Local LLM reasoning content**: `buzz-agent` now handles `reasoning_content` field from OpenAI-compatible endpoints (local models), falling back to `content` when `reasoning_content` is absent. +- **Fallback turn text publishing**: `buzz-acp` now accumulates `agent_message_chunk` text during a turn and publishes a `kind: 9` channel message on `StopReason::EndTurn` if no `send_message` tool call was made. Enables non-tool-calling models to participate. +- **Response sanitization**: `clean_agent_text_response` strips pseudo-tool JSON blocks (`` ```json ... ``` ``) and model tokens (`<|tool_call|>`, `<|im_end|>`) from generated text. +- **Owner pubkey seeding**: `agent_owner_pubkey` seeded in Postgres `users` table across all local dev community hosts (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`). +- **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. + +Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. diff --git a/wiki/operations/cli-reference.md b/wiki/operations/cli-reference.md new file mode 100644 index 0000000000..a17a2c96d6 --- /dev/null +++ b/wiki/operations/cli-reference.md @@ -0,0 +1,55 @@ +# CLI Reference + +## just (task runner) + +The `Justfile` at the project root provides common development commands. + +### Development + +| Command | Description | +|---|---| +| `just dev` | Start full dev stack (Docker Compose) | +| `just dev-reset` | Destroy and recreate dev stack | +| `just seed-local-community` | Seed sample data | +| `just desktop` | Launch desktop client dev server | +| `just mobile` | Launch Flutter dev server | + +### Testing + +| Command | Description | +|---|---| +| `just test-all` | Run all tests | +| `just test-rust` | Run Rust tests | +| `just test-desktop` | Run desktop E2E tests (Playwright) | +| `just test-mobile` | Run Flutter tests | + +### Building + +| Command | Description | +|---|---| +| `just build-relay` | Build relay binary | +| `just build-desktop` | Build desktop app | +| `just build-mobile` | Build mobile app | +| `just docker` | Build Docker images | + +## cargo + +Standard Cargo commands work. Key workspace crates: + +```bash +cargo build -p buzz-relay +cargo test -p buzz-conformance +cargo clippy -p buzz-core +``` + +## Hermit + +Hermit manages toolchain versions. Activate automatically by `cd`-ing into `buzz/`, or manually: + +```bash +. bin/activate-hermit +``` + +**Related:** +- [DevelopmentSetup](development-setup) +- [Deployment](deployment) diff --git a/wiki/operations/configuration.md b/wiki/operations/configuration.md new file mode 100644 index 0000000000..5d34b98a68 --- /dev/null +++ b/wiki/operations/configuration.md @@ -0,0 +1,35 @@ +# Configuration + +Buzz is configured primarily through environment variables. + +## Core + +| Variable | Description | +|---|---| +| `DATABASE_URL` | Postgres connection string | +| `REDIS_URL` | Redis connection string | +| `RELAY_URL` | Public URL of the relay | +| `RELAY_PORT` | Listen port (default: 8080) | + +## Media (S3/MinIO) + +| Variable | Description | +|---|---| +| `S3_ENDPOINT` | S3-compatible endpoint URL | +| `S3_BUCKET` | Bucket name for media storage | +| `S3_REGION` | AWS region (default: us-east-1) | +| `S3_ACCESS_KEY` | Access key | +| `S3_SECRET_KEY` | Secret key | + +## Auth + +| Variable | Description | +|---|---| +| `RATE_LIMIT_MESSAGES` | Messages per minute per connection | +| `RATE_LIMIT_CONNECTIONS` | Max connections per IP | + +See `.env.example` for the full list. + +**Related:** +- [DevelopmentSetup](development-setup) +- [Deployment](deployment) diff --git a/wiki/operations/deployment.md b/wiki/operations/deployment.md new file mode 100644 index 0000000000..09f974a018 --- /dev/null +++ b/wiki/operations/deployment.md @@ -0,0 +1,30 @@ +# Deployment + +## Docker Compose (Production) + +A production-ready Docker Compose bundle is available in `deploy/compose/`. It includes: +- `buzz-relay` (with all service crates compiled in) +- PostgreSQL 17 +- Redis 7 +- MinIO (S3-compatible storage) +- Prometheus (metrics) + +## Helm (Kubernetes) + +Helm charts are in `deploy/charts/`. Suitable for production multi-tenant deployments. + +## Requirements + +- PostgreSQL 17 +- Redis 7 +- S3-compatible object storage (MinIO, AWS S3, etc.) +- TLS termination (reverse proxy with Let's Encrypt) + +## Configuration + +All configuration is via environment variables. See [Configuration](configuration) for the full list. + +**Related:** +- [DevelopmentSetup](development-setup) +- [Configuration](configuration) +- [MultiTenancy](../concepts/multi-tenancy) diff --git a/wiki/operations/development-setup.md b/wiki/operations/development-setup.md new file mode 100644 index 0000000000..f06428373f --- /dev/null +++ b/wiki/operations/development-setup.md @@ -0,0 +1,48 @@ +# Development Setup + +## Prerequisites + +- **Hermit** (pinned toolchain manager) — activates automatically in the `buzz/` directory +- **Docker Desktop** — for Postgres, Redis, and MinIO containers +- Rust, Node, pnpm, Flutter — all managed by Hermit + +## Quick start + +```bash +# From the buzz/ directory +just dev +``` + +This starts the full stack via Docker Compose: Postgres 17, Redis 7, MinIO, and the relay. + +## Key commands + +| Command | Description | +|---|---| +| `just dev` | Start full dev environment | +| `just dev-reset` | Reset dev environment (destroy data) | +| `cargo build -p buzz-relay` | Build the relay | +| `cargo test -p buzz-conformance` | Run conformance tests | +| `just desktop` | Start the desktop client | +| `just mobile` | Start the mobile client | + +## Environment + +Copy `.env.example` to `.env` and configure. Key variables: +- `DATABASE_URL` — Postgres connection string +- `REDIS_URL` — Redis connection string +- `S3_ENDPOINT` — MinIO/S3 endpoint +- `RELAY_URL` — the relay's external URL + +## Seeding + +```bash +just seed-local-community +``` + +Creates a local community with sample channels and test data. + +**Related:** +- [Deployment](deployment) +- [Configuration](configuration) +- [CLIReference](cli-reference) diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md new file mode 100644 index 0000000000..23b2dd8606 --- /dev/null +++ b/wiki/operations/troubleshooting.md @@ -0,0 +1,220 @@ +# Troubleshooting + +Common issues when running Buzz locally. + +## "Can't reach the relay" / "relay returned 521 Unknown Status Code" + +521 is a [Cloudflare-specific status code](https://en.wikipedia.org/wiki/HTTP_521) meaning Cloudflare's edge can't reach the origin server. This happens when the desktop app is trying to connect to a Cloudflare-proxied URL (e.g. `wss://buzz.block.builderlab.xyz` or a staging/production relay) that is down or unreachable. + +**Fix:** Connect to your local relay instead — use `ws://localhost:3000` as the relay URL. + +If the app cached a previous cloud URL, clear the stored state: + +```bash +just desktop-standalone fresh=1 +``` + +Then start fresh: + +```bash +just dev +``` + +The error is generated in `desktop/src-tauri/src/relay.rs:295` (HTTP fallback) and classified in `desktop/src/shared/lib/relayError.ts` (checks for `relay unreachable:` prefix — 521 doesn't match it, so it's treated as an application error rather than a network error). + +## "relay unreachable: could not connect to relay" + +The relay process isn't running or isn't reachable on the expected port. + +**Checks:** + +```bash +# Is the relay binary running? +ps aux | grep buzz-relay + +# Is it listening on the right port? +lsof -i :3000 + +# Are Docker services up? +docker compose ps + +# Check health endpoints +curl http://localhost:8080/_liveness +curl http://localhost:8080/_readiness +``` + +**Fix:** Start the relay: + +```bash +just relay +``` + +## Port already in use + +``` +Error: relay port 3000 is already in use; refusing to launch desktop against a stale relay. +``` + +A previous relay instance is still running. Kill it: + +```bash +pkill buzz-relay +just dev +``` + +## "relay rate-limited: retry in Ns" + +The relay's Redis-backed rate limiter has been hit. Wait the indicated time and retry. Rate limits are configured via `BUZZ_RATE_LIMIT_*` env vars in `.env`. + +## Docker services not healthy + +If `docker compose ps` shows `unhealthy`: + +```bash +# Check individual service logs +docker compose logs postgres +docker compose logs redis + +# Full reset +just reset +``` + +## Relay starts but immediately exits + +Check the relay logs for database connection errors. Ensure Postgres is healthy and `DATABASE_URL` in `.env` is correct (default: `postgres://buzz:buzz_dev@localhost:5432/buzz`). + +## "No auth challenge received" + +The WebSocket connection succeeded but the relay didn't send a NIP-42 AUTH challenge. This usually means the relay is not configured to require auth (`auth_required: true` in the NIP-11 response). Check `RELAY_URL` in `.env` points to the correct relay. + +## "Event rejected by relay" + +The relay rejected a published event. Possible causes: + +- Event signature verification failed +- Sender is not a member of the target channel +- Event kind is not allowed +- Rate limit exceeded + +Check the relay logs for details (`RUST_LOG=debug` is set in `.env`). + +## Agent shows response text in a "bubble" but never publishes to the channel + +The agent generates text (GPU spikes, LLM runs, text appears in a UI bubble) but the message never shows up in the channel timeline. + +### Cause 1: Agent connected to the wrong relay + +The agent's `managed-agents.json` may have a hardcoded `relay_url` pointing to a different relay than the one you're using. Check: + +```bash +cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json +``` + +If you see `relay_url` set to a remote URL (e.g. `wss://milimo.communities.buzz.xyz`) instead of `ws://localhost:3000`, the agent publishes responses to the wrong relay. + +**Fix:** Edit the file to replace the remote URL with your local relay: + +```bash +sed -i '' 's|wss://milimo.communities.buzz.xyz|ws://localhost:3000|g' \ + ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json +``` + +Then kill the agent processes — the desktop app will respawn them with the correct URL: + +```bash +pkill -f buzz-acp +pkill -f buzz-agent +pkill -f buzz-dev-mcp +``` + +### Cause 2: LLM returns text but doesn't call the publish tool + +Buzz has two separate rendering paths for agent content: + +| Aspect | Session Transcript (ACP Panel) | Channel Timeline | +|---|---|---| +| Event source | Kind 24200 observer frames (ACP protocol) | Kind 9 / 40002 Nostr events | +| Agent text | `agent_message_chunk` → transcript item | Only if agent publishes explicitly | +| Where shown | Side panel (click "View activity") | Main channel content area | + +The agent generates text and sends it via ACP's `agent_message_chunk` update — this renders in the session transcript panel as a "bubble." But the harness (`buzz-acp`) does **not** auto-publish agent output to the relay. At `crates/buzz-acp/src/lib.rs:3232`, `PromptOutcome::Ok(_)` just returns the agent to the pool without sending anything. + +The agent must **explicitly publish** its response by calling one of: +1. `buzz messages send` via the MCP `shell` tool (`buzz-dev-mcp` provides this) +2. The `send_message` ACP tool (dedicated agent tool) +3. The desktop Tauri IPC `send_managed_agent_channel_message` handler + +To verify if the agent is calling the tool, check the `buzz-dev-mcp` logs: + +```bash +cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/logs/*.log | grep -i 'shell\|tool_call\|buzz messages' +``` + +### Cause 3: Local LLM returns reasoning in `reasoning_content` or lacks native tool-calling + +When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4-bit/8-bit models like `gemma-4-12b`): + +1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. +2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. +3. **Cleaning Pseudo-tool Code Blocks & CLI Payloads**: `clean_agent_text_response` strips pseudo-tool JSON blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), step-by-step pseudo-execution noise, and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. + +## Duplicate Agent Cards Appearing in UI (Builtin Personas vs Standalone Managed Agents) + +The desktop UI renders agent cards in `UnifiedAgentsSection.tsx` by running `buildUnifiedGroups(personas, agents)`. + +- Top cards (with alien face avatars) are **Builtin Personas** (`builtin:fizz`, `builtin:honey`, `builtin:bumble`). +- Bottom cards (with grey circle avatars) are **Managed Agent Instances** loaded from `managed-agents.json`. + +If an agent record in `managed-agents.json` has `"persona_id": null` (or omitted), `buildUnifiedGroups` cannot associate the managed agent instance with its builtin persona. It places the agent under `ungrouped`, displaying duplicate standalone cards. + +**Fix:** Ensure each agent record in `managed-agents.json` explicitly references its corresponding persona ID: + +```json +[ + { + "name": "Fizz", + "persona_id": "builtin:fizz", + ... + }, + { + "name": "Honey", + "persona_id": "builtin:honey", + ... + }, + { + "name": "Bumble", + "persona_id": "builtin:bumble", + ... + } +] +``` + +## "Agent; owner unavailable" badge next to agent name + +The desktop UI displays **"owner unavailable"** when the agent user profile in the Postgres database lacks an `agent_owner_pubkey` mapping to the human owner. + +**Fix:** Ensure the active agent pubkeys are inserted into the `users` table with `agent_owner_pubkey` set to the owner's pubkey across all active community host entries (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`): + +```sql +INSERT INTO users (community_id, pubkey, agent_owner_pubkey, created_at, updated_at, channel_add_policy) +SELECT c.id, decode('', 'hex'), decode('', 'hex'), NOW(), NOW(), 'anyone'::channel_add_policy +FROM communities c +ON CONFLICT (community_id, pubkey) DO UPDATE SET agent_owner_pubkey = EXCLUDED.agent_owner_pubkey; +``` + +## "failed to parse agent store: missing field 'acp_command'" error banner + +The desktop app displays a red warning banner `failed to parse agent store (preserved as .invalid): missing field 'acp_command'` when `managed-agents.json` is missing required non-defaulted fields for `ManagedAgentRecord`. + +**Fix:** Ensure `managed-agents.json` contains all required schema fields (`pubkey`, `name`, `relay_url`, `acp_command` [e.g. `"buzz-acp"`], `agent_command` [e.g. `"buzz-agent"`], `mcp_command` [e.g. `"buzz-dev-mcp"`], `turn_timeout_seconds` [e.g. `900`], `agent_args` [`[]`]) and remove any `.invalid` backup file: + +```bash +rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid +``` + +**Related:** +- [DevelopmentSetup](development-setup) — how to start the dev environment +- [Configuration](configuration) — env var reference +- [CLIReference](cli-reference) — just commands +- [Relay](../entities/relay) — relay entity docs + From dc6e46eb5d58e01b7eeca249b0d3ec388df5eb76 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 22:08:02 -0500 Subject: [PATCH 12/14] docs(wiki): update log.md Signed-off-by: mainza-ai --- wiki/log.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wiki/log.md b/wiki/log.md index ad45230f7e..760382e13a 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -54,7 +54,7 @@ Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components ## [2026-07-28] update | Multi-tenant Loopback Host Normalization & NIP-29 Channel Discovery -- **Loopback Host Normalization (`buzz-core` & `buzz-auth`)**: `normalize_host` now folds loopback host variants (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1`, ensuring HTTP/WebSocket requests and NIP-98 auth signers resolve to the exact same community space. Resolves NIP-98 `401 Unauthorized` URL mismatch errors between `http://localhost:3000` and `http://127.0.0.1:3000`. -- **NIP-29 Channel Discovery (`buzz-acp`)**: `extract_channel_uuid_from_event` now inspects both `d` tags (NIP-29 group members `kind: 39002`) and `h` tags. Enables agents to dynamically subscribe to channels in real time as soon as they are added. +- **Loopback Host Normalization (`buzz-core` & `buzz-auth`)**: `normalize_host` now folds loopback variants (`localhost`, `127.0.0.1`, `[::1]`) to `127.0.0.1`, ensuring HTTP/WebSocket requests and NIP-98 auth signers resolve to the same community. Fixes host mismatch partitioning between `localhost:3000` and `127.0.0.1:3000`. +- **NIP-29 Channel Discovery (`buzz-acp`)**: `extract_channel_uuid_from_event` now inspects both `d` tags (`kind: 39002`) and `h` tags, enabling agents to subscribe to newly created channels in real time. - Updated `operations/troubleshooting.md`. From 8fcb42e5d0f6d83a00b7911e1ff0d3cf69788bb3 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Tue, 28 Jul 2026 22:08:45 -0500 Subject: [PATCH 13/14] chore: remove wiki directory from PR branch Signed-off-by: mainza-ai --- wiki/CLAUDE.md | 51 ------ wiki/components/admin-web.md | 16 -- wiki/components/buzz-acp.md | 17 -- wiki/components/buzz-admin.md | 14 -- wiki/components/buzz-agent.md | 20 --- wiki/components/buzz-audit.md | 15 -- wiki/components/buzz-auth.md | 15 -- wiki/components/buzz-cli.md | 16 -- wiki/components/buzz-conformance.md | 13 -- wiki/components/buzz-core.md | 15 -- wiki/components/buzz-db.md | 16 -- wiki/components/buzz-dev-mcp.md | 15 -- wiki/components/buzz-media.md | 14 -- wiki/components/buzz-persona.md | 13 -- wiki/components/buzz-pubsub.md | 15 -- wiki/components/buzz-push-gateway.md | 9 - wiki/components/buzz-relay-mesh.md | 14 -- wiki/components/buzz-relay.md | 24 --- wiki/components/buzz-sdk.md | 13 -- wiki/components/buzz-search.md | 14 -- wiki/components/buzz-test-client.md | 9 - wiki/components/buzz-workflow.md | 17 -- wiki/components/buzz-ws-client.md | 13 -- wiki/components/desktop-client.md | 25 --- wiki/components/git-credential-nostr.md | 14 -- wiki/components/git-sign-nostr.md | 9 - wiki/components/mobile-client.md | 21 --- wiki/components/sprig.md | 13 -- wiki/components/web-client.md | 13 -- wiki/concepts/acp.md | 21 --- wiki/concepts/architecture.md | 43 ----- wiki/concepts/audit-log.md | 16 -- wiki/concepts/authentication.md | 22 --- wiki/concepts/buzz-mesh.md | 14 -- wiki/concepts/channel-membership.md | 14 -- wiki/concepts/event-pipeline.md | 21 --- wiki/concepts/git-integration.md | 21 --- wiki/concepts/media-storage.md | 15 -- wiki/concepts/multi-tenancy.md | 19 -- wiki/concepts/nostr-protocol.md | 25 --- wiki/concepts/search.md | 16 -- wiki/concepts/workflow-engine.md | 35 ---- wiki/entities/agent.md | 22 --- wiki/entities/channel.md | 19 -- wiki/entities/community.md | 14 -- wiki/entities/nostr-event.md | 15 -- wiki/entities/relay.md | 16 -- wiki/index.md | 66 ------- wiki/log.md | 47 ----- wiki/operations/cli-reference.md | 55 ------ wiki/operations/configuration.md | 35 ---- wiki/operations/deployment.md | 30 ---- wiki/operations/development-setup.md | 48 ------ wiki/operations/troubleshooting.md | 220 ------------------------ 54 files changed, 1342 deletions(-) delete mode 100644 wiki/CLAUDE.md delete mode 100644 wiki/components/admin-web.md delete mode 100644 wiki/components/buzz-acp.md delete mode 100644 wiki/components/buzz-admin.md delete mode 100644 wiki/components/buzz-agent.md delete mode 100644 wiki/components/buzz-audit.md delete mode 100644 wiki/components/buzz-auth.md delete mode 100644 wiki/components/buzz-cli.md delete mode 100644 wiki/components/buzz-conformance.md delete mode 100644 wiki/components/buzz-core.md delete mode 100644 wiki/components/buzz-db.md delete mode 100644 wiki/components/buzz-dev-mcp.md delete mode 100644 wiki/components/buzz-media.md delete mode 100644 wiki/components/buzz-persona.md delete mode 100644 wiki/components/buzz-pubsub.md delete mode 100644 wiki/components/buzz-push-gateway.md delete mode 100644 wiki/components/buzz-relay-mesh.md delete mode 100644 wiki/components/buzz-relay.md delete mode 100644 wiki/components/buzz-sdk.md delete mode 100644 wiki/components/buzz-search.md delete mode 100644 wiki/components/buzz-test-client.md delete mode 100644 wiki/components/buzz-workflow.md delete mode 100644 wiki/components/buzz-ws-client.md delete mode 100644 wiki/components/desktop-client.md delete mode 100644 wiki/components/git-credential-nostr.md delete mode 100644 wiki/components/git-sign-nostr.md delete mode 100644 wiki/components/mobile-client.md delete mode 100644 wiki/components/sprig.md delete mode 100644 wiki/components/web-client.md delete mode 100644 wiki/concepts/acp.md delete mode 100644 wiki/concepts/architecture.md delete mode 100644 wiki/concepts/audit-log.md delete mode 100644 wiki/concepts/authentication.md delete mode 100644 wiki/concepts/buzz-mesh.md delete mode 100644 wiki/concepts/channel-membership.md delete mode 100644 wiki/concepts/event-pipeline.md delete mode 100644 wiki/concepts/git-integration.md delete mode 100644 wiki/concepts/media-storage.md delete mode 100644 wiki/concepts/multi-tenancy.md delete mode 100644 wiki/concepts/nostr-protocol.md delete mode 100644 wiki/concepts/search.md delete mode 100644 wiki/concepts/workflow-engine.md delete mode 100644 wiki/entities/agent.md delete mode 100644 wiki/entities/channel.md delete mode 100644 wiki/entities/community.md delete mode 100644 wiki/entities/nostr-event.md delete mode 100644 wiki/entities/relay.md delete mode 100644 wiki/index.md delete mode 100644 wiki/log.md delete mode 100644 wiki/operations/cli-reference.md delete mode 100644 wiki/operations/configuration.md delete mode 100644 wiki/operations/deployment.md delete mode 100644 wiki/operations/development-setup.md delete mode 100644 wiki/operations/troubleshooting.md diff --git a/wiki/CLAUDE.md b/wiki/CLAUDE.md deleted file mode 100644 index 7c90321f17..0000000000 --- a/wiki/CLAUDE.md +++ /dev/null @@ -1,51 +0,0 @@ -# Buzz Wiki — Schema & Conventions - -This directory (`wiki/`) is an LLM-maintained knowledge base for the Buzz project. -The LLM creates, updates, and cross-references all pages. Humans read and guide. - -## Directory structure - -``` -wiki/ -├── CLAUDE.md # This file — schema, conventions, workflows -├── index.md # Catalog of all pages, organized by category -├── log.md # Append-only chronological record of changes -├── entities/ # Core system entities (Relay, Community, Agent, etc.) -├── concepts/ # Key ideas and mechanisms (Auth, Pipeline, Workflow, etc.) -├── components/ # Crate/service/client reference docs -└── operations/ # Deployment, configuration, development setup -``` - -## Page conventions - -- All pages are Markdown with `.md` extension. -- Every page starts with an `#` title matching the filename (title case). -- Every page should link to related pages using `[display text](../category/pagename)`. -- Pages in `entities/` describe a thing. Pages in `concepts/` describe an idea or mechanism. -- Pages in `components/` document a crate or client. Pages in `operations/` document how-to. -- Keep pages focused. Split into sub-pages when a section gets too long. -- Use `##` for major sections, `###` for subsections. - -## Workflows - -### Ingest a source -1. Read the source document. -2. Discuss notable points with the user. -3. Create/update relevant entity and concept pages across the wiki. -4. Update `index.md` if new pages were created. -5. Append an entry to `log.md`. - -### Answer a query -1. Read `index.md` to find relevant pages. -2. Read the relevant pages. -3. Synthesize an answer with citations to wiki pages. -4. If the answer is valuable as a new page, write it and update `index.md`. -5. Append an entry to `log.md`. - -### Lint the wiki -1. Check for contradictions between pages. -2. Find stale claims that newer entries have superseded. -3. Find orphan pages with no inbound links. -4. Find important concepts missing their own page. -5. Suggest new questions and sources to investigate. -6. Append an entry to `log.md`. diff --git a/wiki/components/admin-web.md b/wiki/components/admin-web.md deleted file mode 100644 index 47f835d076..0000000000 --- a/wiki/components/admin-web.md +++ /dev/null @@ -1,16 +0,0 @@ -# Admin Web - -Web-based admin dashboard for relay operators. Provides a graphical interface for administrative tasks. - -**Capabilities:** -- Community management (create, configure, delete) -- Channel administration -- Member management -- Audit log viewer -- System health monitoring -- Configuration editing - -**Related:** -- [buzz-admin](buzz-admin) — CLI equivalent -- [Community](../entities/community) -- [AuditLog](../concepts/audit-log) diff --git a/wiki/components/buzz-acp.md b/wiki/components/buzz-acp.md deleted file mode 100644 index 5a57e2dd95..0000000000 --- a/wiki/components/buzz-acp.md +++ /dev/null @@ -1,17 +0,0 @@ -# buzz-acp - -ACP (Agent Communication Protocol) harness. Bridges Nostr relay events to AI agent subprocesses. - -**How it works:** -- Maintains a WebSocket connection to the relay (NIP-42 auth) -- Spawns and manages agent subprocesses over stdio JSON-RPC -- Translates Nostr events → JSON-RPC calls for the agent -- Translates agent responses → Nostr events published to the relay -- Accumulates turn `agent_message_chunk` text and fallback-publishes text responses to the channel on `StopReason::EndTurn` if no tool published a message -- Sanitizes pseudo-tool parameter blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), and special tokens (`<|tool_call>`, `<|im_end|>`) via `clean_agent_text_response` -- Handles reconnection, subscription management, and agent lifecycle - -**Related:** -- [ACP](../concepts/acp) -- [Agent](../entities/agent) -- [buzz-agent](buzz-agent) diff --git a/wiki/components/buzz-admin.md b/wiki/components/buzz-admin.md deleted file mode 100644 index bff2592a93..0000000000 --- a/wiki/components/buzz-admin.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-admin - -Operator CLI for relay administration. Used for managing communities, channels, members, and system configuration. - -**Capabilities:** -- Create/delete communities -- Manage channel memberships -- View audit log -- System health checks -- Configuration management - -**Related:** -- [Community](../entities/community) -- [AdminWeb](admin-web) diff --git a/wiki/components/buzz-agent.md b/wiki/components/buzz-agent.md deleted file mode 100644 index c7131dcbe1..0000000000 --- a/wiki/components/buzz-agent.md +++ /dev/null @@ -1,20 +0,0 @@ -# buzz-agent - -A minimal ACP-compliant agent binary. Can be used as a reference implementation or as a lightweight agent for simple automation tasks. - -**Features:** -- ACP-compliant stdio JSON-RPC communication -- Basic message send/receive -- Reaction handling -- LLM provider support (Anthropic, OpenAI, local OpenAI-compatible endpoints like OMLX/Ollama) -- Reasoning content fallback (`reasoning_content` / `reasoning` parsing for local models) -- Designed to be swapped out for more capable agents (Goost, Codex, Claude Code) - -**LLM Response Parsing:** -- In `crates/buzz-agent/src/llm.rs`, responses from OpenAI-compatible endpoints are parsed by `parse_openai` and `parse_responses`. -- When local reasoning models output generated text in `reasoning_content` while leaving `content: ""`, `buzz-agent` falls back to `reasoning` to populate turn text output. - -**Related:** -- [ACP](../concepts/acp) -- [buzz-acp](buzz-acp) -- [Agent](../entities/agent) diff --git a/wiki/components/buzz-audit.md b/wiki/components/buzz-audit.md deleted file mode 100644 index 2c48d9c24a..0000000000 --- a/wiki/components/buzz-audit.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-audit - -SHA-256 hash-chain tamper-evident audit log. - -**Key responsibilities:** -- Appending audit entries to the hash chain -- Single-writer serialization via `pg_advisory_lock` -- 10 audit action types (event/create/delete, channel CRUD, member add/remove, auth success/failure, rate limit) -- Querying audit history for investigations -- All audit actions are also emitted as Nostr events - -**Related:** -- [AuditLog](../concepts/audit-log) -- [buzz-db](buzz-db) -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-auth.md b/wiki/components/buzz-auth.md deleted file mode 100644 index d5668da52a..0000000000 --- a/wiki/components/buzz-auth.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-auth - -Authentication, authorization, rate limiting, and scope enforcement. - -**Key responsibilities:** -- NIP-42 WebSocket challenge/response auth -- NIP-98 HTTP request auth -- Rate limiting per connection and per pubkey -- SSRF protection (`is_private_ip()` checking IPv4/IPv6 private/loopback/link-local ranges) -- Scope enforcement for admin operations - -**Related:** -- [Authentication](../concepts/authentication) -- [buzz-relay](buzz-relay) — integrates auth into connection lifecycle -- [ChannelMembership](../concepts/channel-membership) diff --git a/wiki/components/buzz-cli.md b/wiki/components/buzz-cli.md deleted file mode 100644 index 0acd7fd527..0000000000 --- a/wiki/components/buzz-cli.md +++ /dev/null @@ -1,16 +0,0 @@ -# buzz-cli - -Agent-first CLI tool. Designed for LLM tool calls — JSON in, JSON out. Every command accepts structured input and returns structured output. - -**Use cases:** -- Querying channel messages -- Sending messages programmatically -- Managing channels and memberships -- Triggering workflows -- Integration with agent subprocesses - -The CLI is the recommended way for agents to interact with Buzz when they need more structured control than real-time messaging provides. - -**Related:** -- [ACP](../concepts/acp) -- [Agent](../entities/agent) diff --git a/wiki/components/buzz-conformance.md b/wiki/components/buzz-conformance.md deleted file mode 100644 index 9d788ff2f9..0000000000 --- a/wiki/components/buzz-conformance.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-conformance - -Multi-tenant conformance tests. Verifies that the relay behaves correctly under multi-tenant deployment, including: - -- Tenant isolation (community A cannot see community B's data) -- Auth across tenants -- Correct scoping of events, channels, and memberships by community_id -- Rate limits per tenant - -**Related:** -- [MultiTenancy](../concepts/multi-tenancy) -- [buzz-test-client](buzz-test-client) -- [Community](../entities/community) diff --git a/wiki/components/buzz-core.md b/wiki/components/buzz-core.md deleted file mode 100644 index 0d62c52294..0000000000 --- a/wiki/components/buzz-core.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-core - -Core types and zero-I/O logic. The foundation crate that everything else depends on. Contains no I/O, no database access, no network — purely data structures and algorithms. - -**Contents:** -- Event type definitions (81 kinds in `kind.rs`) -- Event verification (Schnorr signature checks) -- Filter matching (NIP-01 filter evaluation) -- Core data structures (`Event`, `Filter`, `Subscription`, `Channel`, etc.) -- Constants, enums, and utility functions - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [buzz-relay](buzz-relay) — consumes core types -- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-db.md b/wiki/components/buzz-db.md deleted file mode 100644 index 987e8c055c..0000000000 --- a/wiki/components/buzz-db.md +++ /dev/null @@ -1,16 +0,0 @@ -# buzz-db - -Postgres event store and data access layer. Uses **sqlx** for runtime-queried database access (no compile-time macros). - -**Key responsibilities:** -- Event persistence (idempotent insert by event ID) -- Event querying (by filter, by ID, by kind, by author, by channel) -- Channel CRUD -- Community CRUD -- Search queries over `search_tsv` GIN index -- Connection pooling and migration management (25 SQL migrations, auto-applied on startup) - -**Related:** -- [buzz-relay](buzz-relay) — primary consumer -- [buzz-search](buzz-search) — search queries -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-dev-mcp.md b/wiki/components/buzz-dev-mcp.md deleted file mode 100644 index 5cc1aa286f..0000000000 --- a/wiki/components/buzz-dev-mcp.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-dev-mcp - -MCP (Model Context Protocol) server providing shell and file-edit tools. Intended for development agents that need to interact with the filesystem. - -**Tools provided:** -- Shell command execution -- File read/write/edit operations -- Directory listing - -Uses the **rmcp** SDK (Rust MCP implementation). - -**Related:** -- [ACP](../concepts/acp) -- [buzz-acp](buzz-acp) -- [buzz-persona](buzz-persona) diff --git a/wiki/components/buzz-media.md b/wiki/components/buzz-media.md deleted file mode 100644 index d749e47867..0000000000 --- a/wiki/components/buzz-media.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-media - -Blossom protocol media storage backed by S3-compatible object storage. - -**Key responsibilities:** -- File upload via HTTP (NIP-98 auth) -- Thumbnail generation (server-side image processing) -- File serving with content-type headers and caching -- Blob deletion -- S3 configuration (endpoint, bucket, region, credentials) - -**Related:** -- [MediaStorage](../concepts/media-storage) -- [buzz-relay](buzz-relay) — serves media endpoints diff --git a/wiki/components/buzz-persona.md b/wiki/components/buzz-persona.md deleted file mode 100644 index 8b62b86eaa..0000000000 --- a/wiki/components/buzz-persona.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-persona - -Agent persona packs — bundles of model configuration and system prompts that define an agent's behavior and capabilities. - -Examples: -- **Ralph** — code review persona -- **Scout** — research persona - -Each persona specifies: model backend, system prompt, tool permissions, and channel memberships. - -**Related:** -- [Agent](../entities/agent) -- [buzz-acp](buzz-acp) diff --git a/wiki/components/buzz-pubsub.md b/wiki/components/buzz-pubsub.md deleted file mode 100644 index 4f220a8828..0000000000 --- a/wiki/components/buzz-pubsub.md +++ /dev/null @@ -1,15 +0,0 @@ -# buzz-pubsub - -Redis-backed pub/sub, presence tracking, and typing indicators. - -**Key responsibilities:** -- Cross-process event broadcasting via Redis pub/sub -- Presence tracking (who is online in which channels) -- Typing indicator propagation (agents broadcast typing too) -- Uses `deadpool-redis` for connection pooling - -In a multi-process relay deployment, events published by one process are broadcast to subscribers on all processes via Redis pub/sub. - -**Related:** -- [buzz-relay](buzz-relay) -- [EventPipeline](../concepts/event-pipeline) diff --git a/wiki/components/buzz-push-gateway.md b/wiki/components/buzz-push-gateway.md deleted file mode 100644 index d0f280dce3..0000000000 --- a/wiki/components/buzz-push-gateway.md +++ /dev/null @@ -1,9 +0,0 @@ -# buzz-push-gateway - -Push notification gateway. Bridges Nostr events to push notification services (APNs for iOS, FCM for Android). - -**Flow:** Event arrives at relay → relay notifies push gateway → gateway formats push payload → sends to APNs/FCM for offline or backgrounded clients. - -**Related:** -- [MobileClient](mobile-client) -- [DesktopClient](desktop-client) diff --git a/wiki/components/buzz-relay-mesh.md b/wiki/components/buzz-relay-mesh.md deleted file mode 100644 index 8011d6000e..0000000000 --- a/wiki/components/buzz-relay-mesh.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-relay-mesh - -Inter-relay mesh transport. Uses **iroh** for peer-to-peer connections between relays. - -**Purpose:** Enables Buzz Mesh shared AI compute across relay communities. Relay instances in the mesh can share computational resources for agent inference. - -**Transport features (from iroh):** -- NAT traversal -- End-to-end encryption -- Relay fallback for difficult network conditions - -**Related:** -- [BuzzMesh](../concepts/buzz-mesh) -- [Relay](../entities/relay) diff --git a/wiki/components/buzz-relay.md b/wiki/components/buzz-relay.md deleted file mode 100644 index 74cc457d55..0000000000 --- a/wiki/components/buzz-relay.md +++ /dev/null @@ -1,24 +0,0 @@ -# buzz-relay - -The main WebSocket relay server. Built with **Axum** on **Tokio**. Coordinates all subsystems and never exposes internal crate boundaries to clients. - -**Key responsibilities:** -- WebSocket connection lifecycle (accept, auth, recv/send/heartbeat loops, cleanup) -- Event pipeline execution (12 steps) -- HTTP endpoints: `/events`, `/query`, `/count`, `/hooks/*`, `/media/*`, `/git/*` -- Connection management via `ConnectionManager` and `SubscriptionRegistry` (DashMap) -- Community binding via `TenantContext` - -**Connection lifecycle:** -1. Community binding (Host header → TenantContext) -2. Semaphore acquire (connection limit) -3. NIP-42 challenge (`["AUTH", ""]`) -4. Authentication (client signs challenge) -5. Three concurrent tasks: `recv_loop`, `send_loop`, `heartbeat_loop` (30s ping) -6. Cleanup on disconnect - -**Related:** -- [Relay](../entities/relay) -- [EventPipeline](../concepts/event-pipeline) -- [buzz-core](buzz-core) -- [buzz-db](buzz-db) diff --git a/wiki/components/buzz-sdk.md b/wiki/components/buzz-sdk.md deleted file mode 100644 index ed937562fd..0000000000 --- a/wiki/components/buzz-sdk.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-sdk - -Typed Nostr event builders for Rust. Provides a type-safe API for constructing Nostr events programmatically. - -**Features:** -- Typed event builders for common event kinds -- Automatic field validation -- Schnorr signing integration -- Filter construction helpers - -**Related:** -- [buzz-core](buzz-core) — uses core types -- [NostrEvent](../entities/nostr-event) diff --git a/wiki/components/buzz-search.md b/wiki/components/buzz-search.md deleted file mode 100644 index 8dac3c946b..0000000000 --- a/wiki/components/buzz-search.md +++ /dev/null @@ -1,14 +0,0 @@ -# buzz-search - -Postgres full-text search (FTS) index and query support. - -**Key responsibilities:** -- Maintaining the `search_tsv` tsvector column and GIN index -- Building FTS queries from NIP-50 search filters -- Excluding privacy-sensitive event kinds from indexing -- Tenant-scoped search (by `community_id`) - -**Related:** -- [Search](../concepts/search) -- [buzz-db](buzz-db) — shares the Postgres connection -- [NostrProtocol](../concepts/nostr-protocol) diff --git a/wiki/components/buzz-test-client.md b/wiki/components/buzz-test-client.md deleted file mode 100644 index 8ad778634d..0000000000 --- a/wiki/components/buzz-test-client.md +++ /dev/null @@ -1,9 +0,0 @@ -# buzz-test-client - -Integration test harness for the Buzz relay. Provides programmatic access to connect, authenticate, send events, and verify responses. - -Used by the integration test suite to verify relay behavior end-to-end. - -**Related:** -- [buzz-conformance](buzz-conformance) -- [buzz-relay](buzz-relay) diff --git a/wiki/components/buzz-workflow.md b/wiki/components/buzz-workflow.md deleted file mode 100644 index b194075c5f..0000000000 --- a/wiki/components/buzz-workflow.md +++ /dev/null @@ -1,17 +0,0 @@ -# buzz-workflow - -YAML-as-code workflow engine for channel automation. - -**Key responsibilities:** -- Loading and parsing workflow YAML files -- Evaluating trigger conditions (message_posted, reaction_added, schedule, webhook) -- Executing action chains (send_message, send_dm, set_channel_topic, add_reaction, call_webhook, request_approval, delay) -- Cron scheduler (ticks every 60 seconds) -- `evalexpr` condition evaluation with custom string/regex functions - -**Approval gates** (request_approval action): schema, API, and UI are built; executor persistence is pending. - -**Related:** -- [WorkflowEngine](../concepts/workflow-engine) -- [EventPipeline](../concepts/event-pipeline) -- [Channel](../entities/channel) diff --git a/wiki/components/buzz-ws-client.md b/wiki/components/buzz-ws-client.md deleted file mode 100644 index 1a27456250..0000000000 --- a/wiki/components/buzz-ws-client.md +++ /dev/null @@ -1,13 +0,0 @@ -# buzz-ws-client - -Shared WebSocket client library implementing NIP-42 authentication. Used by other components that need to connect to a relay as a client. - -**Features:** -- NIP-42 auth flow (connect, challenge, sign, verify) -- Automatic reconnection -- Subscription management -- Event sending and receiving - -**Related:** -- [buzz-acp](buzz-acp) — uses this for relay connections -- [Authentication](../concepts/authentication) diff --git a/wiki/components/desktop-client.md b/wiki/components/desktop-client.md deleted file mode 100644 index 37c54b7956..0000000000 --- a/wiki/components/desktop-client.md +++ /dev/null @@ -1,25 +0,0 @@ -# Desktop Client - -Native desktop application built with **Tauri 2** and **React 19**. - -**Tech stack:** -- Tauri 2 (Rust backend + webview frontend) -- React 19 with Vite -- Tailwind CSS for styling -- Biome for linting/formatting -- Playwright for E2E testing -- pnpm package manager - -**Features:** -- Stream channel real-time chat -- Forum thread browsing -- Canvas editing -- Media uploads (paste/drop/attach) -- Voice huddles (WebSocket Opus relay) -- Git repo browser (via web client embedded views) -- Agent management - -**Related:** -- [buzz-relay](buzz-relay) — backend -- [MobileClient](mobile-client) — companion app -- [WebClient](web-client) diff --git a/wiki/components/git-credential-nostr.md b/wiki/components/git-credential-nostr.md deleted file mode 100644 index 6ada7e58c7..0000000000 --- a/wiki/components/git-credential-nostr.md +++ /dev/null @@ -1,14 +0,0 @@ -# git-credential-nostr - -A git credential helper that authenticates `git push` and `git fetch` operations using a Nostr key (NIP-98 HTTP auth). - -**How it works:** -- Git calls the credential helper when it needs credentials for an HTTP remote -- The helper signs an auth request with the Nostr key -- The relay verifies the signature and allows the git operation -- No passwords, tokens, or SSH keys needed - -**Related:** -- [GitIntegration](../concepts/git-integration) -- [git-sign-nostr](git-sign-nostr) -- [Authentication](../concepts/authentication) diff --git a/wiki/components/git-sign-nostr.md b/wiki/components/git-sign-nostr.md deleted file mode 100644 index c13ddb8331..0000000000 --- a/wiki/components/git-sign-nostr.md +++ /dev/null @@ -1,9 +0,0 @@ -# git-sign-nostr - -A tool for signing git objects (commits, tags) with a Nostr key rather than a traditional PGP key. - -**Usage:** Replaces or supplements `git commit -S` / `git tag -s`. The signature is generated using the Nostr keypair (secp256k1) instead of a PGP key. - -**Related:** -- [GitIntegration](../concepts/git-integration) -- [git-credential-nostr](git-credential-nostr) diff --git a/wiki/components/mobile-client.md b/wiki/components/mobile-client.md deleted file mode 100644 index 05ea694692..0000000000 --- a/wiki/components/mobile-client.md +++ /dev/null @@ -1,21 +0,0 @@ -# Mobile Client - -Mobile application for iOS and Android built with **Flutter** and **Dart**. - -**Tech stack:** -- Flutter + Dart -- Riverpod for state management -- flutter_hooks for local state -- Catppuccin theme (Latte light / Macchiato dark) - -**Features:** -- Stream channel messaging -- Forum thread browsing -- Push notifications (via buzz-push-gateway) -- Media viewing and upload -- Agent interactions - -**Related:** -- [buzz-push-gateway](buzz-push-gateway) -- [DesktopClient](desktop-client) -- [buzz-relay](buzz-relay) diff --git a/wiki/components/sprig.md b/wiki/components/sprig.md deleted file mode 100644 index 1a96365d3c..0000000000 --- a/wiki/components/sprig.md +++ /dev/null @@ -1,13 +0,0 @@ -# sprig - -All-in-one development harness combining ACP, agent, and MCP server into a single process. Useful for local development and testing. - -**Bundles:** -- ACP harness (relay connection) -- Agent subprocess -- MCP tools (shell, file-edit) - -**Related:** -- [buzz-acp](buzz-acp) -- [buzz-agent](buzz-agent) -- [buzz-dev-mcp](buzz-dev-mcp) diff --git a/wiki/components/web-client.md b/wiki/components/web-client.md deleted file mode 100644 index 5dc6e2497e..0000000000 --- a/wiki/components/web-client.md +++ /dev/null @@ -1,13 +0,0 @@ -# Web Client - -Browser-based web application. Primarily a **repo browser** for the NIP-34 git hosting feature, served by the relay over HTTP. - -**Tech stack:** -- React + Vite -- Tailwind CSS -- Served directly by `buzz-relay` - -**Related:** -- [DesktopClient](desktop-client) -- [GitIntegration](../concepts/git-integration) -- [buzz-relay](buzz-relay) diff --git a/wiki/concepts/acp.md b/wiki/concepts/acp.md deleted file mode 100644 index 53a640a913..0000000000 --- a/wiki/concepts/acp.md +++ /dev/null @@ -1,21 +0,0 @@ -# ACP (Agent Communication Protocol) - -The Agent Communication Protocol bridges Buzz relay events to AI agent subprocesses. It is the standard way for agents to connect to a Buzz community. - -**How it works:** -- `buzz-acp` spawns an agent subprocess (e.g., Goost, Codex, Claude Code) -- Agent and harness communicate over stdio JSON-RPC -- The harness translates Nostr events (messages, reactions, etc.) into calls the agent understands -- Agent actions (sending messages, reacting, etc.) are translated back into Nostr events and published to the relay - -**Architecture:** -``` -Relay ← WebSocket → ACP Harness ← stdio JSON-RPC → Agent Subprocess -``` - -The harness maintains the WebSocket connection to the relay, handles reconnection, manages subscriptions, and translates between the two protocols. - -**Related:** -- [Agent](../entities/agent) -- [buzz-acp](../components/buzz-acp) -- [buzz-agent](../components/buzz-agent) diff --git a/wiki/concepts/architecture.md b/wiki/concepts/architecture.md deleted file mode 100644 index ad9e8c4484..0000000000 --- a/wiki/concepts/architecture.md +++ /dev/null @@ -1,43 +0,0 @@ -# Architecture - -Buzz is a self-hostable team workspace built on a single Nostr relay as the source of truth. - -## Layers - -``` -Clients (Desktop, Mobile, CLI, Agent) ← WebSocket / HTTP - │ - buzz-relay (Axum) - │ - ┌────┼────┐ - │ │ │ -Postgres Redis MinIO -``` - -**The relay** is the central coordinator. All subsystems (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) are orchestrated by `buzz-relay` and never talk to each other directly. Cross-subsystem coordination happens only through the relay. - -**Clients** connect via WebSocket (real-time) or HTTP (REST). Every action is a signed Nostr event. - -**Data stores** — Postgres (events, channels, search, audit, workflows), Redis (pub/sub, presence, typing indicators), MinIO/S3 (media attachments). - -## Design principles - -- **Single source of truth** — the relay event log. No P2P gossip. -- **URL is the community** — one URL = one isolated workspace. -- **Membership is the only gate** — no roles, no permissions, no ACLs beyond channel membership. -- **Events are immutable** — once written, events are never modified. -- **Everything is an event** — messages, reactions, workflow steps, git pushes, huddles. 81 event kinds. - -## Security model - -- NIP-42 for WebSocket auth (challenge-response) -- NIP-98 for HTTP auth (Nostr-signed HTTP requests) -- Channel membership is the only access control -- Hash-chain audit log for tamper-evident record -- SSRF protection via `is_private_ip()` checks - -**Related:** -- [Relay](../entities/relay) -- [EventPipeline](event-pipeline) -- [MultiTenancy](multi-tenancy) -- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/audit-log.md b/wiki/concepts/audit-log.md deleted file mode 100644 index 5eaa696d3e..0000000000 --- a/wiki/concepts/audit-log.md +++ /dev/null @@ -1,16 +0,0 @@ -# Audit Log - -Buzz maintains a tamper-evident audit trail using a SHA-256 hash chain. - -- Each audit entry contains: timestamp, action type, actor pubkey, target, previous hash, and metadata -- The chain is single-writer — serialized via `pg_advisory_lock` to prevent concurrent writes -- 10 audit action types: `EventCreated`, `EventDeleted`, `ChannelCreated`, `ChannelUpdated`, `ChannelDeleted`, `MemberAdded`, `MemberRemoved`, `AuthSuccess`, `AuthFailure`, `RateLimitExceeded` -- The hash chain ensures that modifying any historical entry would invalidate all subsequent hashes -- All audit actions are also Nostr events, making them visible in the relay's event stream - -**Source:** `buzz-audit` crate - -**Related:** -- [buzz-audit](../components/buzz-audit) -- [EventPipeline](event-pipeline) -- [Architecture](architecture) diff --git a/wiki/concepts/authentication.md b/wiki/concepts/authentication.md deleted file mode 100644 index f364ab32f9..0000000000 --- a/wiki/concepts/authentication.md +++ /dev/null @@ -1,22 +0,0 @@ -# Authentication - -Buzz uses Nostr's cryptographic identity model. Authentication is based on Schnorr signatures over the secp256k1 curve. - -## NIP-42 (WebSocket) - -The relay issues a random challenge string on connection. The client signs it with their Nostr private key and sends it back. The relay verifies the signature against the advertised pubkey. - -**Flow:** Connect → `["AUTH", ""]` → client signs → `["AUTH", {"event": ...}]` → verified - -## NIP-98 (HTTP) - -HTTP requests include a Nostr-signed authorization header. The relay verifies the signature against the pubkey. Used for REST endpoints (media upload, git operations, admin API). - -## Rate limiting - -The `buzz-auth` crate enforces rate limits per connection and per pubkey, with separate limits for different event kinds. - -**Related:** -- [buzz-auth](../components/buzz-auth) -- [NostrEvent](../entities/nostr-event) -- [ChannelMembership](channel-membership) diff --git a/wiki/concepts/buzz-mesh.md b/wiki/concepts/buzz-mesh.md deleted file mode 100644 index 0b6fe64e0c..0000000000 --- a/wiki/concepts/buzz-mesh.md +++ /dev/null @@ -1,14 +0,0 @@ -# Buzz Mesh - -Buzz Mesh enables relay communities to pool opted-in member hardware into shared AI compute. Agents consume this compute via a local OpenAI-compatible endpoint. - -**Transport:** Uses **iroh** for inter-relay mesh transport — a peer-to-peer networking library with NAT traversal, end-to-end encryption, and relay fallback. - -**Runtime:** Uses **llama.cpp** for native on-device LLM inference, or forwards to external providers. - -**Design goal:** Shared AI compute across a community, reducing reliance on external API providers and keeping inference local. - -**Related:** -- [Agent](../entities/agent) -- [buzz-relay-mesh](../components/buzz-relay-mesh) -- [ACP](acp) diff --git a/wiki/concepts/channel-membership.md b/wiki/concepts/channel-membership.md deleted file mode 100644 index 23bba3b78e..0000000000 --- a/wiki/concepts/channel-membership.md +++ /dev/null @@ -1,14 +0,0 @@ -# Channel Membership - -Channel membership is the only access control mechanism in Buzz. There are no roles, permissions, or ACLs — if you are a member of a channel, you can read and write to it. - -This is a deliberate design choice that simplifies the security model: the event pipeline has exactly one access control check at step 6, and it's a simple membership lookup. - -- Membership is scoped to a [Community](../entities/community) -- Agents have their own memberships, managed independently of human members -- Membership changes are themselves Nostr events (auditable) - -**Related:** -- [Channel](../entities/channel) -- [EventPipeline](event-pipeline) -- [Authentication](authentication) diff --git a/wiki/concepts/event-pipeline.md b/wiki/concepts/event-pipeline.md deleted file mode 100644 index 1a0706f0b2..0000000000 --- a/wiki/concepts/event-pipeline.md +++ /dev/null @@ -1,21 +0,0 @@ -# Event Pipeline - -Every Nostr event in Buzz goes through a 12-step pipeline when received by the relay: - -1. **Auth check** — verify the client is authenticated (NIP-42) -2. **Pubkey match** — ensure the event pubkey matches the authenticated client -3. **Reject reserved kinds** — prevent spoofing of internal event types (KIND_AUTH) -4. **Ephemeral route** — ephemeral events are broadcast but not persisted -5. **Schnorr verify** — cryptographic signature verification -6. **Membership check** — verify sender is a member of the target channel -7. **DB insert** — idempotent write to Postgres (event ID is the dedup key) -8. **Redis publish** — publish to Redis pub/sub for cross-process notification -9. **Fan-out** — send event to all subscribed WebSocket connections -10. **Search index** — update Postgres FTS search index -11. **Audit log** — append to the hash-chain audit trail -12. **Workflow trigger** — evaluate workflow conditions and execute matching actions - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [Relay](../entities/relay) -- [buzz-relay](../components/buzz-relay) diff --git a/wiki/concepts/git-integration.md b/wiki/concepts/git-integration.md deleted file mode 100644 index 0bf7e1b5bd..0000000000 --- a/wiki/concepts/git-integration.md +++ /dev/null @@ -1,21 +0,0 @@ -# Git Integration - -Buzz implements NIP-34 for git hosting, plus additional tools for Nostr-signed git operations. - -## NIP-34 Git Hosting - -The relay hosts bare git repos over smart HTTP. Repos are accessed via the relay's HTTP endpoints, authenticated with NIP-98. - -## Branch-as-Room - -Creating a feature branch automatically creates a channel where patches, CI results, reviews, and merge decisions live. This ties git workflow directly into the chat workspace. - -## Tools - -- **git-sign-nostr** — sign git commits, tags, and other objects with a Nostr key -- **git-credential-nostr** — git credential helper that authenticates push/fetch using Nostr keys - -**Related:** -- [git-sign-nostr](../components/git-sign-nostr) -- [git-credential-nostr](../components/git-credential-nostr) -- [NostrProtocol](nostr-protocol) diff --git a/wiki/concepts/media-storage.md b/wiki/concepts/media-storage.md deleted file mode 100644 index da1a5f82a4..0000000000 --- a/wiki/concepts/media-storage.md +++ /dev/null @@ -1,15 +0,0 @@ -# Media Storage - -Buzz uses the Blossom protocol for media uploads and storage, backed by S3-compatible object storage (MinIO in development, any S3 provider in production). - -- Users paste, drag, or attach files in channels -- Files are uploaded to S3 via the relay's HTTP endpoints (NIP-98 auth) -- The relay generates server-side thumbnails for images -- Files are served with content-type headers and caching -- Media events are Nostr events with references to the stored blob - -**Configuration:** S3 endpoint, bucket, region, access key, and secret key via environment variables. - -**Related:** -- [buzz-media](../components/buzz-media) -- [Relay](../entities/relay) diff --git a/wiki/concepts/multi-tenancy.md b/wiki/concepts/multi-tenancy.md deleted file mode 100644 index 921ddb16a6..0000000000 --- a/wiki/concepts/multi-tenancy.md +++ /dev/null @@ -1,19 +0,0 @@ -# Multi-Tenancy - -Buzz supports multi-tenant deployments where multiple communities share the same Postgres/Redis/MinIO infrastructure while maintaining strict isolation. - -## Isolation Model - -- **Community** is the tenant boundary — one workspace, one URL, one isolated world -- All data is scoped by `community_id` at the database level -- The relay extracts the community from the Host header on connection -- `TenantContext` is established before any handler runs - -## Formal Verification - -The multi-tenant relay behavior has been mechanized in **TLA+** for correctness verification. Authorization properties are verified in **Tamarin** (a security protocol verifier). These formal specs live in `docs/formal/`. - -**Related:** -- [Community](../entities/community) -- [Architecture](architecture) -- [buzz-conformance](../components/buzz-conformance) diff --git a/wiki/concepts/nostr-protocol.md b/wiki/concepts/nostr-protocol.md deleted file mode 100644 index f3423986da..0000000000 --- a/wiki/concepts/nostr-protocol.md +++ /dev/null @@ -1,25 +0,0 @@ -# Nostr Protocol - -Buzz is built on the Nostr protocol — an open, decentralized protocol for signed events. - -## Standard Compliance - -- Wire-compatible with NIP-01 (event format, relay-client protocol) -- NIP-42 (authentication via challenge-response) -- NIP-50 (search) -- NIP-98 (HTTP auth) -- NIP-34 (git integration) - -## Custom Extensions - -Buzz extends Nostr with 81 event kinds in the 40000-49999 custom range, covering: stream messages, forum posts, DMs, canvases, reactions, workflows, git operations, media, huddles, typing indicators, and admin actions. - -## Key Differences from P2P Nostr - -Unlike typical Nostr relays, Buzz is **not P2P**. There is no gossip or replication between relays. The relay is the single source of truth. This is intentional — Buzz is a workspace, not a decentralized social network. The Nostr protocol is used for its cryptographic identity and event model, not for federation. - -**Related:** -- [NostrEvent](../entities/nostr-event) -- [Authentication](authentication) -- [GitIntegration](git-integration) -- [EventPipeline](event-pipeline) diff --git a/wiki/concepts/search.md b/wiki/concepts/search.md deleted file mode 100644 index cddc956430..0000000000 --- a/wiki/concepts/search.md +++ /dev/null @@ -1,16 +0,0 @@ -# Search - -Buzz uses Postgres full-text search (FTS) for searching events. There is no external search service — all search is handled within Postgres. - -- Events are indexed into a `search_tsv` column (a Postgres `tsvector`) via a GIN index -- Search supports NIP-50, the Nostr standard search protocol -- Queries come in via the relay's `REQ` handler with a search filter -- Privacy-sensitive event kinds are excluded at the storage level (not indexed) -- Search is scoped by community (tenant isolation) - -**Implementation:** `buzz-search` crate handles indexing and query building over the `search_tsv` GIN index. - -**Related:** -- [buzz-search](../components/buzz-search) -- [NostrProtocol](nostr-protocol) -- [MultiTenancy](multi-tenancy) diff --git a/wiki/concepts/workflow-engine.md b/wiki/concepts/workflow-engine.md deleted file mode 100644 index 2d78319b31..0000000000 --- a/wiki/concepts/workflow-engine.md +++ /dev/null @@ -1,35 +0,0 @@ -# Workflow Engine - -Buzz has a YAML-as-code workflow engine for channel automation. Workflows are defined in YAML files, scoped to a channel, and executed by `buzz-workflow`. - -## Triggers - -| Trigger | Description | -|---|---| -| `message_posted` | Fires when a message is posted matching a text pattern | -| `reaction_added` | Fires when a reaction is added matching an emoji | -| `schedule` | Cron-based scheduled trigger (ticks every 60s) | -| `webhook` | External HTTP webhook trigger | - -## Actions - -| Action | Description | -|---|---| -| `send_message` | Post a message to the channel | -| `send_dm` | Send a direct message to a user | -| `set_channel_topic` | Update the channel topic | -| `add_reaction` | Add an emoji reaction | -| `call_webhook` | Call an external webhook URL | -| `request_approval` | Request human approval before proceeding | -| `delay` | Wait before executing next action | - -## Conditions - -Conditions are expressions evaluated with `evalexpr`, with custom functions: `str_contains`, `str_starts_with`, `str_ends_with`, `matches_regex`, and more. - -**Approval gates** are partially built (schema, API, and UI exist but executor persistence is pending). - -**Related:** -- [buzz-workflow](../components/buzz-workflow) -- [Channel](../entities/channel) -- [EventPipeline](event-pipeline) diff --git a/wiki/entities/agent.md b/wiki/entities/agent.md deleted file mode 100644 index 68e1c1ceef..0000000000 --- a/wiki/entities/agent.md +++ /dev/null @@ -1,22 +0,0 @@ -# Agent - -AI agents are first-class team members in Buzz. They have their own Nostr keypairs, channel memberships, and audit trail — exactly like human teammates, just different cryptographic identities. - -**How agents connect:** -- Agents connect via the **ACP (Agent Communication Protocol)** harness (`buzz-acp`) -- ACP bridges Nostr relay events to AI agent subprocesses over stdio JSON-RPC -- Agents use tools like Goost, Codex, Claude Code as their AI backend -- Agent teams bundle a persona (model + system prompt), e.g. Ralph for code review, Scout for research - -**Agent capabilities:** -- Send and receive messages in channels -- Participate in voice huddles via STT/TTS -- Broadcast typing indicators -- Trigger and respond to workflows -- Use `buzz-cli` for JSON-in/JSON-out interaction - -**Related:** -- [ACP](../concepts/acp) — the protocol that connects agents -- [buzz-acp](../components/buzz-acp) — ACP harness crate -- [buzz-agent](../components/buzz-agent) — minimal agent binary -- [buzz-persona](../components/buzz-persona) — persona packs diff --git a/wiki/entities/channel.md b/wiki/entities/channel.md deleted file mode 100644 index cca0c2865d..0000000000 --- a/wiki/entities/channel.md +++ /dev/null @@ -1,19 +0,0 @@ -# Channel - -Channels are communication spaces within a [Community](community). Buzz supports three channel types: - -## Stream -Slack-like real-time chat. Mandatory topics on creation. Supports sub-replies (thread-like) and has zero-notification default to reduce noise. - -## Forum -Discourse-like async long-form posts. Flat replies. Designed for asynchronous discussion rather than real-time chat. - -## Direct Messages -1:1 and group DMs (up to 9 participants). Private communication outside of stream/forum channels. - -**Channel membership is the only access control gate** in Buzz. If you're a member of a channel, you can read and write to it. There are no roles, permissions, or ACLs beyond membership. - -**Related:** -- [ChannelMembership](../concepts/channel-membership) — access control model -- [Community](community) — parent tenant -- [NostrEvent](nostr-event) — every channel action is an event diff --git a/wiki/entities/community.md b/wiki/entities/community.md deleted file mode 100644 index ade52f5fac..0000000000 --- a/wiki/entities/community.md +++ /dev/null @@ -1,14 +0,0 @@ -# Community - -A community is a workspace — the tenant boundary in Buzz. One URL, one isolated world. Multi-tenant deployments share Postgres/Redis/MinIO infrastructure but scope all data by `community_id`. - -- The URL is authoritative: the host header determines which community a request belongs to -- A community has its own channels, members (human and agent), workflows, audit log, and git repos -- Communities cannot see each other's data - -**Connection flow:** A client connects via WebSocket → the relay extracts the community from the Host header → establishes `TenantContext` → enforces connection limits per community → authenticates the client. - -**Related:** -- [Relay](relay) — serving a community -- [MultiTenancy](../concepts/multi-tenancy) — isolation model -- [Channel](channel) — communication spaces within a community diff --git a/wiki/entities/nostr-event.md b/wiki/entities/nostr-event.md deleted file mode 100644 index 0f0f6bd915..0000000000 --- a/wiki/entities/nostr-event.md +++ /dev/null @@ -1,15 +0,0 @@ -# Nostr Event - -The atomic unit of all activity in Buzz. Every action — a chat message, a reaction, a workflow step, a canvas update, a git push, a huddle voice event — is a cryptographically signed Nostr event. - -Events follow the NIP-01 standard and are extended with custom kinds in the 40000-49999 range. Buzz defines **81 event kinds** across stream channels, forums, DMs, canvases, reactions, workflows, git, media, huddles, and admin operations. - -**Event pipeline (12 steps):** -1. Auth check → 2. Pubkey match → 3. Reject reserved kinds → 4. Ephemeral route → 5. Schnorr verify → 6. Membership check → 7. DB insert (idempotent) → 8. Redis publish → 9. Fan-out to subscribers → 10. Search index → 11. Audit log → 12. Workflow trigger - -**Source:** `crates/buzz-core/src/kind.rs` for the full kind list. - -**Related:** -- [EventPipeline](../concepts/event-pipeline) — the 12-step lifecycle -- [Relay](relay) — processes all events -- [Authentication](../concepts/authentication) — NIP-42/NIP-98 signing diff --git a/wiki/entities/relay.md b/wiki/entities/relay.md deleted file mode 100644 index c6d4d124ba..0000000000 --- a/wiki/entities/relay.md +++ /dev/null @@ -1,16 +0,0 @@ -# Relay - -The Nostr relay server is the single source of truth for a Buzz community. All reads and writes — chat messages, reactions, workflow triggers, canvas updates, git pushes, huddle events — flow through it as signed Nostr events. - -Built with **Axum** on **Tokio**, the relay handles WebSocket connections, HTTP requests, and coordinates all subsystems. It imports all service crates (`buzz-db`, `buzz-auth`, `buzz-pubsub`, `buzz-search`, `buzz-audit`, `buzz-workflow`) and orchestrates cross-subsystem coordination. - -**Key traits:** -- Single source of truth — no P2P gossip or replication -- Every action is a signed Nostr event -- All subsystems are coordinated through the relay, never directly between crates -- URL is authoritative — the relay's URL defines the community - -**Related:** -- [Community](community) — tenant boundary -- [EventPipeline](../concepts/event-pipeline) — event lifecycle -- [buzz-relay](../components/buzz-relay) — implementation crate diff --git a/wiki/index.md b/wiki/index.md deleted file mode 100644 index f2ec1332e6..0000000000 --- a/wiki/index.md +++ /dev/null @@ -1,66 +0,0 @@ -# Index - -Catalog of all wiki pages, organized by category. - -## Entities - -- [Relay](entities/relay) — the Nostr relay server; the single source of truth for a community -- [Community](entities/community) — a workspace; one URL, one isolated tenant -- [Agent](entities/agent) — an AI agent as a first-class team member with its own Nostr keypair -- [Channel](entities/channel) — stream, forum, and DM communication spaces -- [NostrEvent](entities/nostr-event) — the atomic unit of all activity; a cryptographically signed event - -## Concepts - -- [Architecture](concepts/architecture) — system overview, layers, and design principles -- [EventPipeline](concepts/event-pipeline) — the 12-step lifecycle of an event from receipt to fan-out -- [Authentication](concepts/authentication) — NIP-42 challenge-response and NIP-98 HTTP auth -- [ChannelMembership](concepts/channel-membership) — access control model (membership is the only gate) -- [WorkflowEngine](concepts/workflow-engine) — YAML-as-code channel automation with triggers and actions -- [AuditLog](concepts/audit-log) — SHA-256 hash-chain tamper-evident audit trail -- [BuzzMesh](concepts/buzz-mesh) — inter-relay mesh for pooled AI compute -- [ACP](concepts/acp) — Agent Communication Protocol bridging Nostr events to agent subprocesses -- [GitIntegration](concepts/git-integration) — NIP-34 git hosting, signing, and branch-as-room -- [MediaStorage](concepts/media-storage) — Blossom protocol media uploads on S3/MinIO -- [Search](concepts/search) — Postgres FTS full-text search over events -- [MultiTenancy](concepts/multi-tenancy) — community isolation model and formal verification -- [NostrProtocol](concepts/nostr-protocol) — Nostr wire protocol and Buzz's custom event kinds - -## Components - -- [buzz-relay](components/buzz-relay) — main WebSocket relay server (Axum) -- [buzz-core](components/buzz-core) — core types, event verification, filter matching (zero I/O) -- [buzz-db](components/buzz-db) — Postgres event store and data access layer -- [buzz-auth](components/buzz-auth) — auth, rate limiting, and scope enforcement -- [buzz-pubsub](components/buzz-pubsub) — Redis pub/sub, presence, typing indicators -- [buzz-search](components/buzz-search) — Postgres FTS search index -- [buzz-audit](components/buzz-audit) — hash-chain audit log -- [buzz-media](components/buzz-media) — Blossom/S3 media storage -- [buzz-workflow](components/buzz-workflow) — YAML workflow engine -- [buzz-acp](components/buzz-acp) — ACP harness for agent subprocess orchestration -- [buzz-agent](components/buzz-agent) — minimal ACP-compliant agent binary -- [buzz-dev-mcp](components/buzz-dev-mcp) — MCP server providing shell and file-edit tools -- [buzz-persona](components/buzz-persona) — agent persona packs (model + system prompt) -- [buzz-cli](components/buzz-cli) — agent-first CLI (JSON in/out) -- [buzz-sdk](components/buzz-sdk) — typed Nostr event builders -- [buzz-admin](components/buzz-admin) — operator CLI for relay administration -- [buzz-ws-client](components/buzz-ws-client) — shared WebSocket client (NIP-42) -- [buzz-test-client](components/buzz-test-client) — integration test harness -- [buzz-conformance](components/buzz-conformance) — multi-tenant conformance tests -- [buzz-push-gateway](components/buzz-push-gateway) — push notification gateway -- [buzz-relay-mesh](components/buzz-relay-mesh) — iroh-based inter-relay mesh transport -- [git-sign-nostr](components/git-sign-nostr) — sign git objects with a Nostr key -- [git-credential-nostr](components/git-credential-nostr) — git credential helper for Nostr auth -- [sprig](components/sprig) — all-in-one harness (ACP + agent + MCP) -- [DesktopClient](components/desktop-client) — Tauri 2 + React 19 native desktop app -- [MobileClient](components/mobile-client) — Flutter mobile app (iOS + Android) -- [WebClient](components/web-client) — browser-based web client (repo browser) -- [AdminWeb](components/admin-web) — admin dashboard - -## Operations - -- [DevelopmentSetup](operations/development-setup) — local dev environment setup with Docker Compose -- [Deployment](operations/deployment) — production deployment with Helm and Docker Compose -- [Configuration](operations/configuration) — environment variables and community config -- [CLIReference](operations/cli-reference) — just commands and common dev workflows -- [Troubleshooting](operations/troubleshooting) — common issues and fixes diff --git a/wiki/log.md b/wiki/log.md deleted file mode 100644 index 2223b00be6..0000000000 --- a/wiki/log.md +++ /dev/null @@ -1,47 +0,0 @@ -# Log - -Chronological record of wiki changes. Each entry uses the format: -`## [YYYY-MM-DD] type | Title` - -- **ingest** — a new source was read and integrated -- **query** — a question was answered and the result was filed -- **lint** — a health check was performed -- **update** — pages were revised or created outside of ingest/query - ---- - -## [2026-07-27] ingest | Initial Wiki Creation - -Created the initial wiki for the Buzz project based on project source code and documentation. - -**Pages created:** -- `CLAUDE.md` — schema, conventions, and workflows -- `index.md` — catalog of all pages -- `log.md` — this file -- `entities/relay.md`, `entities/community.md`, `entities/agent.md`, `entities/channel.md`, `entities/nostr-event.md` -- `concepts/architecture.md`, `concepts/event-pipeline.md`, `concepts/authentication.md`, `concepts/channel-membership.md`, `concepts/workflow-engine.md`, `concepts/audit-log.md`, `concepts/buzz-mesh.md`, `concepts/acp.md`, `concepts/git-integration.md`, `concepts/media-storage.md`, `concepts/search.md`, `concepts/multi-tenancy.md`, `concepts/nostr-protocol.md` -- `components/buzz-relay.md`, `components/buzz-core.md`, `components/buzz-db.md`, `components/buzz-auth.md`, `components/buzz-pubsub.md`, `components/buzz-search.md`, `components/buzz-audit.md`, `components/buzz-media.md`, `components/buzz-workflow.md`, `components/buzz-acp.md`, `components/buzz-agent.md`, `components/buzz-dev-mcp.md`, `components/buzz-persona.md`, `components/buzz-cli.md`, `components/buzz-sdk.md`, `components/buzz-admin.md`, `components/buzz-ws-client.md`, `components/buzz-test-client.md`, `components/buzz-conformance.md`, `components/buzz-push-gateway.md`, `components/buzz-relay-mesh.md`, `components/git-sign-nostr.md`, `components/git-credential-nostr.md`, `components/sprig.md`, `components/desktop-client.md`, `components/mobile-client.md`, `components/web-client.md`, `components/admin-web.md` -- `operations/development-setup.md`, `operations/deployment.md`, `operations/configuration.md`, `operations/cli-reference.md` - -## [2026-07-27] update | Added Troubleshooting Page - -Created `operations/troubleshooting.md` covering common issues: 521 errors when connecting to cloud relays, port conflicts, rate limiting, Docker health, and event rejection. Updated `index.md` to link the new page. - -## [2026-07-27] query | Agent Shows Response Bubble But Doesn't Publish - -Investigated agent response not publishing. Two root causes found: -1. Agent was connected to `wss://milimo.communities.buzz.xyz` instead of `ws://localhost:3000` — hardcoded in `managed-agents.json`. Responses went to the wrong relay. -2. Even on the correct relay, the LLM (Qwen3.6-35B-A3B-bf16 via OMLX) returns text via ACP `agent_message_chunk` but doesn't call the `shell` tool to run `buzz messages send`. The harness does not auto-publish agent output. - -Updated `operations/troubleshooting.md` with both causes and fixes. - -## [2026-07-28] update | Root Causes Resolved — Wiki Updated - -Applied fixes from investigation: -- **Local LLM reasoning content**: `buzz-agent` now handles `reasoning_content` field from OpenAI-compatible endpoints (local models), falling back to `content` when `reasoning_content` is absent. -- **Fallback turn text publishing**: `buzz-acp` now accumulates `agent_message_chunk` text during a turn and publishes a `kind: 9` channel message on `StopReason::EndTurn` if no `send_message` tool call was made. Enables non-tool-calling models to participate. -- **Response sanitization**: `clean_agent_text_response` strips pseudo-tool JSON blocks (`` ```json ... ``` ``) and model tokens (`<|tool_call|>`, `<|im_end|>`) from generated text. -- **Owner pubkey seeding**: `agent_owner_pubkey` seeded in Postgres `users` table across all local dev community hosts (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`). -- **Agent config schema**: Fixed `managed-agents.json` parsing for required field `acp_command`; cleaned up `.invalid` backup files. - -Updated `operations/troubleshooting.md`, `components/buzz-agent.md`, `components/buzz-acp.md`. diff --git a/wiki/operations/cli-reference.md b/wiki/operations/cli-reference.md deleted file mode 100644 index a17a2c96d6..0000000000 --- a/wiki/operations/cli-reference.md +++ /dev/null @@ -1,55 +0,0 @@ -# CLI Reference - -## just (task runner) - -The `Justfile` at the project root provides common development commands. - -### Development - -| Command | Description | -|---|---| -| `just dev` | Start full dev stack (Docker Compose) | -| `just dev-reset` | Destroy and recreate dev stack | -| `just seed-local-community` | Seed sample data | -| `just desktop` | Launch desktop client dev server | -| `just mobile` | Launch Flutter dev server | - -### Testing - -| Command | Description | -|---|---| -| `just test-all` | Run all tests | -| `just test-rust` | Run Rust tests | -| `just test-desktop` | Run desktop E2E tests (Playwright) | -| `just test-mobile` | Run Flutter tests | - -### Building - -| Command | Description | -|---|---| -| `just build-relay` | Build relay binary | -| `just build-desktop` | Build desktop app | -| `just build-mobile` | Build mobile app | -| `just docker` | Build Docker images | - -## cargo - -Standard Cargo commands work. Key workspace crates: - -```bash -cargo build -p buzz-relay -cargo test -p buzz-conformance -cargo clippy -p buzz-core -``` - -## Hermit - -Hermit manages toolchain versions. Activate automatically by `cd`-ing into `buzz/`, or manually: - -```bash -. bin/activate-hermit -``` - -**Related:** -- [DevelopmentSetup](development-setup) -- [Deployment](deployment) diff --git a/wiki/operations/configuration.md b/wiki/operations/configuration.md deleted file mode 100644 index 5d34b98a68..0000000000 --- a/wiki/operations/configuration.md +++ /dev/null @@ -1,35 +0,0 @@ -# Configuration - -Buzz is configured primarily through environment variables. - -## Core - -| Variable | Description | -|---|---| -| `DATABASE_URL` | Postgres connection string | -| `REDIS_URL` | Redis connection string | -| `RELAY_URL` | Public URL of the relay | -| `RELAY_PORT` | Listen port (default: 8080) | - -## Media (S3/MinIO) - -| Variable | Description | -|---|---| -| `S3_ENDPOINT` | S3-compatible endpoint URL | -| `S3_BUCKET` | Bucket name for media storage | -| `S3_REGION` | AWS region (default: us-east-1) | -| `S3_ACCESS_KEY` | Access key | -| `S3_SECRET_KEY` | Secret key | - -## Auth - -| Variable | Description | -|---|---| -| `RATE_LIMIT_MESSAGES` | Messages per minute per connection | -| `RATE_LIMIT_CONNECTIONS` | Max connections per IP | - -See `.env.example` for the full list. - -**Related:** -- [DevelopmentSetup](development-setup) -- [Deployment](deployment) diff --git a/wiki/operations/deployment.md b/wiki/operations/deployment.md deleted file mode 100644 index 09f974a018..0000000000 --- a/wiki/operations/deployment.md +++ /dev/null @@ -1,30 +0,0 @@ -# Deployment - -## Docker Compose (Production) - -A production-ready Docker Compose bundle is available in `deploy/compose/`. It includes: -- `buzz-relay` (with all service crates compiled in) -- PostgreSQL 17 -- Redis 7 -- MinIO (S3-compatible storage) -- Prometheus (metrics) - -## Helm (Kubernetes) - -Helm charts are in `deploy/charts/`. Suitable for production multi-tenant deployments. - -## Requirements - -- PostgreSQL 17 -- Redis 7 -- S3-compatible object storage (MinIO, AWS S3, etc.) -- TLS termination (reverse proxy with Let's Encrypt) - -## Configuration - -All configuration is via environment variables. See [Configuration](configuration) for the full list. - -**Related:** -- [DevelopmentSetup](development-setup) -- [Configuration](configuration) -- [MultiTenancy](../concepts/multi-tenancy) diff --git a/wiki/operations/development-setup.md b/wiki/operations/development-setup.md deleted file mode 100644 index f06428373f..0000000000 --- a/wiki/operations/development-setup.md +++ /dev/null @@ -1,48 +0,0 @@ -# Development Setup - -## Prerequisites - -- **Hermit** (pinned toolchain manager) — activates automatically in the `buzz/` directory -- **Docker Desktop** — for Postgres, Redis, and MinIO containers -- Rust, Node, pnpm, Flutter — all managed by Hermit - -## Quick start - -```bash -# From the buzz/ directory -just dev -``` - -This starts the full stack via Docker Compose: Postgres 17, Redis 7, MinIO, and the relay. - -## Key commands - -| Command | Description | -|---|---| -| `just dev` | Start full dev environment | -| `just dev-reset` | Reset dev environment (destroy data) | -| `cargo build -p buzz-relay` | Build the relay | -| `cargo test -p buzz-conformance` | Run conformance tests | -| `just desktop` | Start the desktop client | -| `just mobile` | Start the mobile client | - -## Environment - -Copy `.env.example` to `.env` and configure. Key variables: -- `DATABASE_URL` — Postgres connection string -- `REDIS_URL` — Redis connection string -- `S3_ENDPOINT` — MinIO/S3 endpoint -- `RELAY_URL` — the relay's external URL - -## Seeding - -```bash -just seed-local-community -``` - -Creates a local community with sample channels and test data. - -**Related:** -- [Deployment](deployment) -- [Configuration](configuration) -- [CLIReference](cli-reference) diff --git a/wiki/operations/troubleshooting.md b/wiki/operations/troubleshooting.md deleted file mode 100644 index 23b2dd8606..0000000000 --- a/wiki/operations/troubleshooting.md +++ /dev/null @@ -1,220 +0,0 @@ -# Troubleshooting - -Common issues when running Buzz locally. - -## "Can't reach the relay" / "relay returned 521 Unknown Status Code" - -521 is a [Cloudflare-specific status code](https://en.wikipedia.org/wiki/HTTP_521) meaning Cloudflare's edge can't reach the origin server. This happens when the desktop app is trying to connect to a Cloudflare-proxied URL (e.g. `wss://buzz.block.builderlab.xyz` or a staging/production relay) that is down or unreachable. - -**Fix:** Connect to your local relay instead — use `ws://localhost:3000` as the relay URL. - -If the app cached a previous cloud URL, clear the stored state: - -```bash -just desktop-standalone fresh=1 -``` - -Then start fresh: - -```bash -just dev -``` - -The error is generated in `desktop/src-tauri/src/relay.rs:295` (HTTP fallback) and classified in `desktop/src/shared/lib/relayError.ts` (checks for `relay unreachable:` prefix — 521 doesn't match it, so it's treated as an application error rather than a network error). - -## "relay unreachable: could not connect to relay" - -The relay process isn't running or isn't reachable on the expected port. - -**Checks:** - -```bash -# Is the relay binary running? -ps aux | grep buzz-relay - -# Is it listening on the right port? -lsof -i :3000 - -# Are Docker services up? -docker compose ps - -# Check health endpoints -curl http://localhost:8080/_liveness -curl http://localhost:8080/_readiness -``` - -**Fix:** Start the relay: - -```bash -just relay -``` - -## Port already in use - -``` -Error: relay port 3000 is already in use; refusing to launch desktop against a stale relay. -``` - -A previous relay instance is still running. Kill it: - -```bash -pkill buzz-relay -just dev -``` - -## "relay rate-limited: retry in Ns" - -The relay's Redis-backed rate limiter has been hit. Wait the indicated time and retry. Rate limits are configured via `BUZZ_RATE_LIMIT_*` env vars in `.env`. - -## Docker services not healthy - -If `docker compose ps` shows `unhealthy`: - -```bash -# Check individual service logs -docker compose logs postgres -docker compose logs redis - -# Full reset -just reset -``` - -## Relay starts but immediately exits - -Check the relay logs for database connection errors. Ensure Postgres is healthy and `DATABASE_URL` in `.env` is correct (default: `postgres://buzz:buzz_dev@localhost:5432/buzz`). - -## "No auth challenge received" - -The WebSocket connection succeeded but the relay didn't send a NIP-42 AUTH challenge. This usually means the relay is not configured to require auth (`auth_required: true` in the NIP-11 response). Check `RELAY_URL` in `.env` points to the correct relay. - -## "Event rejected by relay" - -The relay rejected a published event. Possible causes: - -- Event signature verification failed -- Sender is not a member of the target channel -- Event kind is not allowed -- Rate limit exceeded - -Check the relay logs for details (`RUST_LOG=debug` is set in `.env`). - -## Agent shows response text in a "bubble" but never publishes to the channel - -The agent generates text (GPU spikes, LLM runs, text appears in a UI bubble) but the message never shows up in the channel timeline. - -### Cause 1: Agent connected to the wrong relay - -The agent's `managed-agents.json` may have a hardcoded `relay_url` pointing to a different relay than the one you're using. Check: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -If you see `relay_url` set to a remote URL (e.g. `wss://milimo.communities.buzz.xyz`) instead of `ws://localhost:3000`, the agent publishes responses to the wrong relay. - -**Fix:** Edit the file to replace the remote URL with your local relay: - -```bash -sed -i '' 's|wss://milimo.communities.buzz.xyz|ws://localhost:3000|g' \ - ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json -``` - -Then kill the agent processes — the desktop app will respawn them with the correct URL: - -```bash -pkill -f buzz-acp -pkill -f buzz-agent -pkill -f buzz-dev-mcp -``` - -### Cause 2: LLM returns text but doesn't call the publish tool - -Buzz has two separate rendering paths for agent content: - -| Aspect | Session Transcript (ACP Panel) | Channel Timeline | -|---|---|---| -| Event source | Kind 24200 observer frames (ACP protocol) | Kind 9 / 40002 Nostr events | -| Agent text | `agent_message_chunk` → transcript item | Only if agent publishes explicitly | -| Where shown | Side panel (click "View activity") | Main channel content area | - -The agent generates text and sends it via ACP's `agent_message_chunk` update — this renders in the session transcript panel as a "bubble." But the harness (`buzz-acp`) does **not** auto-publish agent output to the relay. At `crates/buzz-acp/src/lib.rs:3232`, `PromptOutcome::Ok(_)` just returns the agent to the pool without sending anything. - -The agent must **explicitly publish** its response by calling one of: -1. `buzz messages send` via the MCP `shell` tool (`buzz-dev-mcp` provides this) -2. The `send_message` ACP tool (dedicated agent tool) -3. The desktop Tauri IPC `send_managed_agent_channel_message` handler - -To verify if the agent is calling the tool, check the `buzz-dev-mcp` logs: - -```bash -cat ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/logs/*.log | grep -i 'shell\|tool_call\|buzz messages' -``` - -### Cause 3: Local LLM returns reasoning in `reasoning_content` or lacks native tool-calling - -When using local OpenAI-compatible LLM endpoints (e.g. OMLX, Ollama, or local 4-bit/8-bit models like `gemma-4-12b`): - -1. **Empty `content` with non-empty `reasoning_content`**: Local reasoning models output text under `reasoning_content` or `reasoning` while leaving `content: ""`. Both `parse_openai` and `parse_responses` in `buzz-agent` (`crates/buzz-agent/src/llm.rs`) fall back to `reasoning` when `text` is empty and no tool calls exist. -2. **Fallback Turn Text Publishing**: When models output text without executing a `buzz messages send` tool call, `buzz-acp` (`crates/buzz-acp/src/pool.rs`) accumulates `agent_message_chunk` text during the turn and posts it directly to the channel as a `kind: 9` event upon `StopReason::EndTurn`. -3. **Cleaning Pseudo-tool Code Blocks & CLI Payloads**: `clean_agent_text_response` strips pseudo-tool JSON blocks (` ```json ... ``` `), Python pseudo-code blocks (` ```python def reply_to_mention... ``` `), raw CLI stdout execution outputs (`{"accept": true, "event_id": "..."}`), step-by-step pseudo-execution noise, and special model tokens (`<|tool_call>`, `<|im_end|>`) so that only clean conversational text is posted to the channel. - -## Duplicate Agent Cards Appearing in UI (Builtin Personas vs Standalone Managed Agents) - -The desktop UI renders agent cards in `UnifiedAgentsSection.tsx` by running `buildUnifiedGroups(personas, agents)`. - -- Top cards (with alien face avatars) are **Builtin Personas** (`builtin:fizz`, `builtin:honey`, `builtin:bumble`). -- Bottom cards (with grey circle avatars) are **Managed Agent Instances** loaded from `managed-agents.json`. - -If an agent record in `managed-agents.json` has `"persona_id": null` (or omitted), `buildUnifiedGroups` cannot associate the managed agent instance with its builtin persona. It places the agent under `ungrouped`, displaying duplicate standalone cards. - -**Fix:** Ensure each agent record in `managed-agents.json` explicitly references its corresponding persona ID: - -```json -[ - { - "name": "Fizz", - "persona_id": "builtin:fizz", - ... - }, - { - "name": "Honey", - "persona_id": "builtin:honey", - ... - }, - { - "name": "Bumble", - "persona_id": "builtin:bumble", - ... - } -] -``` - -## "Agent; owner unavailable" badge next to agent name - -The desktop UI displays **"owner unavailable"** when the agent user profile in the Postgres database lacks an `agent_owner_pubkey` mapping to the human owner. - -**Fix:** Ensure the active agent pubkeys are inserted into the `users` table with `agent_owner_pubkey` set to the owner's pubkey across all active community host entries (`localhost:3000`, `127.0.0.1:3000`, `localhost`, `127.0.0.1`): - -```sql -INSERT INTO users (community_id, pubkey, agent_owner_pubkey, created_at, updated_at, channel_add_policy) -SELECT c.id, decode('', 'hex'), decode('', 'hex'), NOW(), NOW(), 'anyone'::channel_add_policy -FROM communities c -ON CONFLICT (community_id, pubkey) DO UPDATE SET agent_owner_pubkey = EXCLUDED.agent_owner_pubkey; -``` - -## "failed to parse agent store: missing field 'acp_command'" error banner - -The desktop app displays a red warning banner `failed to parse agent store (preserved as .invalid): missing field 'acp_command'` when `managed-agents.json` is missing required non-defaulted fields for `ManagedAgentRecord`. - -**Fix:** Ensure `managed-agents.json` contains all required schema fields (`pubkey`, `name`, `relay_url`, `acp_command` [e.g. `"buzz-acp"`], `agent_command` [e.g. `"buzz-agent"`], `mcp_command` [e.g. `"buzz-dev-mcp"`], `turn_timeout_seconds` [e.g. `900`], `agent_args` [`[]`]) and remove any `.invalid` backup file: - -```bash -rm -f ~/Library/Application\ Support/xyz.block.buzz.app.dev.main/agents/managed-agents.json.invalid -``` - -**Related:** -- [DevelopmentSetup](development-setup) — how to start the dev environment -- [Configuration](configuration) — env var reference -- [CLIReference](cli-reference) — just commands -- [Relay](../entities/relay) — relay entity docs - From 48ac9a1b63485d1821e2d6a543797c4fc319b373 Mon Sep 17 00:00:00 2001 From: mainza-ai Date: Wed, 29 Jul 2026 10:16:13 -0500 Subject: [PATCH 14/14] fix(desktop): streamline types.rs line count under check-file-sizes limit Signed-off-by: mainza-ai --- desktop/src-tauri/src/managed_agents/types.rs | 81 +++++-------------- 1 file changed, 19 insertions(+), 62 deletions(-) diff --git a/desktop/src-tauri/src/managed_agents/types.rs b/desktop/src-tauri/src/managed_agents/types.rs index e5c280c7c3..5a58ad9b9f 100644 --- a/desktop/src-tauri/src/managed_agents/types.rs +++ b/desktop/src-tauri/src/managed_agents/types.rs @@ -77,21 +77,14 @@ pub struct AgentDefinition { /// Stored as a BTreeMap for deterministic on-disk ordering. #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] pub env_vars: BTreeMap, - /// NIP-AP behavioral defaults, stored in WIRE shape (kebab-case string, - /// not the `RespondTo` enum) so `persona_event_content` is a verbatim - /// copy and quad-absent records serialize byte-identically to the - /// pre-activation era. Copied onto instances at mint time only — spawn - /// re-snapshot never touches them. Validated at the instance boundary. #[serde(default, skip_serializing_if = "Option::is_none")] pub respond_to: Option, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub respond_to_allowlist: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub parallelism: Option, - #[serde(default)] - pub created_at: String, - #[serde(default)] - pub updated_at: String, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, } impl AgentDefinition { @@ -243,35 +236,15 @@ pub struct ManagedAgentRecord { /// against what was actually published rather than re-deriving it from /// persona config — which would silently overwrite user intent on restart. /// `#[serde(default)]` so pre-existing records deserialize as `None`. - #[serde(default)] - pub avatar_url: Option, - #[serde(default = "default_acp_command")] - pub acp_command: String, - #[serde(default)] - pub agent_command: String, + #[serde(default)] pub avatar_url: Option, + #[serde(default = "default_acp_command")] pub acp_command: String, + #[serde(default)] pub agent_command: String, /// Explicit per-instance harness pin. `None` (the default) means inherit - /// the harness from the linked persona's `runtime`, so persona harness - /// edits propagate on the next spawn — mirroring the opt-in `model` - /// override. `Some` is set only when the user deliberately picks a harness - /// that diverges from the persona. Resolved via `effective_agent_command`; - /// `agent_command` above is the create-time snapshot kept for avatar/legacy - /// derivations and is not authoritative for spawn. - #[serde(default)] - pub agent_command_override: Option, - #[serde(default)] - pub agent_args: Vec, - /// Create-time snapshot of the catalog MCP command. Never read at spawn — - /// the effective MCP command is always re-derived from the runtime catalog - /// (`known_acp_runtime`) — and no longer written by updates. Kept for - /// serde compatibility with existing stores. - #[serde(default)] - pub mcp_command: String, - /// Deprecated: `BUZZ_ACP_TURN_TIMEOUT` is ignored by the harness and the - /// desktop no longer emits or edits it. Kept for serde compatibility with - /// existing stores; use `idle_timeout_seconds` or - /// `max_turn_duration_seconds` for turn-length control. - #[serde(default)] - pub turn_timeout_seconds: u64, + /// the harness from the linked persona's `runtime`. + #[serde(default)] pub agent_command_override: Option, + #[serde(default)] pub agent_args: Vec, + #[serde(default)] pub mcp_command: String, + #[serde(default)] pub turn_timeout_seconds: u64, /// Idle timeout in seconds (`BUZZ_ACP_IDLE_TIMEOUT`): how long the agent /// may stay silent on its ACP channel mid-turn before the harness times /// the turn out. @@ -330,33 +303,17 @@ pub struct ManagedAgentRecord { #[serde(default)] pub provider_binary_path: Option, /// Installed team directory path (absolute). Set when agent was created from a team persona. - #[serde( - default, - skip_serializing_if = "Option::is_none", - alias = "persona_pack_path" - )] + #[serde(default, skip_serializing_if = "Option::is_none", alias = "persona_pack_path")] pub persona_team_dir: Option, - /// Persona name within the team. - #[serde( - default, - skip_serializing_if = "Option::is_none", - alias = "persona_name_in_pack" - )] + #[serde(default, skip_serializing_if = "Option::is_none", alias = "persona_name_in_pack")] pub persona_name_in_team: Option, - #[serde(default)] - pub created_at: String, - #[serde(default)] - pub updated_at: String, - #[serde(default)] - pub last_started_at: Option, - #[serde(default)] - pub last_stopped_at: Option, - #[serde(default)] - pub last_exit_code: Option, - #[serde(default)] - pub last_error: Option, - #[serde(default)] - pub last_error_code: Option, + #[serde(default)] pub created_at: String, + #[serde(default)] pub updated_at: String, + #[serde(default)] pub last_started_at: Option, + #[serde(default)] pub last_stopped_at: Option, + #[serde(default)] pub last_exit_code: Option, + #[serde(default)] pub last_error: Option, + #[serde(default)] pub last_error_code: Option, /// Inbound author gate mode. Translates to `BUZZ_ACP_RESPOND_TO`. #[serde(default)] pub respond_to: RespondTo,