--- name: remind description: > Create, list, edit, enable, disable, and remove recurring or one-time reminders. Triggers on: "/remind", "remind me", "set a reminder". --- # /remind Reminders are stored in SQLite (`db/reminders.sqlite`) and delivered by `remind_send.py`, which runs every minute from the nanobot user crontab, directly to Telegram, outside the agent. Reply to the user in their own language. ## Natural language → command mapping | User says | Command | |-----------|---------| | "every day at 9" / "every weekday at 9:30" | `add --cron "0 9 * * *"` | | "on 2026-06-15 at 18:00" / "once at …" | `add --at "2026-06-15T18:00:00"` | | "randomly 2× between 08:00 and 20:00" | `add --random-times-per-day 2 --random-window 08:00-20:00` | | "randomly 2× a week between 08:00 and 20:00" | `add --random-times-per-week 2 --random-window 08:00-20:00` | | "what reminders arrived today / since when" | `delivered [--since YYYY-MM-DD]` | | "what goes out today / tomorrow / this week" | `upcoming [--date YYYY-MM-DD \| --days N]` | | list all reminders | `list` | For the full flag reference of any command, run: ```sh uv run skills/remind/scripts/remind_cli.py --help uv run skills/remind/scripts/remind_cli.py --help ``` ## Behavioral contract **Showing read results.** `list`, `upcoming`, and `delivered` return text for the user — present it, never collapse to a count. For `list`, rewrite the raw output into a compact, readable form of your own: **one reminder per line**, schedules paraphrased to natural language (`30 9 * * 1-5` → "9:30 on weekdays"). Show **only enabled** reminders — skip disabled ones; keep each shown reminder's `#display-id` exactly as the CLI printed it (so `--id` still matches — gaps from skipped disabled ones are fine). Don't print the `[enabled]` marker. **`list`** returns readable text. Each reminder: ``` # text [enabled|disabled] cron: 0 9 * * * at: 2026-06-15T18:00:00 random: 2× daily 09:00–21:00 (1-5) from 2026-06-01 random: 2× weekly 08:00–20:00 ``` An empty store prints `(no active reminders)`. **Display IDs** (`#1`, `#2`, …) are sequential positions among active reminders, computed on the fly — never the internal DB id. They renumber after every `remove`, so always run `list` first when unsure. The internal DB id is never shown to the user; do not surface the `id` field from mutation JSON as `#…`. A weekly random schedule fires `N` times across the week (Mon–Sun) on `N` distinct random days, one random time each inside the window. `--random-days`/`--random-from`/ `--random-until` narrow the eligible days; a partial week at a from/until edge squeezes the full weekly count into the days that remain (no proration). **Mutations** (`add`, `edit`, `remove`, `enable`, `disable`) return JSON: `{"added": …}`, `{"edited": …}`, etc. Errors go to stderr with a non-zero exit code. **Selecting a reminder:** `edit`, `remove`, `enable`, `disable` accept `--keyword` (case-insensitive substring) or `--id` (the **display ID** from `list`). An ambiguous keyword match returns `{"error": "ambiguous", "matches": [{"display_id": n, "text": …}]}` — retry with `--id `. Run `list` to see current display IDs. **`delivered`** reads the `reminder_fires` table (delivered rows only, Prague local time). Defaults to today; `--since YYYY-MM-DD` widens the window. The agent never sees deliveries happen — this is the only window into them. **`upcoming`** returns readable text: each scheduled fire as `YYYY-MM-DD HH:MM #display-id text (type)`, sorted by time. The `#display-id` matches the one in `list`. It shows the *plan* (computed from the schedules), not actual deliveries — use `delivered` for those. Defaults to the rest of today; `--date` shows one whole day, `--days N` the next N calendar days. An empty window prints `(nothing scheduled in this window)`. **`remove`** is a soft delete. ## Editing reminders **To fix or change wording:** use `edit --id --text "…"` (get the display ID from `list`), or `edit --keyword --text "…"`. **NEVER remove + re-add a reminder just to change its text** — that loses the delivery history and changes the id. Use `--replace-schedules` (with at least one new `--cron`/`--at`/`--random-*`) only when you need to change the *schedule*, not the text. ## Environment - `REMIND_DB` — override SQLite path (used in tests). - Scripts run via `uv run` (PEP 723 headers declare their dependencies).