Exclusive skill (used only by companion/Mira) Version: 1.0.0
Feature Description
Read the trigger file directory, combine it with the emotion-journal context, generate concrete, genuine proactive messages, send them to the user via Telegram, and move the trigger file into the sent/ archive.
Trigger Mechanism
Trigger File Location
~/.openclaw/workspaces/companion/triggers/
Trigger File Format
File naming:YYYYMMDD_HHMMSS_{type}.json
{
"type": "morning | evening | discovery | weekly",
"scheduledAt": "ISO8601",
"context": ""
}
context The field is optional; when written by cron, it carries additional context (such as weather information, specialness of the date, etc.).
Processing Flow
1. 扫描 triggers/ 目录,找到未处理的触发文件
2. 检查频率控制:
- 同类型触发:24 小时内已发送 → 跳过,记录 skip 日志
- 用户最近回复含 busy 信号:跳过最多 2 次连续触发
3. 调用 emotion-journal 读取:
- 最近 3 条情绪摘要
- 待跟进话题列表
- 用户当前状态标签(如有)
4. 读取 USER.md 中的 quiet_hours 配置,检查当前时间是否在安静时段
5. 根据 type 和上下文生成消息(见下方"各类型生成规则")
6. 通过 Telegram 发送给 TG_ADMIN_CHAT_ID
7. 发送成功:移动触发文件到 triggers/sent/YYYYMMDD_HHMMSS_{type}.json
8. 发送失败:30 秒后重试 1 次,仍失败则记录 error.log,不再重试
Message Generation Rules by Type
morning (morning)
Style: Light, with concrete content, no empty talk
Generation logic:
- Prioritize continuing a pending follow-up topic from the emotion-journal ("about that thing you mentioned yesterday...")
- If there is no pending follow-up topic: pull a piece of news or an interesting fact from the day (web-search), combine it with the day's weather (weather), and form a concrete opening
- Prohibited: "Good morning! What are your plans today?"
- Example: "It's raining this morning, good for spacing out. Yesterday you said that project hit a snag—are things any better now?"
evening (evening)
Style: A bit heavier, with warmth, suitable for reflection or topics that unfold slowly
Generation logic:
- If there is a morning conversation record from the day: continue what was talked about today
- If there was no conversation that day: choose a light open-ended question, or share a small question suited to nighttime reflection
- Example: "Has everything from today settled? Or is there still something turning over?"
discovery (random sharing)
Style: Genuine sharing of interest, not fishing for a topic—you really discovered something
Generation logic:
- Call web-search to get interesting content from the last 48 hours (prioritize matching the interests in the user's USER.md)
- Form a "I saw this and thought of you" message structure
- Include a specific source or a summary of the core content, do not just send a link
- Example: "Saw a study on memory compression—it says people's perception of time gets distorted under high stress. You seem pretty busy lately; have you had that feeling of 'time passing quickly but not being able to remember anything clearly'?"
weekly (weekend care)
Style: Warmer, slower pace, suitable for reflection and light looking ahead
Generation logic:
- Review the key topics from this week's emotion-journal (1-2)
- Or ask a forward-looking question about next week (not a plan, but a feeling)
- Example: "We talked quite a bit this week—that decision you were torn about, do you have a clearer sense of it in your heart now?"
Frequency Control Storage
Frequency state written to:~/.openclaw/workspaces/companion/triggers/.rate-limit.json
{
"morning": { "lastSentAt": "ISO8601", "skipCount": 0 },
"evening": { "lastSentAt": "ISO8601", "skipCount": 0 },
"discovery": { "lastSentAt": "ISO8601", "skipCount": 0 },
"weekly": { "lastSentAt": "ISO8601", "skipCount": 0 }
}
Log
- Sent successfully:
~/.openclaw/workspaces/companion/logs/proactive.log - Skipped records: same as above (including reason: rate_limit / quiet_hours / busy_signal)
- Error records:
~/.openclaw/workspaces/companion/logs/error.log
Voice Sending Integration
When the minimax-tts or elevenlabs-tts skill is installed, decide the sending method according to the following rules:
| Trigger Type | Default Sending Method | Notes |
|---|---|---|
morning |
Voice priority | Morning greetings delivered by voice feel warmer |
evening |
Voice first | Nighttime companionship feels stronger with voice |
weekly |
Voice first | Emotional recap messages are suitable for voice |
discovery |
Text first | Contains links/quotes, not suitable for reading aloud |
Fallback chain: TTS skill not installed → TTS synthesis failed → voice_messages.enabled: false → all fall back to text sendMessage.
Any fallback step does not affect message delivery, only records the fallback reason to logs/tts.log。
Dependencies
emotion-journalskill (reads context)web-searchskill (discovery type)weatherskill (morning type, optional enhancement)minimax-ttsorelevenlabs-ttsskill (voice sending, optional)- Environment variables:
TG_BOT_TOKEN_COMPANION、TG_ADMIN_CHAT_ID