Skip to content

Agents name an audience; agent-to-agent messages read as quiet lines - #866

Closed
baxen wants to merge 32 commits into
baxen/agent-siblingsfrom
baxen/agent-audience
Closed

baxen wants to merge 32 commits into
baxen/agent-siblingsfrom
baxen/agent-audience

Conversation

@baxen

@baxen baxen commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Agents had no way to mark a message as coordination between agents, so people had to read every hand-off and status ping at full weight. Agents could also nest replies under any message, which buried the conversation.

Change

  • MCP send: requires audience, either everyone or agents, so an agent always chooses one instead of falling back to everyone. agents writes ["audience","agents"] on the kind 9 message; everyone writes no tag. The schema description is baxen's: "agents: only other agents need this (delegating, asking or answering an agent)". The shared MCP is the only place this lives; neither plugin has its own audience code.
  • Shared Buzz prompt: src/buzz-mcp/prompt.md holds the Posting Conventions, and both plugins include it with their own harness text. Claude puts it after its base prompt; Codex puts it after its own intro. It says:
    • Reply in the thread at its top level, which is what send does by default. DMs reply at the top level.
    • Talking to agents and low-level detail always go to agents.
    • everyone posts stay brief: one saying what's about to happen for long work, then one when done.
  • Flat replies: a reply to any message in a thread goes to the thread's root, so agents post top-level or in a thread, never deeper.
  • Plugin drift removed: Codex no longer rewrites send's reply before calling the tool. Both plugins pass their conversation's context and the tool decides.
    • Behaviour change: Codex replies in DMs are now top-level, as Claude's already were, instead of starting a thread under the DM message.
    • Both plugins' failure notices reply flat to the thread root.
    • The Claude base prompt drops its allowance for nested agent-only subthreads. Its "narrate as you go" line now points narration at agents, and milestones at everyone, to match the shared prompt. Codex's own threading sentence moved into the shared prompt.
  • Quiet rows: a message tagged agents renders as one line in time order: [author avatar] → [avatar of each leading @mention] first paragraph.
    • The leading mentions become the line's recipients and are removed from its text.
    • Clicking the line opens the whole message in place, at the line's caption size and colour, starting where the preview was and without the leading mentions. The whole entry stays highlighted while open. A click anywhere in it folds it back, except on links and controls or when selecting text.
    • A message that opens with prose, or is nothing but a mention, shows as written. A missing or unknown audience renders as before.
  • Notifications: desktop never alerts for an agents message, even one that mentions the viewer. IncomingMessage now carries the audience. This needed a 2-line edit to FOUNDATION session.ts, approved by baxen.
  • Not changed: unread counts (server-side work is in flight), mobile push, relay enforcement.

Known limits

  • Recipient avatars come from the same bound mentions the message body uses: exact profile or agent-library names. A leading @name in the wrong case, or one whose profile hasn't loaded, shows as plain text, with no recipient avatar.
  • The collapsed line doesn't show reply counts, reactions or retry. Those appear once it's opened.
  • The preview is the first paragraph as raw text, the same as link previews.
  • audience is self-declared, so any sender can quiet its own desktop alert. Unread counts and the sidebar still show the message.

Validation

  • At f6a1dd5 the full vitest run passed (576 files, 8223 tests). At 5f29996, tsc --noEmit is clean and these suites pass: src/buzz-mcp, src/bundled/claude-code, src/bundled/codex, src/features/messages and src/features/notifications.
  • New tests:
    • MCP: the agents tag is written, and a missing or unknown audience is rejected. A reply to a nested message goes to the thread root.
    • Both plugins' prompts include the shared Buzz prompt.
    • MessageRow: the quiet line, its recipients, and opening it then clicking its body to fold it back. Prose-first and mention-only messages are kept as written.
    • Address helper: seam shifting, and line breaks kept after a leading mention.
    • Notifications: an agents message that mentions the viewer doesn't alert, and the next plain message does. I confirmed this test fails without the change.
  • I checked rendering in headless Chromium against the prototype's sample conversation, collapsed and open, in light and dark at wide and narrow widths. There I checked that a click on the open body folds it and that a drag-selection doesn't.
  • Pre-push hooks pass on 5f29996: types and unit tests, design system, rust-clippy, org check.
  • An independent agent review found a timestamp regression, now fixed. Its other findings are listed under known limits.
  • Deferred: the native app run, the live agent-to-agent flow, and the human test.

🤖 Generated with Claude Code

baxen and others added 29 commits October 11, 2026 10:06
Store optional picture and about fields on Agents2 identities and publish them with the name. Track accepted metadata so updates and clears publish even without a rename. Preserve compatibility with older rows and publication receipts.

Implemented with goose AI assistance. Human acceptance: green confirmed working.

Signed-off-by: Bradley Axen <baxen@squareup.com>
Agents2 can now take over an identity that the harness controller or
old Buzz (installed or dev) saved on this machine. It keeps the key,
name and picture, and leaves the instructions and settings behind.
Neither old store is written.

- port.rs lists both stores as one flat list, one entry per key. The
  harness copy wins because its key is already in this app's store.
  It also re-reads an identity and its key at take-over time.
- AppAgents::adopt is prepare with an existing key. When a harness
  agent saved for the same community already holds the key under the
  same credential ID, commit shares that key and never adds or
  withdraws it. Without this, a failed add would have deleted the
  harness copy.
- An adopted agent keeps the profile its community already has.
  Without one, it publishes the name and picture it brought. If the
  read fails, it overwrites nothing until the agent is renamed.
  Agents2 profiles gain an optional picture.
- Adds a "Bring over" side panel on the Agents2 page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
fixup! [agents2-adopt] bring over agents from earlier agent systems

Check an adopted key's community profile under its publication turn, on
the first publication rather than right after bringing it over, so a
sync meanwhile cannot replace it and a failed read is retried. Refuse a
key that is already here or still being removed, never delete a
credential an adopted key may share, read old Buzz's inline keys, and
wait out a busy credential store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Adapt adoption to the metadata layer so accepted pictures and descriptions are recorded with the name.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
…d agent-mention popups

Delete the bundled Agents and Channel templates plugins and every v1
mention popup: wake notices, owner-review requests, the mention attach
path in agent control, and snapshot previews. Adding an agent to a
channel no longer starts it.

Settings > Agents keeps only "Remember mentioned agents" and the saved
activity archive. The shell's collapsible-sidebar, retry and icon
special cases move from the v1 Agents page to Agents2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Plugins now provide profile content. With no profile panel registered,
avatars and names render inert, and mention chips keep their identity
attributes without a button so copy and paste still round-trips them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
…g and security

With the v1 Agents page, Profiles and Channel templates gone, the services
behind them have no consumer. Delete v1 AgentControl and its native bridge,
AgentSecurity, agent snapshots and snapshot sharing, team bundles and
import, the community catalog, the agent-management request lease, and the
channel kit's team payload/text write paths.

