Skip to content

feat(desktop): show external relay agents in the Agents view - #3803

Open
suhaskashyaps wants to merge 3 commits into
block:mainfrom
suhaskashyaps:agents-view-relay-agents
Open

feat(desktop): show external relay agents in the Agents view#3803
suhaskashyaps wants to merge 3 commits into
block:mainfrom
suhaskashyaps:agents-view-relay-agents

Conversation

@suhaskashyaps

@suhaskashyaps suhaskashyaps commented Jul 30, 2026

Copy link
Copy Markdown

Problem

Agents that run behind an external buzz-acp harness (e.g. on a VPS or server) announce themselves on the relay via kind:10100 agent-profile events. They participate fully in DMs, channels, and mention autocomplete, but the desktop Agents view renders only desktop-managed agents, so externally hosted agents are invisible in the one place a user goes to see 'my agents'. There is no way to publish anything to the relay that makes them appear there today.

Change

Adds a read-only Relay agents section to the Agents view, fed by the existing useRelayAgentsQuery (kind:10100 directory) and deduplicated against the managed-agents list. Cards show the relay profile name/avatar and presence status, and open the agent's profile panel.

  • New: desktop/src/features/agents/ui/RelayAgentsSection.tsx
  • Wired into AgentsView below the unified managed-agents section
  • No Rust changes; tsc --noEmit and biome check pass

Non-goals: no management of external agents

This section is display-only by design. The desktop cannot manage a relay agent: no start/stop, no restart, no model/persona/env editing, no deletion. Those operations only exist for desktop-managed agents because the desktop owns their process and their record in the local managed-agents store. An external harness agent's lifecycle and configuration live wherever the harness runs (systemd unit, container, another machine), which the desktop can neither see nor control; the relay only carries the agent's self-published kind:10100 profile. The cards therefore intentionally omit every management affordance and only open the profile panel.

If remote management is ever wanted, it would need a separate control-plane design (e.g. owner-signed control events the harness subscribes to) and is out of scope here.

Testing

Verified against a live relay with two external buzz-acp harness agents running different ACP runtimes: both appear with avatar and Online badge, collapse/expand works, and managed agents are not duplicated.

🤖 Generated with Claude Code

suhaskashyaps and others added 3 commits July 27, 2026 10:21
…ample

Setting BUZZ_CORS_ORIGINS to only the public origin blocks the desktop
app's HTTP API calls (invites, moderation) with a CORS network error,
while WebSocket traffic keeps working. The webview origins that must be
allowlisted are tauri://localhost (macOS/Linux) and http://tauri.localhost
(Windows, per media_proxy.rs and Tauri v2's http default). The relay code
documents this in a doc comment (config.rs), but .env.example, the file
operators actually copy, had no mention of the variable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Device pairing was failing with "WebSocket connection failed: HTTP error:
404 Not Found". The compose bundle never ran the pairing sidecar — upstream
ships it only in the Helm chart (deploy/charts/buzz/templates/pairing-relay.yaml).

An unpaired device holds only an ephemeral keypair, so it is rejected at
NIP-42 AUTH time by enforce_relay_membership (crates/buzz-relay/src/api/mod.rs)
on a membership-enforcing relay. The handshake therefore has to run on a
separate unauthenticated relay. Clients find it via the NIP-11
`pairing_relay_url` field; with BUZZ_PAIRING_RELAY_URL unset, the desktop
client instead infers NIP-43 support and falls back to <relay>/pair
(desktop/src-tauri/src/commands/pairing.rs), a path nothing served — hence
the 404.

Adds a `pairing` service on the existing image. Two notes for future edits:

- Uses `entrypoint:`, not `command:`. The image ENTRYPOINT is buzz-relay, so
  `command:` would append args to the wrong binary. The Helm chart's
  `command:` works only because Kubernetes overrides ENTRYPOINT.
- No env_file. The sidecar needs no DB, Redis, S3, or relay private key, so
  it is not handed the secrets in .env.

The reverse proxy must route only /pair to it (exact-match location), since
the sidecar is unauthenticated by design. It self-limits: kind 24134 only,
no persistence, 128 conns, 4 KiB frames, 120s TTL.

Also re-applies the 127.0.0.1 relay port binding, which had drifted back to
0.0.0.0 and exposed port 3300 off-box, bypassing TLS and nginx.

Deployed and verified on buzz.axonclaw.cloud: /pair returns 101, / still
returns 101, /pairing stays 404.

Co-Authored-By: Claude <noreply@anthropic.com>
The Agents view only rendered desktop-managed agents, so agents running
behind an external buzz-acp harness (announced via kind:10100) were
invisible outside DMs and channel member lists. Add a read-only 'Relay
agents' section listing kind:10100 agents not already managed by this
desktop. Cards show the relay profile name/avatar and presence status,
and open the agent's profile panel; lifecycle stays wherever the harness
runs, so there are no start/stop controls.

Signed-off-by: Suhas Kashyap <suhas.s.kashyap@gmail.com>
@suhaskashyaps
suhaskashyaps requested a review from a team as a code owner July 30, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant