Files
openclaw-config/agents/main/agent/workshop-skills/scheduled-reminders/SKILL.md
T

11 KiB
Raw Blame History

name, description
name description
scheduled-reminders 创建/管理定时提醒(每周/每天/睡前等周期或一次性)并推送到钉钉或飞书。触发:帮我设提醒、每天X点提醒、每周提醒、推送到飞书。

scheduled-reminders

创建和管理杨轩的定时提醒:周期性(每周/每天)或一次性,默认推送钉钉,用户点名时改投飞书(见「投递通道」)。非生日类提醒走本 skill;生日提醒走 birthday-reminder skill。

触发场景

  • 杨轩说「帮我设个提醒」「每天 X 点提醒我」「每周三提醒」「睡前提醒」等
  • 需要查看/修改/删除已有提醒任务

核心规则(必须遵守)

所有提醒都是 OpenClaw cron 任务,统一:

  • 投递只交给 deliverypayload 只输出文案(--command 'echo "..."'),路由写在 delivery 参数上;默认钉钉--announce --channel dingtalk-connector --to 0464031658857345。用户要求飞书时按「投递通道」换参数。
  • 多频道下频道必须显式:本机已配 3 个频道(dingtalk-connector / feishu / openclaw-weixin),省略投递参数时 cron add 直接失败:cron announce delivery requires an explicit channel when multiple channels are configured。要推送就照上面写全;不需要推送给人的内部维护任务--no-deliver(实测结果 delivery.mode=none),不要只把 flag 省掉。
  • 禁止在命令里手动调 openclaw message send——CLI 的 message send 不认识 dingtalk-connector(内置频道枚举无 DingTalk 插件名),会 exit 1 失败。
  • 必须 --agent main:多 agent 环境下无 owneragent-less)的 cron 任务会让调度器 nextWake 锁死,阻塞所有提醒。
  • 时间参数:周期性用 --cron "<表达式>" --tz Asia/Shanghai;一次性用 --at(不带时区按 UTC 处理,北京时间 = UTC+8)。

投递通道:钉钉(默认)/ 飞书

杨轩说「推送到飞书」时,只把 delivery 换掉:--announce --channel feishu --to <目标>

  • 飞书目标必须用 DM 会话 chat_idoc_8eecfa0e1cc185c1cb19b4f3950cbc52(杨轩的飞书私聊)。
  • 不要用用户 open_idou_28124d6721134f0e31d6122d30088418):2026-09-16 实测 cron 投递报 Feishu send failed: Sending messages to users is temporarily unavailable.,判为 not-delivered;同一时刻改投上面的 chat_id 即刻成功。错误文案含「temporarily」,条件可能变化,但先用 chat_id 就不必试错。用 conversations_list(channel="feishu") 可复核 DM 目标。
  • 可达性分两类:同日实测飞书群 / chat_id 可达,而机器人主动向用户私聊(open_id)不可达、可复现——该错误文案里虽然带「temporarily」,但先按不可达处理,别计划性地依赖飞书私聊推送。
  • 换通道只动 delivery--agent main、时间、打卡机制等其余规则一律不变。
  • 通了没有要实测,不要推断:可临时建一条一次性测试任务,用 automations run <jobId> 立即跑一次,看 state.lastDelivered / lastDeliveryError,验证完把测试任务删掉。
  • 测试只发一次:验证投递时按上面的 run 方式做,不要额外往群或私聊手发多条诊断消息;确需手发时正文标注「测试/请忽略」。
  • cron 的 delivery 与手动发消息是两条路:本 skill 的投递只写在 delivery 参数上;「消息发不出去 / 要跨频道手动投递」另见 cross-channel-send
  • 要同一条推两个通道时用「孪生任务」单条 cron 只能投一个渠道delivery.channel 只有一个值)。杨轩要「钉钉和飞书一起提醒」时,同一天建两条任务(各带一个渠道、文案完全一致),飞书那条在 --name 加后缀「(飞书)」以便分辨。典型应用:生日提醒(见 birthday-reminder,已按 3 对×每人落地)。不要试图用一条任务投多个渠道,也不要在 payload 里叠 message send 来凑第二个通道。

创建一条周期提醒

openclaw cron add "任务名" \
  --cron "0 21 * * 2" --tz Asia/Shanghai \
  --agent main --session isolated --announce \
  --channel dingtalk-connector --to 0464031658857345 \
  --wake now --display-name "任务名" \
  --command 'echo "提醒文案"'

cron 星期数字:周日 = 0,周一 = 1 … 周六 = 6(容易记错,务必核对)。

写在脚本里时用 CLI 绝对路径/home/yangxuan/.openclaw/tmp/agent-cli/openclaw(裸 openclaw 是同一目录下的 shim,只在 exec 的 PATH 里有效)。shell 助手/批量脚本若自行重设了 PATH,裸 openclaw 会报「未找到命令」(2026-09-16 实测);用绝对路径,或把该目录并入 PATH

一次创建多条(批量)

多条同类提醒时,写一个 shell 助手函数把上面的标准 flag 包起来,再用循环调用(模板见 examples/batch-reminders.sh),比逐条手敲省大量往返。文案相同的提醒合并成变量复用,避免重复粘贴。

验证(必做)