Names, mentions and New message now read a LocalAgents snapshot published
by Agents2 (the viewer's own live identities) instead of v1 native control,
so Agents2 agents stay "managed" for DMs and mention invitations. The
plugin author API no longer exports the AgentControl or AgentSecurity
types. Docs drop agent-control.md and agent-security.md and describe the
remaining agent surfaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Templates & teams was the only TemplateProviders contributor, so with it
gone the extension point only rendered empty slots and "templates are off"
notes. Remove ctx.channelTemplates and its editor, group-default and
save-as slots from Create channel, the channel menu, Channel settings and
Personal groups. Create now sends name, privacy, duration and destination
group only.

The channel kit model and session setup stay: groups and Canvas depend on
them, and frozen setup receipts saved by earlier builds still retry with
their original agents and Canvas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
…sion point

fixup! [remove-agents-v1-templates] Remove the channel template extension point

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Nothing in the frontend drives the v1 agent controller any more. Delete
AgentHost and every agent_control_* command, agent_security, native model
discovery (agent/codex/goose/pi models), harness installers and managed
npm, media_snapshot_read, the kit team-catalog reader and the agent
supervisor dispatch, with their build.rs, capability and permission-test
entries, plus the orphaned authorize-agent route in native-api and the
dev broker. Drop the now-unused buzz-agent dependency.

Agents2's app_agent_* commands are unchanged; app_agents.rs now owns the
NIP-98 header helper it borrowed from the v1 module. Quit, update restart
and sign-out no longer wait on a native agent host: Agents2 agents are
plugin host processes that stop when Buzz exits. Sign-out still deletes
keys listed in the v1 agent registry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Erase kept only the earlier agent registry: "keep agents" wiped
agents2/identities.json, orphaning its keys, and "remove agents" deleted
only keys listed in the earlier registry. Both registries are now kept,
and removing agents deletes the keys of both.

A rename republished an adopted agent's profile with only its name, bot
flag and picture, dropping about, banner, NIP-05 and the rest. It now
reads the community's current profile and changes only the name and bot
flag, adding the picture only where there is none.

The Agents2 grid, peek and build view now show the picture an agent
brought over instead of only its initials.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Stop building and shipping the unused v1 agent runtime. Keep desktop launch,
application signing, installer verification and AppImage launch repairs.

Trim the controller crate to Agents2 identities, credentials, profile signing
and legacy import. Preserve legacy key deletion with bounded registry reads,
identity validation and controller locking, without retaining the v1 runtime.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Import authored descriptions and retained pictures from legacy and harness records. Publish ordinary stored metadata and track accepted picture/about changes without a persistent adopted flag or community-profile preservation path. Retain transient shared-key custody protections and compatibility with saved adoption flags.

Implemented with goose AI assistance. Validated on tail with 46 controller unit tests, 5 integration tests, 4 native host tests, formatting and diff checks. Live tail acceptance remains deferred.

Signed-off-by: Bradley Axen <baxen@squareup.com>
Agents2 had no way to set a picture, and its grid, peek and build view
passed raw relay media URLs straight to <img>, which community media
refuses without the media proxy, so even agents brought over with a
picture showed initials.

AppAgents::set_picture (app_agent_set_picture) saves or clears an HTTPS
picture; Agents2.save takes { picture } and republishes the profile
through the existing refresh. The build view's identity rail uses the
shared AvatarEditor (uploads as the owner, like your own profile), and
every agent portrait goes through useAvatarPreview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
…agents

Removing the Profiles plugin left nothing registering the profile panel,
so mentions and avatars of people and agents no longer opened anything.

Revert that removal, then drop only what served v1 agents: Runtime,
Instances, harness log, start/stop/restart, archive, Memories, Add to
channel, exact-instance targets and the kind-10100 Agent type and
Capabilities rows. Human profiles render as before. Agents2 agents keep
their type's tabs and Delete, and Message for an agent follows the
Agents2 LocalAgents snapshot. Browser fixtures use LocalAgents instead
of AgentControl; v1-only cases are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Keep the plugin default and persistence assertions without a single-element loop, and remove the duplicate profile field introduced by rebasing overlapping metadata changes. Authored by the goose AI agent.

Signed-off-by: goose <goose@users.noreply.github.com>
Until Agents2 agents show as typing, the host reacts to a mention as the
agent with 👀 and 💬 when its run starts, and deletes both once the run and
the work it handed off have settled (at most the longest run allowed).

Plugins return from `run` early and finish their turns in the background,
so `Delivery.workingUntil(done)` lets them say when that work settles.
Claude Code and Codex now call it. The reactions live in
working-reactions.ts and its one call in the service, so they can be
deleted once typing indicators ship; `workingUntil` stays for those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
The relay rejects a deletion with more than one target, so the single
deletion naming both reactions was refused and they were never removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
STOPGAP until agents' typing pulses reach the relay: the host shows a
mention's agent typing in the mention's thread on this device only, for as
long as the run counts as working. Every 3 s it feeds a pulse into the
session's existing typing store through a new `typing.local`, so expiry and
the agent's reply ending it work as they do for live pulses.

Every piece is tagged STOPGAP(agent-local-typing); grep for it and delete
what it marks to retire this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
The last pulse kept an agent shown as typing for up to 8s after its
reply, and longer for Codex, which runs one more model call after a
final send. Stopping now feeds a local kind 9 end, the same signal a
relay reply gives, so the indicator clears at once.

STOPGAP(agent-local-typing): delete with the rest of local typing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Each post an agent made hid its typing, then the 2s post-message quiet
and the 3s pulse interval left it blank for up to 5s before the next
pulse brought it back. While this app drives an agent's typing in a
thread, the agent's own posts there no longer end it; the local end at
the turn's close does.

STOPGAP(agent-local-typing): delete with the rest of local typing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Codex makes one more model call after a final send before its turn
ends, so the request's working handoff, and with it the agent's working
reactions and typing, outlasted its reply by about 3s. The handoff now
settles at the final send, for every request the turn has taken in by
then. The turn itself still ends on its own: interrupting it would leave
a <turn_aborted> note in Codex's history after every reply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Claude and Codex answered only their owner (Claude also anyone, behind
an Answers setting), and the app woke an agent for one of the owner's
other agents only on a mention outside a thread it had spoken in. So an
agent could not hand work to another and hear back from it.

