Skip to content

fix(buzz): publish native agent directory metadata - #9

Merged
cmyk merged 2 commits into
fix/buzz-dynamic-channelsfrom
fix/buzz-directory-publication
Aug 13, 2026
Merged

cmyk merged 2 commits into
fix/buzz-dynamic-channelsfrom
fix/buzz-directory-publication

Conversation

@reinhold-ph

@reinhold-ph reinhold-ph commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Why

A native Hermes Buzz Gateway can be fully operational yet absent from Buzz's agent directory because the adapter never publishes kind 10100. That breaks the visible agent badge/owner metadata and makes an agent undiscoverable after it is removed from a channel.

This is the directory-publication half of #6. It is intentionally stacked on NousResearch#74823, which adds live joined-channel discovery.

Architecture

  • Generalize the existing dependency-free BIP-340 signer for canonical Nostr events.
  • Validate NIP-OA owner attestations structurally, cryptographically, and against the exact event kind/timestamp before attaching them.
  • Project a complete kind-10100 record from the adapter's effective authorization and authoritative observed groups.
  • Publish on the authenticated active WebSocket and require the matching positive relay ACK.
  • Reconcile additions and removals (kinds 44100/44101), close stale subscriptions, and republish only when the projection changes.
  • In poll mode, periodically reconcile memberships and retry failed publication, while suppressing unchanged projections before opening a socket.
  • Republish deliberately on reconnect; keep home_channel independent from inbound observation.

Public projection

The record includes:

  • name / display_name
  • agent_type: hermes-gateway
  • capabilities: [chat]
  • Buzz-compatible status
  • authorization-safe respond_to / respond_to_allowlist
  • current eligible channel names and IDs
  • channel_add_policy: owner_only
  • the configured public NIP-OA attestation when valid for the exact event

An empty effective authorization policy is represented as Buzz's supported empty allowlist rather than a broader or unknown wire value.

Safety

  • Adapter allowlists take precedence over broader global allow-all settings.
  • Config-only allow_all_users is not advertised when runtime authorization does not honor it.
  • Invalid, self-signed, wrong-agent, wrong-kind, or out-of-window NIP-OA tags are rejected before publication.
  • Authentication and ACK waits have absolute deadlines and bounded unrelated-frame queues.
  • Secrets/private keys are neither embedded nor logged.
  • Removed groups are unsubscribed and omitted; DMs and explicit channel configuration keep their existing semantics.

Tests

Independent local verification:

92 passed

Command covered:

  • Buzz adapter and WebSocket tests
  • config-driven authorization
  • multiplex profile authorization
  • startup authorization gate

Focused pre-commit rerun:

63 passed

Additional gates:

  • Ruff: passed
  • py_compile: passed
  • git diff --check: passed
  • added-line static security scan: no findings

The full tests/gateway suite completed with 4,447 passing, 23 skipped, and seven failures that reproduce on the unchanged base checkout (optional Discord/WeCom dependency state plus an existing session-home fixture issue); none touch the changed Buzz files.

Live evidence

Before this patch, Habeler had no kind-10100 event and disappeared from add-member discovery after channel removal. Publishing the exact projection manually restored:

  • agent classification and badge
  • abbreviated pubkey and owner display
  • Agent type → hermes-gateway
  • Capabilities → chat
  • rediscovery and successful re-add

This patch turns that proven recovery into the native adapter lifecycle.

Dependency and rollout

Tracking

Live pilot acceptance

Both Linux and macOS cumulative-runtime pilots passed. See the PR comment for exact sanitized evidence.

Publish and reconcile signed kind-10100 directory records from the native Buzz gateway, including bounded ACK handling, authorization-safe policy projection, NIP-OA condition verification, and channel-removal refresh.
@reinhold-ph

Copy link
Copy Markdown
Collaborator Author

Live pilot acceptance — 2026-08-13

Both cumulative-runtime pilots passed against the Peakhunter relay and Buzz Desktop consumer.

Reinhold (Linux Gateway)

  • Cumulative candidate: a62561ce5e20fdd2d756247d8c5a5ad297b7a671, applied one commit above the exact production baseline 97f027a7eb9763c9889584cf4995447dc2e9c116.
  • 178 focused Buzz/config/authz tests passed on the cumulative candidate; Ruff and byte-compilation passed.
  • Gateway restarted under an external rollback controller and remained healthy.
  • Authenticated relay readback returned Reinhold’s self-authored kind-10100 event d4b2aa3472278e4f52c8d8cbf42a4cdec01fde57fa370a260818a763573c108e for the expected identity.
  • Independent Buzz Desktop UI observation confirmed Agent type: hermes-gateway and Capabilities: chat.

Habeler (macOS Gateway)

  • Exact same cumulative candidate SHA a62561ce5e20fdd2d756247d8c5a5ad297b7a671, one commit above the same audited baseline.
  • 149 focused Buzz adapter/WebSocket tests passed on macOS.
  • Independent controller completed with rollback armed and verified the candidate launchd runtime.
  • Authenticated kind-10100 publication/readback passed, including event signature, NIP-OA owner binding, channel metadata, and effective allowlist.
  • Buzz Desktop rendered the expected agent metadata.
  • A normal structural mention activated Habeler and produced a Habeler-signed response.

Scope boundary

Inline-code addressed-name text still activates Hermes through the existing raw-content mention predicate. That is the separately tracked #8 and is not changed by this directory-publication PR.

The pilots used cumulative candidates solely to preserve production-only fixes. The upstream review branch remains the focused one-commit change stacked on NousResearch#74823.

@reinhold-ph

Copy link
Copy Markdown
Collaborator Author

CI follow-up: Slice 6 exposed an upstream test-fixture ordering bug unrelated to the Buzz implementation. test_allowed_for_nous_anthropic_messages constructed a Nous agent with model="", then assigned Claude only after initialization; endpoint metadata could therefore trip the 64K floor at 32K before the test reached its recovery assertion.

Separate commit 9319e7860 makes the fixture initialize with the Claude model it actually tests and mocks the Anthropic constructor alongside the existing OpenAI mock. No production code changed. Local verification: tests/run_agent/test_primary_runtime_restore.py — 24 passed; Ruff, byte-compile, and git diff --check passed.

@reinhold-ph

Copy link
Copy Markdown
Collaborator Author

✅ CI follow-up resolved. Run 31737340867 completed successfully at head 9319e7860a847ada95d2a120a67cb78f20dc94c3: all eight Python slices passed (including Slice 6), Desktop E2E passed, docs passed, lints passed, supply-chain/OSV checks passed, and All required checks pass is green. The PR is currently reported MERGEABLE / CLEAN.

@cmyk
cmyk merged this pull request into fix/buzz-dynamic-channels Aug 13, 2026
37 checks passed
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.

2 participants