| name | reminder |
| description | Set reminders and manage todos with natural language. Uses built-in cron scheduling, no external service needed. |
| version | 1.0.0 |
| metadata | {"echo":{"tags":["Reminder","Todo","Schedule","Cron","Productivity"]}} |
Reminder
Set timed reminders and manage todos.
IMPORTANT: how a reminder actually fires
A row in reminders.db is just a note — nothing scans it or delivers it. To make
a reminder that actually fires and gets delivered, you MUST create a scheduled
job with the cronjob tool, which persists to the scheduler and is delivered
through the active channel by Echo Agent's scheduler service:
cronjob(action="create", name="weekly-report",
schedule="0 9 * * 1", command="提醒你写周报")
The reminder_store.py script below is only a lightweight local note-taking
list (list/done/delete). It has NO delivery path on its own. If the user wants
to be reminded at a time, use cronjob — optionally also recording a note via
the script. For a background one-off that must take effect, spawn_task can run
the cronjob call for you.
Jobs that produce a file (audio/image/document)
When the scheduled command generates an artifact the user must receive (e.g. a
voice briefing), make the delivery happen inside the same tool call — do not
assume a later step will send it. For audio use text_to_speech(..., deliver=true)
(see the tts-voice skill); for other files call send_file explicitly with the
target channel/chat. An unattended cron run may end right after producing the
file, so "generate then hope it gets sent" silently drops the artifact.
After creating a job: confirm, then stop
Once cronjob(action="create") returns, you are done. Send the user ONE
confirmation with the concrete facts and end the turn:
- job id, the schedule, and the next fire time (from the create result)
- if a delivery target was inferred, say so; if the create result carried the
"⚠️ 无法确定投递目标" warning, relay it and ask for target_channel/target_chat_id.
Do NOT try to "prove delivery works" by exercising the agent's own plumbing —
reading gateway/server.py, a2a/server.py, or curling internal endpoints like
/v1/chat or /api/v1/message is not verification, it's a rabbit hole that
burns the turn and leaves the user with no reply. If you genuinely need to sanity
-check the schedule, use cronjob(action="list"); trigger a real run at most
once and only if the user asked. The scheduled job itself is the delivery test —
it will fire on schedule.
Quick Commands
| Action | Example |
|---|
| Set reminder | "提醒我明天9点开会" |
| Recurring | "每周一早上8点提醒我写周报" |
| List | "显示我的所有提醒" |
| Complete | "完成提醒 #3" |
| Delete | "删除提醒 #5" |
Time Parsing
Natural language to cron expression mapping. Feed the resulting expression into
the cronjob tool's schedule argument:
| Input | Cron Expression |
|---|
| 明天9点 | 0 9 {tomorrow} * * |
| 每天早上8点 | 0 8 * * * |
| 每周一 | 0 9 * * 1 |
| 每月1号 | 0 9 1 * * |
| 2小时后 | one-shot timer |
| 工作日下午5点 | 0 17 * * 1-5 |
Local note storage (no delivery)
The script keeps a local note list in SQLite: ~/.echo-agent/reminders.db.
This is bookkeeping only — creating a row here does NOT schedule or deliver
anything. Timed delivery is the cronjob tool's job (see top of this doc).
CREATE TABLE reminders (
id INTEGER PRIMARY KEY,
content TEXT NOT NULL,
cron_expr TEXT,
next_fire DATETIME,
is_recurring BOOLEAN DEFAULT 0,
is_done BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Script Usage (local notes only — does not schedule delivery)
python3 scripts/reminder_store.py add "写周报" --cron "0 9 * * 1"
python3 scripts/reminder_store.py list
python3 scripts/reminder_store.py done 3
python3 scripts/reminder_store.py delete 5
python3 scripts/reminder_store.py due
Delivery
Delivery is handled by the scheduler, not by this script. When you create a job
with the cronjob tool, the scheduler fires it on schedule and routes the
message through the active channel (Telegram/WeChat/etc). The reminder_store.py
script never delivers anything by itself.