GitHub Issue: Inter-session message attribution incorrectly defaults to owner peer
Repository: plastic-labs/openclaw-honcho
Plugin version: 1.2.1
OpenClaw version: 2026.3.28
Summary
When agents communicate via sessions_send (inter-session messaging), the Honcho plugin attributes all inbound role: "user" messages to the owner peer instead of the sending agent's peer. This causes Honcho to model the owner as having authored messages they never wrote, polluting the owner's representation.
Environment
- Multi-agent OpenClaw setup with 4 agents (main/Kai, atlas, nyx, mia)
- Agents communicate via
sessions_send for task delegation
- Each agent has its own persistent session and Honcho peer (
agent-main, agent-atlas, etc.)
Steps to Reproduce
- Agent A (e.g.,
agent:main) sends a message to Agent B (e.g., agent:atlas) via sessions_send
- Agent B processes the message and responds
- The
agent_end capture hook fires and calls flushMessages() → extractMessages()
- The inbound message from Agent A is attributed to the owner peer instead of Agent A's peer
Expected Behavior
The message should be attributed to Agent A's peer (agent-main), since Agent A is the actual sender.
Actual Behavior
The message is attributed to the owner peer, because extractMessages() maps all role: "user" messages to ownerPeer unconditionally:
const peer = role === "user" ? ownerPeer : agentPeer;
Root Cause Analysis
Provenance data exists but is not accessible
OpenClaw tags sessions_send messages with full provenance in the session transcript (.jsonl file):
{
"role": "user",
"content": [...],
"provenance": {
"kind": "inter_session",
"sourceSessionKey": "agent:main:discord:channel:...",
"sourceChannel": "discord",
"sourceTool": "sessions_send"
}
}
However, event.messages passed to plugin hooks strips the provenance field. Messages in the hook only contain ["role", "content", "timestamp"].
This means the plugin cannot access provenance from the hook event data directly.
Same issue affects subagent_announce messages
Subagent completion announcements also arrive as role: "user" with provenance.sourceTool === "subagent_announce" and are similarly mis-attributed to the owner.
Data from a real session:
- 80
sessions_send messages attributed to owner (should be agent-main)
- 18
subagent_announce messages attributed to owner (should be parent agent)
Additional gap: cron/heartbeat messages
Cron-initiated and heartbeat messages arrive as role: "user" with no provenance at all. These system-generated prompts get attributed to the owner, polluting the owner's representation with content like "Read HEARTBEAT.md..." and "[cron:...] WhatsApp Pulse — 15-min scan."
This cannot be fixed in the plugin without OpenClaw core tagging these messages with provenance.
Workaround (local patch applied)
We implemented a local workaround that reads provenance from the session transcript .jsonl file:
flushMessages() constructs the transcript path from ctx.agentId + ctx.sessionId
- Reads the
.jsonl file and builds a Map<timestamp, provenance> for inter-session user messages
- Matches
event.messages entries by timestamp to find their provenance
- Resolves sender agent peers via
getAgentPeer() and builds a peer override map
- Passes overrides to
extractMessages() which uses them instead of defaulting to ownerPeer
This workaround is functional but has limitations:
- Reads the entire transcript file on every flush (performance concern for large sessions)
- Relies on timestamp matching (could theoretically have collisions)
- Must be re-applied after plugin updates
Recommended Fix
Ideal (requires OpenClaw core change)
OpenClaw should include provenance in event.messages passed to plugin hooks. The data exists on disk — it just needs to not be stripped before hook delivery.
Plugin-side fix (if OpenClaw exposes provenance)
In extractMessages() or flushMessages():
// Before peer assignment, check provenance
if (role === "user" && m.provenance?.kind === "inter_session") {
const senderAgentId = parseAgentIdFromSessionKey(m.provenance.sourceSessionKey);
if (senderAgentId) {
peer = await getAgentPeer(senderAgentId);
}
}
Design decisions (validated with 4-round technical review)
sessions_send messages → attribute to sending agent peer
subagent_announce messages → attribute to parent agent (not ephemeral subagent)
- All
:subagent: session keys collapse to parent agent identity
- Sender peers added to session with
observeMe: true, observeOthers: true
- Single merged
addPeers() call with OR-merge for observation booleans
- Cron/heartbeat attribution deferred (needs OpenClaw core provenance tagging)
Additional Issue: createMemorySearchTool error
After updating OpenClaw to 2026.3.28, the plugin throws:
plugin tool failed (openclaw-honcho): TypeError: Cannot read properties of undefined (reading 'createMemorySearchTool')
This appears to be a compatibility issue between plugin v1.2.1 and OpenClaw 2026.3.28's memory tool API. Core memory capture/context injection still works — only the QMD passthrough tool registration fails.
Impact
- Owner peer representation polluted with agent-authored and system-generated content
- Agent peer representations missing their actual inter-agent communication
- Context injection feeds polluted data back into prompts (compounding effect)
- Multi-agent setups with frequent
sessions_send usage are most affected
GitHub Issue: Inter-session message attribution incorrectly defaults to owner peer
Repository:
plastic-labs/openclaw-honchoPlugin version: 1.2.1
OpenClaw version: 2026.3.28
Summary
When agents communicate via
sessions_send(inter-session messaging), the Honcho plugin attributes all inboundrole: "user"messages to the owner peer instead of the sending agent's peer. This causes Honcho to model the owner as having authored messages they never wrote, polluting the owner's representation.Environment
sessions_sendfor task delegationagent-main,agent-atlas, etc.)Steps to Reproduce
agent:main) sends a message to Agent B (e.g.,agent:atlas) viasessions_sendagent_endcapture hook fires and callsflushMessages()→extractMessages()Expected Behavior
The message should be attributed to Agent A's peer (
agent-main), since Agent A is the actual sender.Actual Behavior
The message is attributed to the owner peer, because
extractMessages()maps allrole: "user"messages toownerPeerunconditionally:Root Cause Analysis
Provenance data exists but is not accessible
OpenClaw tags
sessions_sendmessages with full provenance in the session transcript (.jsonlfile):{ "role": "user", "content": [...], "provenance": { "kind": "inter_session", "sourceSessionKey": "agent:main:discord:channel:...", "sourceChannel": "discord", "sourceTool": "sessions_send" } }However,
event.messagespassed to plugin hooks strips theprovenancefield. Messages in the hook only contain["role", "content", "timestamp"].This means the plugin cannot access provenance from the hook event data directly.
Same issue affects
subagent_announcemessagesSubagent completion announcements also arrive as
role: "user"withprovenance.sourceTool === "subagent_announce"and are similarly mis-attributed to the owner.Data from a real session:
sessions_sendmessages attributed to owner (should beagent-main)subagent_announcemessages attributed to owner (should be parent agent)Additional gap: cron/heartbeat messages
Cron-initiated and heartbeat messages arrive as
role: "user"with no provenance at all. These system-generated prompts get attributed to the owner, polluting the owner's representation with content like "Read HEARTBEAT.md..." and "[cron:...] WhatsApp Pulse — 15-min scan."This cannot be fixed in the plugin without OpenClaw core tagging these messages with provenance.
Workaround (local patch applied)
We implemented a local workaround that reads provenance from the session transcript
.jsonlfile:flushMessages()constructs the transcript path fromctx.agentId+ctx.sessionId.jsonlfile and builds aMap<timestamp, provenance>for inter-session user messagesevent.messagesentries by timestamp to find their provenancegetAgentPeer()and builds a peer override mapextractMessages()which uses them instead of defaulting toownerPeerThis workaround is functional but has limitations:
Recommended Fix
Ideal (requires OpenClaw core change)
OpenClaw should include
provenanceinevent.messagespassed to plugin hooks. The data exists on disk — it just needs to not be stripped before hook delivery.Plugin-side fix (if OpenClaw exposes provenance)
In
extractMessages()orflushMessages():Design decisions (validated with 4-round technical review)
sessions_sendmessages → attribute to sending agent peersubagent_announcemessages → attribute to parent agent (not ephemeral subagent):subagent:session keys collapse to parent agent identityobserveMe: true, observeOthers: trueaddPeers()call with OR-merge for observation booleansAdditional Issue:
createMemorySearchToolerrorAfter updating OpenClaw to 2026.3.28, the plugin throws:
This appears to be a compatibility issue between plugin v1.2.1 and OpenClaw 2026.3.28's memory tool API. Core memory capture/context injection still works — only the QMD passthrough tool registration fails.
Impact
sessions_sendusage are most affected