创建后用 openclaw cron get <id> 逐条确认:

  • agentId=main
  • delivery.mode=announce,且 delivery.channel/delivery.to 就是本次要求的目标(钉钉:dingtalk-connector + 0464031658857345;飞书:feishu + chat_id
  • schedule.expr 与下次触发 nextRunAtMs 正确

整库不应残留 message send 字样。

带打卡确认的提醒(用户要求「要打卡/要确认」时)

提醒发出后用户可能不回复,需要二次确认时,用「提醒 + 延后检查」两条任务:

  1. 提醒文案末尾加一句打卡要求:完成后回我一句「打卡」✅
  2. 另建一条延后检查任务(如提醒 21:00、检查 22:30),payload 用 --message(agentTurn),先读会话再决定是否催:
    • sessions_history 读会话 agent:main:dingtalk-connector:direct:0464031658857345 当天消息
    • 用户已在提醒时间后回复过关键词(如「打卡」)→ 回 NO_REPLY(不打扰)
    • 未回复 → 发一条温和催促
  3. 检查任务用与提醒相同的 delivery 参数(--agent main、announce、dingtalk-connector)。
openclaw cron add "打卡检查" \
  --cron "30 22 * * *" --tz Asia/Shanghai \
  --agent main --session isolated --announce \
  --channel dingtalk-connector --to 0464031658857345 \
  --wake now \
  --message '检查打卡:用 sessions_history 读会话 agent:main:dingtalk-connector:direct:0464031658857345 今天的消息;若用户在提醒时间后回复过「打卡」则回 NO_REPLY,否则发一条温和催促。'

盘点已有提醒(用户问「某提醒还在不在 / 是不是在钉钉 / 提醒看到了吗」时)

  1. automations listincludeDisabled: true)按 name 定位目标;返回已含 scheduleeffectiveAgentIdnextRunAt
  2. 对关心的每条 automations get <jobId>,确认 agentId=maindelivery.mode=announce,并读实际 delivery.channel/to 回报它是投到钉钉还是飞书(不要默认钉钉)。
  3. 用户问「发出去没有 / 我收到了吗」时查历史:openclaw cron runs <jobId>,读最近几条的 statuscompletionStatusdeliveredsummary
  4. 区分「设计内静默」与「投递失败」delivered=falsedeliverySuppressionReasonemptypayload 没输出任何内容)或 silentagent 回 NO_REPLY)属正常静默,不是故障。本机「视频监督踢水」带周末/节假日不出声逻辑,非工作日的 empty 即此类;护肤打卡检查的 silent 即用户已打卡。只有报错(lastDeliveryError 非空、deniedFeishu send failed)才算真失败,不要见 not-delivered 就报警。
  5. 回报时给下次触发时间 + 上次结果,并写明是「已送达」还是「设计内静默」。
  6. 清残留:默认列表不显示已禁用任务,用 openclaw cron list --all 才会列出。确认无用后 openclaw cron rm <id>;若报 Automation not found,说明该条已删成功(列表快照可能滞后),重新 list --all 复核即可,不要重复删或改其它任务。

修改 / 删除

  • 改时间/周期:openclaw cron edit <id> --cron ...,或 automations 工具的 update <jobId>
  • command 型 payload 只能用 CLI 改automations 工具的 update 不接受 payload.kind="command",会报 job.payload.kind: must be equal to one of the allowed values(实测);agentTurn 型(--message)才用 automations update
  • 改已有 command payload 时不要手抄原脚本(脚本常含换行与引号,手抄必错):先 openclaw cron get <id>payload.argv,在 Python 里改,再用完整 argv 的 JSON 写回:
    openclaw cron edit <id> --command-argv '["sh","-lc","..."]'
    
    脚本嵌在 sh -lc "..." 双引号内、内部引号是转义形式 \",用带普通引号的锚点做字符串匹配会 0 命中(实测);改按行定位:找到含唯一文本的那行,沿用它的缩进与转义风格,在其后插入新行。
  • 改完先本地验证再交给调度器:把回读的 payload.argv 直接 subprocess.run(argv) 跑一遍,确认 stdout 就是预期文案。仅对 echo/print 这类无副作用的文案 payload 这样做;有副作用的 payload 不要本地执行。
  • 删除:openclaw cron rm <id>

临时改一次(某晚停用某产品、出门在外等)

只改周期任务的 payload 就完事,会一直错下去;要配一条恢复任务:

  1. openclaw cron edit <id> --command '...'command 型 payload 不能用 automations update,见「修改 / 删除」)把周期任务换成当晚版本。
  2. 回读 openclaw cron get <id> 确认文案已生效,再继续。
  3. 同期建一条一次性任务,在次日合适时间把 payload 改回标准版本。它跑在 isolated 会话、没有本次对话的记忆,所以 message 必须写全 jobId 与目标文案原文,并注明改完回读校验、成功即回 NO_REPLY
  4. 恢复任务不需要给人看:按核心规则加 --no-deliver
  5. 次日要回读确认恢复已执行:该任务跑完自删,不会留在列表里,所以要 openclaw cron get <目标 jobId> 检查周期任务文案是否已还原,再回 cron runs 看恢复任务是否 ok
  6. 一次临时改动可能同时影响多条同类任务(如修复期同时改周四、周五两条),逐条核对文案是否互相打架,别只改一条。

参考

  • 生日提醒(农历换算、每年重设、一次性任务):见 birthday-reminder skill
  • 消息发不出去 / 跨频道手动投递:见 cross-channel-send skill
  • 完整钉钉推送规范:workspace/TOOLS.md📢 钉钉推送统一规范」