| name | schedule-reminder |
| description | Persistent store for todos, events, deadlines and progress with pending/doing/done states; fires due reminders via Discord; stable CLI/JSON API other skills call. |
schedule-reminder, the T0 schedule/memo base
Governing principle (full text in PHILOSOPHY.md): a base is the contract, not the storage.
Downstream skills depend on a frozen CLI/JSON surface, never on the database, so the engine can
change forever without breaking them. Correctness (concurrency-safe, crash-safe, backward-compatible)
beats features.
When to use / when to stop
- Use when the user wants to track a todo / event / deadline / 进度 / 提醒 / 备忘, or when another
skill (email-monitor, daily-hotspots, demand-mining, promotion-assistant) needs to write a
reminder or read task progress.
- Stop / route elsewhere: a one-off "send me a Discord message now" with nothing to persist is
just the relay, not this. This base is for state that must survive, be queried, and be reminded.
How it works (one screen)
SQLite (WAL) single file <- private storage, NEVER touched by downstream
store.py (typed functions) <- in-process, trusted skills MAY import
reminder.py <verb> <- the ONLY stable contract (JSON always); downstream calls via subprocess
[Windows task: PT5M heartbeat] -> reminder.py tick -> reconcile due items -> Discord relay (out)
[Windows task: PT10M ingest] -> ingest_tick -> poll channels for user replies -> dispatch (in)
The Agent Center bus is two-way: relay.py/digest.py push out; ingest.py/dispatch.py pull
user replies back in and turn them into pool mutations via the codex→cc→claude judge chain
(llm_chain.py). See reference/agent-center.md.
The OS task is only a heartbeat; tick reconciles the local table, so a slept/off machine catches
up all missed reminders on the next run (idempotent, at-least-once + dedupe).
Command cheat-sheet
python scripts/reminder.py init
python scripts/reminder.py add --title "买牛奶" --due-at 2026-06-28T17:00:00Z --priority 1 \
--source my-skill --idempotency-key my-skill:42 --ext '{"x_my_skill_id":"42"}'
python scripts/reminder.py get --id <ID>
python scripts/reminder.py list --active --source my-skill --limit 50
python scripts/reminder.py transition --id <ID> --to doing --progress 30
python scripts/reminder.py done --id <ID>
python scripts/reminder.py block --id <ID> --blocker-id <OTHER> --reason "waiting"
python scripts/reminder.py snooze --id <ID> --until 2026-07-01T09:00:00Z
python scripts/reminder.py due --now 2026-06-28T17:00:00Z
python scripts/reminder.py tick --now 2026-06-28T17:00:00Z
python scripts/reminder.py health
Success -> JSON on stdout with api_version, schema_version, ok:true. Failure -> JSON on stderr
with error_code + exit 1. Inject a clock with --now/SCHEDULE_NOW; isolate state with
--db/SCHEDULE_DB_PATH.
Item fields (essentials)
id (immutable UUIDv7) · kind (task|event) · title · state
(pending/doing/done/blocked/cancelled) · progress 0-100 · priority 0-9 · due_at (RFC3339 UTC) ·
tags[] · source · idempotency_key · relations[] (depends-on/...) · recurrence (RRULE ,
tick rolls to the next occurrence) · alarms[] (per-alarm lead, e.g. [{"lead":3600}] /
[{"trigger":"-PT15M"}]) · ext (unknown fields preserved, namespace x_<skill>_*). Full
table -> reference/contract.md.
Hard rules
- Downstream never reads the DB, only
reminder.py <verb> --json. (Lets the engine evolve.)
- DB stays on local NTFS, never OneDrive/GDrive/network (WAL lock + sync = corruption).
- State changes go through
transition/done/block, never update (state machine guarded).
- Always pass
--source + --idempotency-key on writes (audit + safe retries).
- Unknown fields are MUST-PRESERVE, put extras in
--ext as x_<skill>_*; the base round-trips
them.
- All time is UTC RFC3339; due trigger is the interval
now >= due_at - lead, never ==.
Progressive loading
This SKILL.md is the only always-loaded file. Load one shard on demand:
reference/contract.md, frozen verbs, fields, states, error codes, idempotency, versioning.
reference/deployment.md, DB init, heartbeat task, SQLite version, backup, secrets.
reference/integration.md, copy-paste examples for downstream skills.
reference/agent-center.md, the two-way Agent Center bus: outbound relay (relay.py) + daily
当日总结 aggregator (digest.py), and inbound ingest (ingest.py/dispatch.py/llm_chain.py) that
turns user channel replies into pool mutations. Egress + daily summary + reply ingress in one place.