Both types now answer the owner and any agent whose message carries the
owner's NIP-OA attestation, and nobody else; the Answers setting is
gone. Another of the owner's agents wakes an agent by mentioning it
anywhere, including in reply to it. A reply alone still does not, so
two agents replying to each other cannot keep each other going.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
The shared send tool takes audience: agents for coordination only other
agents need, and tags the message ["audience","agents"]. A reply to any
message in a thread now goes to the thread's root, so agent conversations
stay flat in channels and threads.

Codex no longer rewrites send's reply before calling the tool; both
plugins pass their conversation's context and the tool decides. Codex DM
replies are now top-level, as Claude's already were. Both plugins' failure
notices reply flat too, and the Claude prompt drops its allowance for
nested agent-only subthreads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
A message tagged audience: agents reads as one quiet line in time order:
the author's avatar, an arrow to the avatars of whom it opens by
addressing, and its first paragraph. The leading mentions become the
line's recipients and are dropped from its text. Opening the line shows
the whole message. Missing or unknown audiences render as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Incoming live messages carry the signed audience, and desktop
notifications skip agents coordination even when it mentions the viewer.
Unread counts are unchanged.

Touches FOUNDATION session.ts (approved by baxen) to copy the audience
onto IncomingMessage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
The message starts beside its author and recipient avatars, and the
whole entry stays highlighted while open, so it reads as one box that
folds back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
baxen and others added 3 commits October 11, 2026 14:35
Agents had to opt in to the agents audience, so they rarely did. Now every
send names its audience, with baxen's description for agents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Posting conventions live in src/buzz-mcp/prompt.md, which Claude and Codex
both include with their own harness instructions: reply in the thread, say
agents for agent talk and low-level detail, and keep everyone posts brief.
The Claude base prompt's narration and milestone lines now match.

Signed-off-by: Bradley Axen <baxen@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening an agents message keeps the caption size and colour and starts the
text where its preview was, so it only runs on. A click anywhere in the open
box folds it, except on controls and links or when selecting text.

Signed-off-by: Bradley Axen <baxen@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@baxen
baxen force-pushed the baxen/agent-siblings branch from 02298fd to 9eeaff8 Compare October 11, 2026 23:11
@baxen

baxen commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator Author

🤖 Folded into #865 (how agents talk to each other): required audience, quiet agent lines, no notifications for agent-to-agent messages, and the shared Buzz prompt. Branch kept.

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