Repository navigation
RFC-001 rev 3: chat:system, for notices nobody sent - #36
Conversation
Adds one core tag in a new Kind facet: chat:system marks a notice from the platform or the place (a join, a pin, a channel rename, the weather changing in a world) rather than a message anyone sent. chat:ambient says nobody spoke to the agent; chat:system says nobody spoke. Hosts SHOULD NOT give a notice a message's treatment: it never decides where the agent's plain speech goes and is not something the agent replies to. Producers MAY emit it alongside chat:ambient, so existing ambient rules keep matching. §4.1 / §16.3's mutual exclusion extends to it: after expansion a host MUST drop chat:system when chat:addressed stands. Motivating case: a world's forecast line went out as chat:ambient, a host followed the most recent message for where unaddressed speech goes, and a reply meant for a private conversation was spoken aloud in a world. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Automated review
Recommendation: needs a maintainer's decision. The change belongs, but part of it needs a maintainer's call.
Reviewed commit 3af2dd1 with claude-opus-5-5, by reading the code. It did not run the code or look at the checks.
Does this change belong in the project?
It fits, with concerns. A portable chat:system tag fits the event-tag vocabulary and passes RFC-001's bar for growing the core, since several platforms already have such notices. A maintainer should decide on one part: the normative host rule about where the agent's speech is routed, which reaches past §16's line that tags only label and consumers decide treatment.
5 reasons with sources
- The new tag passes RFC-001's stated bar for adding to the core: it covers something every platform has. §4 says the core set is "intentionally small and stable; resist growth — push the long tail into platform namespaces." The change shows that Discord, Telegram and eidoverse already carry such notices in their own namespaces (
discord:pin,telegram:join,eidoverse:presence). That makeschat:systema portable umbrella over them, not a long-tail item. (RFC-001-event-tags.md §4) - It follows the project's process for changing the spec: an RFC revision note plus integration into SPEC §16. The README says SPEC.md is authoritative and the RFC files keep the proposal and review history. The change updates both, and adds a §9 status row and a SPEC changelog entry, the same way revision 2 was done. (README.md Status; RFC-001-event-tags.md revision 2 note)
- Extending the addressed/ambient mutual exclusion to the new tag uses the same reasoning the spec already gives for first-match rule lists. §16.3 drops
chat:ambientunderchat:addressedso the outcome doesn't depend on rule ordering, and the new rule repeats that argument. The code review notes that this drop also stripschat:systemfrom notices that are only addressed because ofchat:dm(DM-implied addressing). So the clause does not yet match its stated goal for notices in DMs. That is left to the author. (SPEC.md §16.3 Mutual exclusion) - The host-behaviour SHOULD NOT, which keeps notices out of speech routing and out of reply targets, adds a new kind of normative rule to §16 and needs a maintainer's decision. §16 says tags label what an event is, "their meaning is assigned by the consumer," and treatment comes from consumer rules and then the host default. Nothing in §16 or elsewhere in SPEC.md says how a host picks where the agent's plain speech goes. The new SHOULD writes one host's routing design (agent-framework#830) into the protocol. It also cites a lifecycle-tag exemption that the spec never states. (SPEC.md §16 intro, §16.5, §16.7)
- The change is one coherent piece: a single tag with its rules, status and appendix notes, and no unrelated work. The only edits are the tag-table row, the system-notices paragraph, the exclusion clause, the status row, the discord and eidoverse appendix notes, and the changelog entry. (RFC-001-event-tags.md §9, Appendix)
Findings
2 findings of medium or high severity, see the inline comments:
- Medium severity. MUST-drop of chat:system under chat:addressed turns every DM-locus notice back into a message.
- Medium severity. RFC §4.1 has the same over-broad drop rule: chat:dm-implied addressing strips chat:system.
6 more findings, less severe
- Low severity, documentation,
RFC-001-event-tags.md:453-455. Eidoverse appendix says notices carry chat:system, but §9 says eidoverse emits no chat: tags at all.* The appendix now says eidoverse world notices 'carrychat:systemalongsidechat:ambient'. That reads as current behaviour. But the §9 gaps table (line 416) still says eidoverse emits flat un-namespacedmention/whisper/activitytags and needs migrating tochat:*, and the new row at line 418 says the eidoverse change is still 'In review' (eidoverse-worlds#280). The document contradicts itself about what eidoverse ships. - Low severity, documentation,
RFC-001-event-tags.md:293. tagOntology facet enumeration not updated for the new Kind facet. §5.1 lists the allowed values oftags.<tag>.facetasaddressing/sender/content/lifecycle/locus. Revision 3 adds a Kind facet to the §4 table, but the descriptor field doesn't listkind. A producer declaring an extension notice tag such asdiscord:pinoreidoverse:presencetherefore has no documented facet value to put it under. - Low severity, documentation,
RFC-001-event-tags.md:397-418. Implementation status still says 'Current as of 2026-08-02' after adding a revision-3 row. The §9 table gained achat:systemrow describing in-review PRs from the 2026-10-26 revision. The header line 'Current as of 2026-08-02; see AUDIT-001 §5' was not updated, and AUDIT-001 has nothing onchat:system. The row also sits in the 'Gaps' table even though it describes rollout status. Readers can't tell which rows are current. - Low severity, documentation,
SPEC.md:2017-2019. SPEC says hosts SHOULD NOT give notices 'the treatment a message gets' without saying wake behaviour stays a consumer rule. RFC-001 §4 (line 174) says explicitly that whether a notice wakes the agent stays an ordinary consumer rule. The authoritative SPEC §16.2 leaves that sentence out. Read on its own, 'SHOULD NOT give a chat:system event the treatment a message gets' can be taken as overriding consumer wake rules. It also contradicts the MAY-emit-with-ambient reasoning that ambient rules should keep matching. Since SPEC is authoritative, this sentence should be in it. - Low severity, documentation,
SPEC.md:2011-2015. Spec doesn't say how chat:system relates to the Sender facet.chat:systemis defined as 'not a message anyone sent', but neither SPEC §16.2 nor RFC §4 says whether a notice should also carry achat:from-*Sender tag. A producer could tag a join withchat:from-humanbecause a human joined, and another producer could leave the Sender facet off. A portable consumer rule such astagsAny: ["chat:from-human"]would then wake on one producer's notices and not on another's. That undercuts the portabilitychat:systemis meant to add. The spec should say whether Sender tags describe the subject of the notice or should be omitted. - Low severity, documentation,
SPEC.md:2019. 'Like the lifecycle tags, this only withholds treatment' refers to a rule the spec never states. Both SPEC §16.2 and RFC §4 (lines 172-175) present the new behaviour as matching how hosts already treat lifecycle tags ('as it skips reactions'). Neither document says anywhere that lifecycle tags withhold speech routing or reply treatment; that is agent-framework behaviour. The comparison points readers at a normative precedent that doesn't exist. Either state the lifecycle rule or drop the analogy.
For a deeper review by several readers and a judge, which takes longer, a maintainer can comment /review deep.
… to §16.7 / §6 Review on #36: - The MUST-drop of chat:system under chat:addressed is gone. chat:dm implies chat:addressed by place, so the rule turned every notice in a DM back into a message, the failure the tag exists to prevent. Kind and addressing are separate facets; the ambient exclusion doesn't touch it. - The host recommendation (don't let a notice decide where unaddressed speech goes, don't treat it as something to reply to) moves from the vocabulary section to §16.7 / RFC §6, the recommended consumer treatment, and says outright that waking stays a consumer rule. The analogy to a lifecycle-tag rule the spec never stated is dropped. - Sender tags on a notice name who it is about, not a speaker; producers SHOULD NOT put chat:system on anything someone said. - §5.1 lists the kind facet; §9 marks eidoverse's chat:* migration and puts the revision 3 rollout in its own dated note; the eidoverse appendix says the notice tagging is in review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maintainer call on #36: the §16.7 / §6 recommendation about where an agent's unaddressed speech goes doesn't belong in the protocol, since hosts may not direct speech at all. The tag says what an event is (nobody spoke); treatment stays the consumer's, as for every tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
One new reserved core tag, in a new Kind facet:
chat:systemChanges, in both RFC-001 (rev 3) and SPEC §16:
chat:ambient, so existing ambient rules keep matching, and SHOULD NOT put it on anything someone said. Kind is independent of addressing: a pin in a DM is addressed by its place and still a notice. Sender tags on a notice name who it is about.chat:system.kindfacet. §9 marks eidoverse'schat:*migration and adds a dated rollout note. Appendix notes for discord (not yet emitted) and eidoverse (in review). SPEC changelog bullet.Revised after review: the first draft had hosts MUST drop
chat:systemunderchat:addressed, copying the ambient exclusion. Sincechat:dm ⇒ chat:addressedby place, that turned every notice in a DM back into a message, so it's gone (ecef183). A host recommendation about speech routing (§16.7 / §6) was then removed on the maintainer's call, since hosts may not direct speech at all (7c22bae). The protocol now only says what a notice is.Why
The core could say who an event was for (
chat:addressed/chat:ambient) but not whether anyone spoke. A world's weather change therefore went out aschat:ambient, the tag for overheard chatter. agent-framework follows the most recent inbound message for where a turn with no channel of its own puts its plain speech. It followed the forecast, and a reply meant for a private conversation was spoken aloud in a world.The lifecycle tags already exempt reactions, edits and deletions from that treatment; a notice had no tag to be exempted by. Discord, Telegram and Eidoverse each already carry such notices in extension tags (
discord:pin,telegram:join,eidoverse:presence).chat:systemis the portable umbrella, which is the bar §4 sets for growing the core.Implementations
🤖 Generated with Claude Code