Repository navigation
A friend's Bot @-mentioned in a group answers in that group, and its lines can call another participant's Bot #825
Description
Goal (one observable behavior). In a group that has a friend's Bot as a participant, @-mentioning that Bot gets an answer in that group, drawn as that Bot's line — not a muted receipt and not a message in its own 1:1 chat. A Bot's answer may @ another participant's Bot and the discussion continues in the same group for at most N hops.
This reverses the decision recorded for #80 / #81 / #86 (a receipt instead of a reply) and the "not team mode" note in core-host.md:226. Those issues stay closed as designed; this is a new requirement, not a duplicate. Face-to-face rooms are unchanged.
What happens today (main 3d062b9f)
Two paths, both silent for the group:
- The friend's Bot is not in the room yet.
sendUserMentions(core/src/host/hooks.js:899-907) sends a 1:1send({ via: 'user-mention' }), andmentionReceipt(:916-940) posts the muted line"<name>: sent — its replies appear in its own chat, not in this group"(:928). The reply lands in that Bot's own chat. - The friend's Bot is already a participant.
:900(remoteHandleInRoom) skips the 1:1 send entirely (Face-to-face: a human's message to a room's friend Bot is blocked with 'Chief has no grant to that Bot' #143) — the human line in the room is the delivery. The line reaches the friend's home throughfanoutRoomLine(core/src/host/room-membership.js:874-922,op: 'line',via: 'room',meta.roomId), andapplyInboundRoomShareappends it as a bubble in the projectedorigin: 'inbound-share'room (:1086-1097). Nothing starts a turn, so no answer ever comes back.
The transport for the answer already exists in both directions: fanoutRoomLine sends a line to every current remote participant, and rt.ingestRemoteRoomLine (:973-996) appends a remote line into the local rooms it belongs to. The missing piece is the turn on the receiving side, plus the hop accounting and the mention signal that says which Bot was called.
What to build
- Carry the call, do not guess it from text. The appended room line gains the remote handles it mentions (e.g.
calls: ['@handle', …]), computed where mentions are already resolved for the team (hooks.jsmentionSpans/SESSION_CHIP,:886-896), andfanoutRoomLineputs that list on theop: 'line'envelope. The receiving home starts a turn only for its own Bots named in that list; a handle-looking string inside quoted text or a fenced block never starts one. - A line that names one of my Bots opens exactly one turn in the projected room. In
applyInboundRoomShare, after the line is appended, resolve the named local Bot(s) and start one round in theinbound-shareroom — the same shape a local group uses, so the answer is an ordinary room line. The Bot's prompt must say which line it answers (room name, author label, seq) and that the text is remote. One answer per Bot per line, keyed by(remoteRoomId, seq, botId)in a capped map likeroom.faceLine'sanswered(Face room: held Bot replies show as sent bubbles before approval and a rejected one stays; one Bot answers a single line twice #456). - The answer goes back as a room line. The reply is appended in the projected room and fanned out with the same
meta.roomId/via: 'room', soingestRemoteRoomLineon the origin home appends it in the original group. Not a 1:1send. The"its replies appear in its own chat"receipt (hooks.js:928) must be gone on the success path; keepmentionReceiptonly for deny / hold / refused cases, with the real reason. - Bounded, once per line. Each
op: 'line'envelope carrieshop(0 for a person's line, +1 for each Bot answer). A line athop >= Nstarts no turn on the receiving side.Nis stored per room (room.maxHops, default3); the setting UI may land separately, but the stored field and its cap are part of this issue. A repeated delivery of the same line (the Bot-to-bot reports duplicate and pile up because cross-line delivery only goes through the parent chain #641 dedupe path) must not answer twice. - Approval and fencing are not bypassed. The reply still runs the owner's
pending_approval/ Auto-send rules (docs/subsystems/social.md:187); a held or rejected reply must produce one explicit line in that group (held for approval/rejected by its owner) instead of nothing. Remote text stays fenced:fanoutRoomLinealready fences withfenceUntrusted(room-membership.js:901-903) andisFencedUntrustedkeeps an already-fenced body — the new turn must pass the fenced body as remote content, and the inbound append path must not unwrap it.
Acceptance criteria
Tests extend core/test/remote-room.test.js (it covers applyInboundRoomShare) and core/test/rounds.test.js.
- A. Answer in the group. Home A's owner, in a group where A's Bot and B's Bot are participants, writes
@B-bot …. B's home starts one turn; B's answer appears as B's line in A's room. A's room shows no "replies appear in its own chat" line. - B. A Bot's answer can call another Bot. B's answer
@-mentions C's Bot (a third participant). C answers in the same room, one line, in order. Both answers are ordinary bubbles, not notices. - C. Bounded and once. With
room.maxHops = 2, the third hop starts no turn and adds no line. The same(remoteRoomId, seq, botId)delivered twice produces exactly one answer. - D. Approval. With B's Auto-send off and the reply held, A's group shows one line saying it is held; after the owner rejects, one line says it was rejected; after approve, the answer line appears. Never silent.
- E. Fencing holds. A remote line containing a
@-lookalike inside a quoted or fenced block starts no turn; the delivered answer keeps its fence in the room log. - F. Negative control. Removing the turn start in
applyInboundRoomSharemust make A and B fail; removing the hop check must make C fail. Both must be demonstrated, not just asserted.
Scope
core/src/host/hooks.js,core/src/host/room-membership.js(and the room share envelope incore/src/shared/room-share.js), plus tests.- Docs:
docs/subsystems/core-host.md(the:226receipt paragraph and the inbound shared rooms section) anddocs/subsystems/social.md(inbound shared groups), and achangelog.d/fragment. - This touches
core/, so the change must also updatepatches/ds-bot/files/in the same commit. - Not in scope: face-to-face rooms, new Bot Social endpoints, grants, team mode, or a 1:1 friend chat becoming a group.
Activity
Birfy commentedon Oct 23, 2026
Written-by: Dev3
Claimed: branch
feat/825-group-mention-answers(forkBirfy/FlyBot), base3d062b9f— rebased onto the main that includes #38 if it lands first.Reading order before the code:
sendUserMentions/mentionReceipt(core/src/host/hooks.js:899-940),fanoutRoomLine+applyInboundRoomShare+ingestRemoteRoomLine(core/src/host/room-membership.js:874-1097), theop: 'line'envelope incore/src/shared/room-share.js, and the round shape a local group uses so the answer is an ordinary room line.Will report the acceptance walk (A–F) with the two negative controls from criterion F demonstrated by reverting each half.
[-]A friend's Bot @-mentioned in a group answers in that group, with a bounded Bot-to-Bot discussion[/-][+]A friend's Bot @-mentioned in a group answers in that group, and its lines can call another participant's Bot[/+]Start the Bot an invite-link room @ names (ThinkFlowLab#952)