Skip to content

Feature: supported way for an owner to attest/adopt an existing external agent pubkey (owner-only rejects same-owner agents) #6997

Description

@fieldsresearch-creator

Summary

There is no supported way for an owner to issue a NIP-OA owner attestation for an
existing, externally created agent keypair. Self-hosted deployments that run
buzz-acp agents from their own Nostr keys therefore cannot use
--respond-to owner-only without losing all agent-to-agent messaging: the owner is
admitted, but same-owner agents are not dispatched, because the relay cannot resolve
a verifiable owner attestation for those agents.

The only supported issuance paths (buzz agents draft-create / draft-update) open a
Buzz Desktop form for a Desktop-managed agent, target agents by display name
only
, and offer no way to adopt an externally created key.

Environment

  • Buzz Desktop 0.5.18
  • Relay image ghcr.io/block/buzz:sha-417eea2
  • Relay source revision 417eea2230c1864e8c77f6440dbcfa109bfb63f6
  • Closed relay: BUZZ_REQUIRE_RELAY_MEMBERSHIP=true, BUZZ_ALLOW_NIP_OA_AUTH=true
  • Four buzz-acp agents launched from externally generated Nostr keypairs by
    OS-managed background tasks; the agents are direct relay members
  • All agents configured with --agent-owner <owner-pubkey> --respond-to owner-only --allowed-respond-to owner-only
  • No --auth-tag flag and no BUZZ_AUTH_TAG environment variable configured on any
    agent — no supported attestation-issuance path was configured or used

Current behavior

  1. Each agent publishes a normal kind:0 profile. buzz users get --name <Agent>
    resolves it correctly (display_name, about, pubkey).
  2. buzz users get --name <Agent> --owner me returns [] for every agent — the
    relay resolves no owner→agent association.
  3. Owner-originated mentions are admitted and answered normally.
  4. Same-owner agent-to-agent mentions are accepted and stored by the relay but
    never dispatch a turn on the target.

This is consistent with crates/buzz-acp/src/lib.rs, where RespondTo::OwnerOnly
resolves through is_owner_or_sibling()check_sibling_via_profile(). That check
requires a four-element tag on the author's kind:0 profile:

["auth", <owner_pubkey>, <conditions>, <signature>]

verified via nip_oa::verify_auth_tag. If the check cannot resolve and verify such a
tag, it returns false, the negative result is cached for the process lifetime, and
the message is dropped with no log entry at the default log level.

To be precise about what was and was not observed: the raw kind:0 tag arrays were not
directly inspected. What was established is that the relay cannot resolve a verifiable
owner attestation for these agents' profiles, and that no supported
attestation-issuance path was configured or used.

Controlled A/B against one target, same channel, same explicit-pubkey mention,
~2 minutes apart:

Author Relay accepted Turn dispatched Response
Another agent, same configured owner yes no none
Owner yes yes correct, ~3 s

Expected behavior

An owner should be able to bind an existing external agent pubkey to their owner
identity through a supported, owner-signed path, so that owner-scoped lookup resolves
the agent and same-owner sibling admission works under --respond-to owner-only
without rotating the agent key or creating a duplicate identity.

Reproduction

Using placeholder keys OWNER_PUBKEY and AGENT_PUBKEY (64-hex):

  1. Generate a Nostr keypair outside Buzz Desktop and run buzz-acp with it.
  2. Connect to a closed relay (require_relay_membership=true,
    allow_nip_oa_auth=true); the agent publishes a normal kind:0 profile.
  3. Start it with --agent-owner OWNER_PUBKEY --respond-to owner-only, with no
    --auth-tag and no BUZZ_AUTH_TAG set.
  4. buzz users get --name <Agent> → resolves the profile. ✅
  5. buzz users get --name <Agent> --owner me[]. ❌
  6. Mention the agent from OWNER_PUBKEY → turn dispatched, agent replies. ✅
  7. Mention it from a second agent sharing the same configured owner → the relay
    accepts and stores the event; no turn, no reply. ❌
  8. buzz agents draft-update --help → only --agent-name; no pubkey selector.
  9. The externally created agent does not appear in Desktop's managed-agent tab
    (see [Bug] Agents created outside the current app-managed store do not appear in the Agents tab #3054).
  10. No installed CLI command issues the missing attestation.

Why existing commands do not solve it

Command Why it does not help
buzz agents draft-update Targets by --agent-name only; no pubkey option. Documented as editing "the personal agent", i.e. a Desktop-managed agent; externally created agents are not in that store
buzz agents draft-create Creates a new keypair; would rotate identities and break historical attribution
buzz users set-profile Options are --name, --avatar, --about, --nip05 — cannot write event tags, so cannot add an auth tag
--auth-tag / BUZZ_AUTH_TAG Documented as "Injected into every signed event" — consumes an attestation, does not issue one
buzz agents archive When target != signer it "fetches the target's kind:0 and attaches its owner-auth tag", so it also presupposes an attestation. --admin is a relay-admin bypass, not a normal-path solution

Display-name-only targeting is additionally unsafe wherever duplicate display names
exist (see #3639, #5667): a name can resolve to more than one pubkey, making
--agent-name ambiguous and causing @Name mentions to be rejected as ambiguous.

Security and identity requirements

Any implementation should:

  • target only by explicit 64-hex public key; never mutate by display name alone
  • authenticate the owner and produce the signature through an existing supported
    owner-signing mechanism (Desktop / OS keyring)
  • never accept or expose an owner or agent private key
  • issue and cryptographically verify the attestation before publication
  • reject self-attestation
  • reject malformed conditions
  • preserve the existing agent key — never rotate it
  • preserve existing profile metadata by default
  • never silently create a duplicate identity
  • be idempotent when repeated
  • provide revocation or replacement
  • create an auditable owner→agent binding record
  • require no --admin bypass for normal use
  • keep authorship and owner provenance clearly distinct

Proposed interfaces

A. CLI issuance

buzz agents attest --target-pubkey <64-hex> [--conditions <nip-oa-conditions>] [--channel <id>]

B. Adoption of an existing key

buzz agents adopt --target-pubkey <64-hex>
# or
buzz agents draft-update --target-pubkey <64-hex>

Either interface would close the issuance/adoption gap. On closed relays matching
#4223/#6072, the separate owner-materialization defect must also be fixed before
owner-scoped lookup and sibling admission will work.

Related issues

Impact

Self-hosted deployments running externally managed buzz-acp agents must choose
between two bad options:

  • --respond-to owner-only — closes public trigger exposure but breaks all
    agent-to-agent delegation
    , because no agent can be admitted as a sibling; or
  • --respond-to anyone — preserves delegation but allows any relay author to
    trigger agents that may hold shell and filesystem authority.

There is no supported configuration providing both. The only workaround — rebuilding
the fleet on Desktop-created identities — rotates every agent key, breaks historical
attribution, and risks adding further duplicate display names.

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