Summary
A workflow send_message step that mentions agents (@Name) wakes them —
but agents configured respond_to: owner-only (the common default) never act
on the message. The agent wakes, replays the mention, silently drops it, and
goes back to sleep. No error is surfaced anywhere (the drop is a debug!).
Mechanism
Workflow messages are relay-signed with owner attribution by convention:
workflow_sink.rs signs with state.relay_keypair and puts the owner in the
first p tag; the relay's own effective_message_author()
(handlers/ingest.rs) resolves "if signer == relay, real author is the
actor/first-p tag" and honors it across deletion auth, counters, workflow
ownership, etc.
buzz-acp never implements this convention. Its inbound author gate
(lib.rs, author_allowed) uses the raw signer:
let author = buzz_event.event.pubkey.to_hex(); // the RELAY's key
So for owner-only (and allowlist) agents, the relay's pubkey is neither
the owner nor a sibling and the event is dropped — after the wake path
(p-tag gated, event_mentions_agent) has already fired. The two gates
disagree about what a workflow message is.
Why the harness can't easily fix it alone
Honoring actor/first-p attribution is only safe when the signer is
verifiably the relay — otherwise any member can forge an attribution tag and
impersonate the owner past an owner-only gate. The harness has no
trustworthy way to learn the relay's signing key today: the relay's NIP-11
document publishes pubkey: null.
Suggested fix
- Publish the relay's signing pubkey (NIP-11
pubkey, and/or inject it into
the harness env at launch, e.g. BUZZ_RELAY_PUBKEY, the way identity env
vars already flow).
- In
buzz-acp's author gate, when event.pubkey == relay_pubkey, resolve
the effective author via the same actor/first-p convention as
effective_message_author() and gate on that.
- Consider having the relay reject client-submitted events that carry an
actor tag, so attribution stays relay-only by construction.
- Upgrade the gate-drop log from
debug! to something owner-visible — a
woken-and-silent agent is otherwise indistinguishable from a dead one.
Repro
- Agent with
respond_to: owner-only, member of a channel.
- Workflow in that channel with a
send_message step whose text mentions
the agent (@AgentName), owned by the agent's owner.
- Trigger the workflow. The message posts, renders as the owner, carries the
agent's p tag; a sleeping remote agent wakes.
- The agent never responds. Harness log (debug level):
inbound author gate — dropping event with the relay's pubkey as author.
Workaround
Switch the agent to respond_to: allowlist and add the relay's signing
pubkey to the allowlist (obtainable from any workflow message's pubkey
field). Note this widens access: any member's workflow mentioning the agent
can then prompt it.
Related: #7065 (found while diagnosing the same workflow — the scheduler issue is why the workflow was being triggered manually in the first place).
Summary
A workflow
send_messagestep that mentions agents (@Name) wakes them —but agents configured
respond_to: owner-only(the common default) never acton the message. The agent wakes, replays the mention, silently drops it, and
goes back to sleep. No error is surfaced anywhere (the drop is a
debug!).Mechanism
Workflow messages are relay-signed with owner attribution by convention:
workflow_sink.rssigns withstate.relay_keypairand puts the owner in thefirst
ptag; the relay's owneffective_message_author()(
handlers/ingest.rs) resolves "if signer == relay, real author is theactor/first-ptag" and honors it across deletion auth, counters, workflowownership, etc.
buzz-acpnever implements this convention. Its inbound author gate(
lib.rs,author_allowed) uses the raw signer:So for
owner-only(andallowlist) agents, the relay's pubkey is neitherthe owner nor a sibling and the event is dropped — after the wake path
(p-tag gated,
event_mentions_agent) has already fired. The two gatesdisagree about what a workflow message is.
Why the harness can't easily fix it alone
Honoring
actor/first-pattribution is only safe when the signer isverifiably the relay — otherwise any member can forge an attribution tag and
impersonate the owner past an
owner-onlygate. The harness has notrustworthy way to learn the relay's signing key today: the relay's NIP-11
document publishes
pubkey: null.Suggested fix
pubkey, and/or inject it intothe harness env at launch, e.g.
BUZZ_RELAY_PUBKEY, the way identity envvars already flow).
buzz-acp's author gate, whenevent.pubkey == relay_pubkey, resolvethe effective author via the same
actor/first-pconvention aseffective_message_author()and gate on that.actortag, so attribution stays relay-only by construction.debug!to something owner-visible — awoken-and-silent agent is otherwise indistinguishable from a dead one.
Repro
respond_to: owner-only, member of a channel.send_messagestep whose text mentionsthe agent (
@AgentName), owned by the agent's owner.agent's
ptag; a sleeping remote agent wakes.inbound author gate — dropping eventwith the relay's pubkey as author.Workaround
Switch the agent to
respond_to: allowlistand add the relay's signingpubkey to the allowlist (obtainable from any workflow message's
pubkeyfield). Note this widens access: any member's workflow mentioning the agent
can then prompt it.
Related: #7065 (found while diagnosing the same workflow — the scheduler issue is why the workflow was being triggered manually in the first place).