Managed agents bind to a different relay community than the owner on loopback, discover 0 channels, and stay idle
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
---
name: Bug report
about: Report a reproducible bug in Buzz
labels: bug
---
**Describe the bug**
Managed agents (desktop → `buzz-acp` → `buzz-agent`) can silently connect to a **different relay community** than the owner's desktop in local loopback development, discover **0 channels**, and sit idle forever — never replying to mentions.
Root cause is a loopback-host equivalence mismatch between two normalizers:
- `buzz_core::relay::normalize_relay_url` (`crates/buzz-core/src/relay.rs`) is the **sole** normalizer for `(agent, relay)` runtime identity. It folds **all** loopback spellings (`localhost`, `127.*`, `[::1]`) to `127.0.0.1`.
- The desktop passes the **canonicalized** URL to the spawned agent: `ManagedAgentRuntimeKey::new(...)` calls `normalize_relay_url`, and `start_managed_agent_process` sets `command.env("BUZZ_RELAY_URL", )`. So the agent connects to `ws://127.0.0.1:3000`.
- The relay binds HTTP/WS requests to a community via the `Host` header through `buzz_core::tenant::normalize_host` (`crates/buzz-core/src/tenant.rs`), which lowercases/strips default ports but **does not** collapse `localhost` vs `127.0.0.1`. Those are deliberately distinct hosts.
- `scripts/seed-local-community.sh` seeds **four** community rows for loopback dev (`localhost`, `127.0.0.1`, `localhost:3000`, `127.0.0.1:3000`) — so the empty `127.0.0.1:3000` row exists and binds successfully.
Net effect: the owner desktop uses `ws://localhost:3000` → community `localhost:3000` (where channels/members/events live), while the agent uses `ws://127.0.0.1:3000` → the **separate, empty** community `127.0.0.1:3000`. The agent's channel-discovery query (kind 39002 with `#p` = agent pubkey) returns 0 events, so the startup log prints `discovered 0 channel(s)` / `no channel subscriptions resolved — agent will sit idle`, and the agent never responds to owner mentions.
The auth seam (`buzz-auth/src/nip98.rs::normalize_url`, NIP-42) deliberately treats loopback spellings as distinct hosts, so collapsing `normalize_host` on the relay side is **not** a safe fix — it would break NIP-98/NIP-42 signature validation on one side. The correct fix is to make the agent land on the **same host string** the owner uses.
**Steps to reproduce**
1. `just setup` then `just relay` (relay on `ws://localhost:3000`; seed script creates the 4 loopback community rows).
2. Launch the desktop app, create an identity, join/create the local community, and let the seeded channels (e.g. `#general`) appear.
3. In **Agents**, start a managed agent (e.g. the default **Fizz** persona, harness `buzz-agent`).
4. Observe the agent's log file under `~/.local/share/xyz.block.buzz.app.dev/agents/logs/__.log` — it shows:
`connected to relay at ws://127.0.0.1:3000` … `discovered 0 channel(s)` … `no channel subscriptions resolved — agent will sit idle`.
5. From the desktop UI (owner identity), mention `@Fizz` in `#general`. No reply is ever posted.
Check the running processes: the agent's `BUZZ_RELAY_URL` env is `ws://127.0.0.1:3000` while the desktop's is `ws://localhost:3000`.
**Expected behavior**
The agent resolves the same community as the owner (channels/members present), subscribes to them (`discovered N channel(s)` → `subscribed to channel …`), and replies to owner mentions.
**Version and platform**
- Buzz version: source at commit `19d57b0d46baa55814ac737041a36d0b405c9f64` (docs: one-click Railway deploy, #2733)
- OS: Debian 13 (trixie), Linux x86_64
**Logs / additional context**
Agent startup log (relevant lines, edited for brevity):
```
buzz-acp starting: relay=ws://127.0.0.1:3000 … subscribe=Mentions … model=auto
connected to relay
subscribed to membership notifications
owner resolved from BUZZ_AUTH_TAG: 5d0498…
relay observer enabled
discovered 0 channel(s)
WARN no channel subscriptions resolved — agent will sit idle
presence set to online
```
Note the relay is **healthy** and the owner desktop (on `ws://localhost:3000`) sees the channels fine — the bug is purely the host-community mismatch.
**Suggested fix**
Make the canonical loopback spelling consistent with what the relay will actually bind. Two viable options:
1. **Fold loopback to `localhost`** (not `127.0.0.1`) in `crates/buzz-core/src/relay.rs::normalize_relay_url` (one line: `url.set_host(Some("localhost"))` plus the docstring and the `loopback_spellings_have_one_identity` test assertion). The desktop owner already connects via `ws://localhost:3000`, so the agent then binds to the same community, and both NIP-98 (`u=http://localhost:3000/query`) and NIP-42 stay consistent. This is what I verified locally: after the change the agent logged `discovered 2 channel(s)` → `subscribed to channel …` and replied to a `@Fizz` mention.
2. Alternatively, normalize loopback equivalence in the relay's host→community resolution **and** mirror it everywhere NIP-98/NIP-42 expected URLs are built — higher blast radius.
Also worth considering: `scripts/seed-local-community.sh` could seed **one** canonical loopback community (or the seed's host map could be keyed on a canonical loopback form) so alternate spellings resolve to the same row; but option 1 above is the minimal, verified fix.
Contributor guide
Research direction
Start in crates/buzz-core/src/relay.rs at normalize_relay_url and read its loopback identity test, then inspect ManagedAgentRuntimeKey and start_managed_agent_process for how BUZZ_RELAY_URL is passed. Run the relay and managed-agent reproduction, and verify the agent uses the owner's community, discovers channels, and replies to a mention without changing NIP-98/NIP-42 behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, shell
- Domain
- backend, distributed-systems, networking
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100