Skip to content

[Bug] Desktop 0.4.23 spawns managed agents on ws://127.0.0.1:3000 while the community uses ws://localhost:3000 - agents silently stop responding #2444

Description

@lewiswang0516

Summary

On desktop v0.4.23 (installed DMG, macOS), managed agents are spawned with BUZZ_RELAY_URL=ws://127.0.0.1:3000 even though the active community is configured as ws://localhost:3000. Because the relay derives the community boundary from the Host, localhost:3000 and 127.0.0.1:3000 are two fully isolated communities. The result: the UI posts messages into the localhost:3000 community while every agent sits in an empty 127.0.0.1:3000 community, so agents never see any message and never reply. There is no error anywhere - the only hint is a low-key log line in the agent log.

Environment

  • Desktop app: v0.4.23, installed from DMG (GUI launch), macOS (Darwin 25.5)
  • Relay: local dev relay at port 3000 (just relay)
  • Community config in the app (localStorage buzz-communities): relayUrl: "ws://localhost:3000"
  • No BUZZ_RELAY_URL in the app process environment, no launchctl env

Steps to reproduce

  1. Run a local relay on port 3000.
  2. In the desktop app, use a community configured as ws://localhost:3000, create channels, add managed agents to a channel.
  3. Install/launch desktop v0.4.23 from DMG and let it restore the managed agents.
  4. Mention an agent in the channel.

What happens

  • The user's messages land in the localhost:3000 community (verified in the relay DB: events.community_id maps to the localhost:3000 row in communities).
  • Every spawned buzz-acp child has BUZZ_RELAY_URL=ws://127.0.0.1:3000 (verified via ps eww). Their membership discovery (kind 39002 query) runs against the 127.0.0.1:3000 community, which is empty, so each agent logs:
INFO buzz_acp: discovered 0 channel(s)
WARN buzz_acp: no channel subscriptions resolved - agent will sit idle
  • Agents show as online (presence is set) but never respond to anything.

Notes on the source of the rewrite

  • The agent records in managed-agents.json have an empty relay_url, so the spawn falls back to the workspace relay (effective_agent_relay_url in desktop/src-tauri/src/relay.rs).
  • On current main, the fallback chain (workspace override from apply_workspace -> env -> build-time -> DEFAULT_RELAY_WS_URL) is all ws://localhost:3000, and the frontend passes the stored community relayUrl unchanged. I could not find the localhost -> 127.0.0.1 rewrite on main, so it seems specific to the 0.4.23 build (repeated agent restarts always produce 127.0.0.1, so it is not a launch-order race).
  • An earlier build on the same machine spawned agents with ws://localhost:3000 (visible in older agent logs), so this looks like a regression introduced in or shortly before 0.4.23.

Why this is nasty to debug

  1. Nothing fails loudly. The agent connects, authenticates, sets presence to online, and then silently subscribes to nothing.
  2. localhost vs 127.0.0.1 is invisible in the UI. The user sees online agents in the member list that simply never answer.
  3. Setting BUZZ_RELAY_URL as a per-agent env var is rejected (it is on RESERVED_ENV_KEYS, which is reasonable), so the only workarounds are the per-agent Relay URL field in the Advanced section, or changing the community relay URL - the latter silently forks the community and hides all previous history.

Suggested fixes

  1. Find and remove the localhost -> 127.0.0.1 rewrite in the agent spawn path so the child relay URL always matches the workspace relay the UI uses.
  2. Consider normalizing loopback hosts (localhost, 127.0.0.1, [::1]) to one canonical community key on the relay side, since they are the same machine and the split is never what a local user wants.
  3. Make the idle state visible: when an agent discovers 0 channels, surface a warning in the desktop UI (the log line is easy to miss), since an online-but-deaf agent looks identical to a working one.

