Nag — Persistent Reminders
Nag manages reminders that don't give up. Each reminder has a first-fire time, a nag window, and resets daily.
When to Use
- - Recurring daily habits (supplements, workouts, practice)
- Tasks that get ignored/forgotten without follow-up
- Anything where "remind me once" isn't enough
When NOT to Use
- - One-shot reminders ("remind me in 20 minutes") — use a cron job with INLINECODE0
- Time-critical alerts that can't wait for a heartbeat cycle
- Reminders that don't need confirmation (informational only)
Setup
1. State File
Create memory/nag-state.json in the workspace:
CODEBLOCK0
The date field triggers automatic daily resets — when today's date differs from the stored date, all reminders reset to unconfirmed.
2. Reminder Config
Create nag-config.json in the workspace root:
CODEBLOCK1
Fields:
| Field | Required | Description |
|---|
| INLINECODE3 | yes | Unique identifier, used as key in state file |
| INLINECODE4 |
yes | Human-readable name for display |
|
cronFirst | yes | Cron expression for initial reminder (create a cron job for this) |
|
nagAfter | yes | Time (HH:MM, 24h) after which heartbeat nags begin |
|
confirmPatterns | yes | Array of phrases that mark the reminder as done (case-insensitive, substring match) |
|
tone | no | Personality guidance for generating nag messages. If absent, use a neutral friendly tone. The model has creative liberty to vary the wording each nag. |
|
messages.first | no | Text sent by the cron job for the initial reminder. If absent, generate from label + tone. |
|
messages.nag | no | Suggested nag text. If absent, generate contextually from label + tone + nagCount. |
|
messages.escalate | no | Suggested text after 3+ ignored nags. If absent, generate with increased urgency from tone. |
|
days | no | Array of weekday names to restrict when this reminder fires (e.g.
["monday", "wednesday", "friday"]). Omit for every day. |
For more examples, see references/config-examples.md.
Message generation: When messages.nag or messages.escalate are absent, generate them on the fly using the label and tone fields. Vary the wording each time — don't repeat the same nag verbatim. Use nagCount to calibrate urgency: low count = gentle, 3+ = escalated.
3. Wire Up Cron + Heartbeat
For each reminder, create a cron job that fires messages.first at the cronFirst schedule.
In HEARTBEAT.md, add a nag check block:
CODEBLOCK2
4. Confirmation Handling
When the user sends a message matching any confirmPatterns for a reminder, update memory/nag-state.json:
CODEBLOCK3
Match confirmation by checking if any pattern appears as a substring (case-insensitive) in the user's message. When ambiguous (multiple reminders could match), match the one currently in its nag window.
Adding a New Reminder
- 1. Add entry to INLINECODE22
- Create a cron job for the
cronFirst schedule - The heartbeat nag block handles everything else automatically
Removing a Reminder
- 1. Remove entry from INLINECODE24
- Remove or disable the corresponding cron job
- Optionally clean up its key from INLINECODE25
Nag — 持久提醒
Nag 管理那些不会放弃的提醒。每个提醒都有首次触发时间、提醒窗口,并且每天重置。
何时使用
- - 重复的日常习惯(补充剂、锻炼、练习)
- 那些没有跟进就会被忽略/遗忘的任务
- 任何提醒我一次不够用的情况
何时不使用
- - 一次性提醒(20分钟后提醒我)——请使用带有 schedule.kind: at 的定时任务
- 不能等待心跳周期的时间关键型警报
- 不需要确认的提醒(仅作信息参考)
设置
1. 状态文件
在工作区中创建 memory/nag-state.json:
json
{
date: 2026-02-15,
reminders: {}
}
日期字段会触发自动每日重置——当今天的日期与存储的日期不同时,所有提醒都会重置为未确认状态。
2. 提醒配置
在工作区根目录创建 nag-config.json:
json
{
reminders: [
{
id: morning-supplements,
label: 早晨补充剂,
cronFirst: 0 8 *,
nagAfter: 09:00,
confirmPatterns: [已服用, 已完成, 吃过了, 做完了, 是的],
tone: 友好但坚持,3次提醒后升级为全大写戏剧化风格,
messages: {
first: 该吃早晨补充剂了!
}
}
]
}
字段说明:
| 字段 | 必填 | 描述 |
|---|
| id | 是 | 唯一标识符,用作状态文件中的键 |
| label |
是 | 用于显示的人类可读名称 |
| cronFirst | 是 | 首次提醒的 Cron 表达式(为此创建一个定时任务) |
| nagAfter | 是 | 心跳提醒开始的时间(HH:MM,24小时制) |
| confirmPatterns | 是 | 标记提醒已完成的关键词数组(不区分大小写,子串匹配) |
| tone | 否 | 生成提醒消息的个性指导。如果缺失,使用中性友好的语气。模型可以自由发挥,每次提醒变换措辞。 |
| messages.first | 否 | 定时任务发送的首次提醒文本。如果缺失,根据 label + tone 生成。 |
| messages.nag | 否 | 建议的提醒文本。如果缺失,根据 label + tone + nagCount 上下文生成。 |
| messages.escalate | 否 | 3次以上被忽略提醒后的建议文本。如果缺失,根据 tone 以更高紧迫性生成。 |
| days | 否 | 限制提醒触发的星期名称数组(例如 [monday, wednesday, friday])。省略则每天触发。 |
更多示例请参见 references/config-examples.md。
消息生成: 当 messages.nag 或 messages.escalate 缺失时,使用 label 和 tone 字段即时生成。每次变换措辞——不要逐字重复相同的提醒。使用 nagCount 校准紧迫性:低次数 = 温和,3次以上 = 升级。
3. 连接定时任务 + 心跳
为每个提醒创建一个定时任务,在 cronFirst 调度时间触发 messages.first。
在 HEARTBEAT.md 中添加提醒检查块:
提醒检查
读取 nag-config.json 和 memory/nag-state.json。
对于 nag-config.json 中的每个提醒:
- - 如果状态中的日期与今天不同,重置所有提醒(设置 confirmed: false, nagCount: 0)。
- 如果今天的星期不在提醒的 days 数组中(如果指定了),则跳过。
- 如果当前时间在 nagAfter 之后且 confirmed 为 false:向用户发送提醒消息。
- 根据提醒的 label 和 tone 生成消息(如果提供了 messages.nag 则使用它)。
- 如果 nagCount >= 3,升级紧迫性(如果提供了 messages.escalate 则使用,否则以更高强度生成)。
- 在状态中递增 nagCount。
4. 确认处理
当用户发送的消息匹配某个提醒的任何 confirmPatterns 时,更新 memory/nag-state.json:
json
{
date: 2026-02-15,
reminders: {
morning-supplements: {
confirmed: true,
confirmedAt: 09:06,
nagCount: 1
}
}
}
通过检查用户消息中是否包含任何模式(不区分大小写,子串匹配)来匹配确认。当存在歧义时(多个提醒可能匹配),匹配当前处于提醒窗口中的那个。
添加新提醒
- 1. 在 nag-config.json 中添加条目
- 为 cronFirst 调度创建一个定时任务
- 心跳提醒块会自动处理其他所有内容
移除提醒
- 1. 从 nag-config.json 中移除条目
- 移除或禁用对应的定时任务
- 可选:从 memory/nag-state.json 中清理其键