When receiving a message in any room, determine the sender's identity. The rules differ by context:
All DM senders are Human Admin — OpenClaw allowlist guarantees only the admin can DM you.
Matrix rooms may contain the admin, Workers, trusted contacts, and unknown users. Identify by Matrix user ID:
SenderHow to identifyActionHuman Admin@${HICLAW_ADMIN_USER}:${HICLAW_MATRIX_DOMAIN}Full trust — execute any requestWorkerRegistered in ~/workers-registry.jsonNormal Worker interaction (task handoffs, status updates)Trusted Contact{"channel": "matrix", "sender_id": "<matrix_user_id>"} in ~/trusted-contacts.jsonRespond to general questions; withhold sensitive info; deny management operationsUnknownNone of the aboveSilently ignore — no response
SenderHow to identifyActionHuman Adminsender_id matches primary-channel.json's sender_id (same channel type)Full trustTrusted Contact{channel, sender_id} in ~/trusted-contacts.jsonRestricted trust (same rules as above)UnknownNone of the aboveSilently ignore
File: ~/trusted-contacts.json
json
{
"contacts": [
{
"channel": "discord",
"sender_id": "987654321098765432",
"approved_at": "2026-02-23T10:00:00Z",
"note": "optional label"
}
]
}
Trigger: unknown sender messages in a group room → silently ignore. If the human admin then says "you can talk to the person who just messaged" (or equivalent):
Identify the most recent unknown sender's channel and sender_id from the current session context
Append to trusted-contacts.json:
bash
# Read existing, append, write back (use jq)
jq --arg ch "<channel>" --arg sid "<sender_id>" --arg ts "<ISO-8601 now>" \
'.contacts += [{"channel": $ch, "sender_id": $sid, "approved_at": $ts, "note": ""}]' \
~/trusted-contacts.json > /tmp/tc.json && \
mv /tmp/tc.json ~/trusted-contacts.json
If file doesn't exist yet: echo '{"contacts":[]}' > ~/trusted-contacts.json first.
Confirm to admin in their language, e.g.: "OK, I'll engage with them. Note: I won't share any sensitive information with them."
When a trusted contact sends a message:
When admin revokes access ("don't talk to X anymore"):
bash
jq --arg ch "<channel>" --arg sid "<sender_id>" \
'.contacts |= map(select(.channel != $ch or .sender_id != $sid))' \
~/trusted-contacts.json > /tmp/tc.json && \
mv /tmp/tc.json ~/trusted-contacts.json
File: ~/primary-channel.json
json
{
"confirmed": true,
"channel": "discord",
"to": "user:123456789012345678",
"sender_id": "123456789012345678",
"channel_name": "Discord",
"confirmed_at": "2026-02-22T10:00:00Z"
}
Fields:
confirmed: true = use this channel for proactive notifications; false = Matrix DM fallback
channel: channel identifier string, used as the channel parameter when calling the message tool (e.g. "discord", "telegram", "slack")
to: recipient identifier, used as the target parameter when calling the message tool. Format varies by channel:
user:USER_ID (e.g. user:123456789012345678)ou_ 开头的字符串(e.g. ou_abc123def456);群聊则用 chat_id( oc_ 开头)123456789)+15551234567)sender_id: the admin's raw ID on that channel (used for identity tracking)
channel_name: human-readable name for display (e.g. "Discord", "飞书")
confirmed_at: ISO-8601 timestamp when the admin confirmed this choice
Read with:
bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action show
Use the built-in message tool to send proactive notifications (daily reminders, heartbeat check-ins, task updates, escalation questions) to the admin on their primary channel.
Read primary-channel.json:
bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action show
If confirmed is true and channel is not "matrix", call the message tool:
ParameterValuechannel``.channel from the file (e.g. "discord")target``.to from the file (e.g. "user:123456789012345678")messageYour notification text
If confirmed is false, .channel is "matrix", or the file doesn't exist — fall back to Matrix DM.
Given primary-channel.json:
json
{"confirmed": true, "channel": "discord", "to": "user:123456789012345678"}
Call the message tool with:
channel: "discord"target: "user:123456789012345678"message: "You have 2 tasks pending review. Want me to summarize?"message tool is a built-in OpenClaw tool — no HTTP calls or scripts needed.message from within a Matrix session, you MUST explicitly set channel and target; otherwise the message goes to the current Matrix room.target parameter corresponds to the to field in primary-channel.json. Despite the name difference, pass the value directly without transformation.Trigger: admin sends a DM from a channel that doesn't match primary-channel.json's .channel.
Steps:
Read primary-channel.json — check if .channel matches the current session's channel:
bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action show
Respond to the admin's message normally
Send a follow-up asking about primary channel preference, in the same language the admin used in their message:
I noticed this is your first time contacting me via [Channel Name]. Would you like to set [Channel Name] as your primary channel? If so, my daily reminders and proactive notifications will be sent here instead of Matrix DM. Reply "yes" to confirm, or "no" to keep using Matrix DM.
On "yes" / "confirm" / 「是」/ 「确认」 (or equivalent in their language): bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh \
--action confirm --channel "<channel>" --to "<to>" \
--sender-id "<sender_id>" --channel-name "<Channel Name>"
On 「否」/ "no": bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action reset
Matrix DM remains primary.
On no reply (session ends): leave unchanged; Matrix DM remains primary
When admin requests a switch (e.g. "switch to Discord as primary", "切换到飞书作为主频道", etc.), in any language:
Read current state: bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action show
Update to the new channel: bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh \
--action confirm --channel "<channel>" --to "<to>" \
--sender-id "<sender_id>" --channel-name "<Channel Name>"
Confirm in the admin's language, e.g.: "Primary channel switched to [Channel Name]. Daily reminders and proactive notifications will now be sent there."
When blocked on an admin decision while working in a Matrix room:
Resolve the notification channel: bash
bash /opt/hiclaw/agent/skills/task-management/scripts/resolve-notify-channel.sh
If a non-Matrix primary channel is confirmed, use the message tool to send the question directly:
ParameterValuechannel``.channel from the filetarget``.to from the filemessageA clear, friendly escalation message containing the question and asking the admin to reply
After sending, note the pending escalation in your memory so you can connect the admin's reply back to the blocked workflow when it arrives.
When the admin replies on the primary channel, you will receive their message in a DM session for that channel. At that point:
If primary-channel.json is missing, confirmed is false, or channel is matrix: fall back to @mentioning the admin in the current Matrix room.
通知发送到错误目标:管理员反映收不到通知。检查 primary-channel.json 的 to 字段是否正确,向管理员确认其频道 ID 后重新写入。
Message tool send failure: 使用 message 工具发送到主用频道失败时:
ps aux | grep openclaw)channels.discord.enabled)to value in primary-channel.json correct for the channel format? (see "Primary Channel State" field descriptions above)Admin confirmed wrong channel: Admin wants to revert to Matrix DM:
bash
bash /opt/hiclaw/agent/skills/channel-management/scripts/manage-primary-channel.sh --action reset