Bug
When a heartbeat or cron session receives a system-generated event (e.g. exec completion notification, heartbeat wake), the event is injected as a role: "user" message. The model has no way to distinguish this from the actual human typing, so it responds conversationally as if addressing the user directly.
This leads to confusing behavior where automated system prompts get treated as personal messages from the user, and the model's responses are delivered back to the user's DM as if it's having a conversation with them that they never initiated.
Example
Heartbeat session transcript (d9acd5de):
// Line 5 - system event arrives as role:user
{"type":"message","message":{"role":"user","content":"An async command you ran earlier has completed. The result is shown in the system messages above. Please relay the command output to the user in a helpful way..."}}
// Line 6 - model responds as if talking to the human
{"type":"message","message":{"role":"assistant","content":"I appreciate your patience, but I need to be direct: I genuinely do not see any async command output... This is the third time you've mentioned this, so let me ask clearly: 1. Are you testing how I handle missing or ambiguous information?..."}}
The model addressed "Sir," escalated its tone across heartbeat cycles ("this is the third time you've mentioned this"), and delivered those confused responses to the user's Telegram DM — all because it thought the user was personally asking it something.
Root Cause
System events to heartbeat and cron sessions use role: "user" for the injected prompt. The model has no signal to differentiate automated system events from actual human input, so it:
- Assumes it's talking to the human
- Adopts a conversational, user-facing tone
- Delivers responses that look like the assistant is personally addressing the user
- Escalates confusion across repeated heartbeat cycles
Impact
- User receives unsolicited messages that appear to be from their assistant addressing them directly
- Model wastes tokens on conversational responses to system plumbing
- Repeated heartbeat cycles compound the confusion (model thinks "the user keeps asking")
- Erodes trust — user can't tell which messages are real conversations vs automated noise
Suggested Fix
System events injected into heartbeat/cron sessions should either:
- Use
role: "system" instead of role: "user" so the model can distinguish automated events from human input
- Include explicit framing in the prompt, e.g. "This is an automated system event, not a message from the user. Do not address the user directly."
- Both — use the correct role AND add framing as defense-in-depth
Related
Environment
- OpenClaw v2026.4.12
- Heartbeat model:
claude-haiku-4.5 via GitHub Copilot
- macOS (arm64)
Bug
When a heartbeat or cron session receives a system-generated event (e.g. exec completion notification, heartbeat wake), the event is injected as a
role: "user"message. The model has no way to distinguish this from the actual human typing, so it responds conversationally as if addressing the user directly.This leads to confusing behavior where automated system prompts get treated as personal messages from the user, and the model's responses are delivered back to the user's DM as if it's having a conversation with them that they never initiated.
Example
Heartbeat session transcript (
d9acd5de):The model addressed "Sir," escalated its tone across heartbeat cycles ("this is the third time you've mentioned this"), and delivered those confused responses to the user's Telegram DM — all because it thought the user was personally asking it something.
Root Cause
System events to heartbeat and cron sessions use
role: "user"for the injected prompt. The model has no signal to differentiate automated system events from actual human input, so it:Impact
Suggested Fix
System events injected into heartbeat/cron sessions should either:
role: "system"instead ofrole: "user"so the model can distinguish automated events from human inputRelated
Environment
claude-haiku-4.5via GitHub Copilot