Activity

  1. mwherman2000 commented on Jul 23, 2026

    @mwherman2000

    SIDE NOTE: With some HTTP clients, localhost resolves to an IPv6 address and 127.0.0.1 always resolves to an IPv4 address and some servers only work with IPv4 addresses. I found this out when configuring a local ollama server ...might be applicable here?

  2. lewiswang0516 commented on Jul 23, 2026

    @lewiswang0516
    Author

    Yeah, that makes sense. But within different communities, agents don't respond, or event do not throw errors. This can become confusing.

  3. JHSeo-git commented on Jul 29, 2026

    @JHSeo-git

    Independently hit this and can confirm it reproduces on current main (22be8bb), not just the 0.4.23 DMG build — so the rewrite you couldn't find on main is there, just not in the fallback chain: every spawn path passes ManagedAgentRuntimeKey.relay_url (the canonical form produced by buzz_core::relay::normalize_relay_url, which folds loopback to 127.0.0.1) to the child as BUZZ_RELAY_URL.

    Reproduced from a completely fresh environment (wiped DB volumes + fresh desktop dev state, just dev from source):

    • Fresh onboarding joined the community as ws://localhost:3000; the Welcome channel, all three starter-team agent memberships (role bot), and the member-added notifications (kind 44100, correctly #p-tagged) all landed under the localhost:3000 row in communities — verified in the relay DB.
    • All three harnesses logged connected to relay at ws://127.0.0.1:3000 → discovered 0 channel(s) → no channel subscriptions resolved — agent will sit idle, and the member list showed the agents stuck on "Waking" indefinitely. Zero requests from the agents ever reached the localhost:3000 community.
    • Rejoining the community as ws://127.0.0.1:3000 (so the configured spelling equals the canonical one) makes everything work — agents discover the Welcome channel and answer mentions — which pins the tenant split as the whole story.

    The canonical value flows in through the spawn call sites (start_pair, launch restore, ensure-running, and the reconcile fan-out all pass key.relay_url), plus probe_agent_relay_access, which probes the canonical HTTP base. I've opened #3484 with the passthrough fix and regression tests — same direction as #2446, rebased on current main.

  4. jbold commented on Aug 1, 2026

    @jbold

    Independent verification on Linux — #3484 fixes this for me.

    Prior reports were macOS (0.4.23 DMG) and a main repro; adding a Linux data point plus one symptom I didn't see described in #2444.

    Symptom was worse than "agents don't respond": onboarding never completes.

    On a fresh install the app hangs permanently on the final onboarding step, "meet your starter team". There is no error, no failed request, and no timeout — the step simply never resolves, because it waits on starter-team agents that are connecting to a different community. The state is also persistent: quitting and relaunching returns straight to the frozen step, so the app is unusable until localStorage is cleared manually. This thread describes agents going silent in an established workspace; this is the same root cause blocking first-run entirely.

    Environment

    • Buzz: built from source, main @ 19d57b0, just relay + just desktop-standalone
    • Also reproduced with the released v0.5.3 .deb (sha256 61b3471776c4…)
    • Host: Fedora Silverblue 43, Wayland, NVIDIA
    • Build/run: Ubuntu 24.04 distrobox, WebKitGTK 2.52.3
    • Relay: local, Postgres/Redis/MinIO via Compose

    Reproduction

    1. just relay with RELAY_URL=ws://localhost:3000
    2. just fresh=1 desktop-standalone, join the community as ws://localhost:3000
    3. Complete onboarding

    Result: hangs at "meet your starter team" indefinitely.

    Evidence it is the loopback tenant split

    The dev database seeds a community row per loopback spelling, which makes the split directly observable. Before the patch, everything the UI wrote landed under localhost:3000 and no bot-role membership was ever created:

          host      |       name       | role  | members
    ----------------+------------------+-------+---------
     localhost:3000 | Welcome          | owner |       1
     localhost:3000 | general          | owner |       1
     localhost:3000 | welcome-everyone | owner |       1
    

    After applying #3484 (applies cleanly to 19d57b0) and joining as ws://127.0.0.1:3000:

          host      |       name       | role  | members
    ----------------+------------------+-------+---------
     127.0.0.1:3000 | Welcome          | owner |       1
     127.0.0.1:3000 | Welcome          | bot   |       3
     127.0.0.1:3000 | general          | owner |       1
     127.0.0.1:3000 | welcome-everyone | owner |       1
    

    Onboarding completes and the starter team appears.

    Why this took a long time to diagnose

    Every check said the stack was healthy. The relay passed /_readiness, served a valid NIP-11 document, accepted a hand-signed NIP-42 AUTH over WebSocket (["OK",<id>,true,""]), and buzz-cli could list channels and post messages as a brand-new identity. The desktop app authenticated and polled POST /query → 200 continuously throughout. Nothing in the relay logs was above INFO at any RUST_LOG level.

    The tenancy mismatch has no error path anywhere, so the only visible signal is a UI step that never finishes.

    One measurable symptom, if it helps others identify this

    While stuck, WebKitWebProcess sits at a sustained 100% of one core (405 jiffies / 4s). After this patch, on the same machine and the same WebKitGTK build, it drops to ~1%. So the frontend is busy-waiting rather than idle-waiting while the starter team never arrives — a quick ps/top check distinguishes this bug from a merely slow start.

    Worth stating explicitly so nobody chases it as a rendering bug: it is not WebKitGTK. I initially suspected #3654 (NVIDIA + WEBKIT_DISABLE_DMABUF_RENDERER) and measured both workarounds from that issue — WEBKIT_DMABUF_RENDERER_FORCE_SHM=1 and WEBKIT_SKIA_ENABLE_CPU_RENDERING=1 — with no effect (100% / 111% / 101%). The spin resolves via the Rust-side patch in #3484, which touches no rendering code.

    One adjacent note on relay URL entry

    For a plaintext local relay you must type the scheme explicitly. A scheme-less entry (localhost:3000) is normalized to wss:// — intentional, and the code says so ("a scheme-less host is assumed to be a secure relay") — which then fails TLS against a plaintext port and surfaces as:

    join policy request failed: error sending request for url (https://localhost:3000/api/join-policy)
    

    relayProbe.ts maps an explicit http:// to ws:// correctly, so this only bites scheme-less input. Not a bug, but the error message never mentions that the scheme was defaulted, which cost me a while. Possibly worth a clearer message for loopback hosts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions