vylepseni /remind skill

This commit is contained in:
lachtan
2026-06-10 07:19:24 +02:00
parent 0b80827d4b
commit fd8a2cd543
4 changed files with 37 additions and 792 deletions

View File

@@ -1,92 +1,68 @@
---
name: remind
description: >
Create, list, edit, enable, disable, and remove recurring or one-time reminders.
Triggers on: "/remind", "remind me", "set a reminder".
---
# /remind
Create, list, edit, enable, disable, and remove recurring or one-time reminders.
## How it works
- **Storage**: SQLite (`db/reminders.sqlite`) — atomic transactions, no YAML races.
- **Schema**: `reminders` (text, enabled, timezone, timestamps, soft-delete) + `schedule_at` / `schedule_cron` / `schedule_random` + `reminder_fires` (dedup + audit).
- **Sender**: `remind_send.py` runs every minute from the user crontab. Reads SQLite, finds due fires, sends to Telegram, logs delivery.
- **Deduplication**: Every delivery is recorded in `reminder_fires` with status `delivered`/`failed`. One-time `at` reminders fire exactly once; cron and random fire once per computed slot.
- **Audit**: All mutations and deliveries are logged to `log/reminder.log`.
## Commands
### Create a reminder
### Create
```
/remind drink water every day at 9:00
/remind stand up every weekday at 9:30
/remind buy milk at 2026-06-15T18:00
/remind stretch randomly 2 times between 08:00 and 20:00
/remind občanka pana Přibyla once daily at random time between 8:00 and 21:00
/remind <text> every day at 9:00
/remind <text> every weekday at 9:30
/remind <text> at 2026-06-15T18:00
/remind <text> randomly 2 times between 08:00 and 20:00
/remind <text> once daily at random time between 8:00 and 21:00
```
The LLM parses natural language and calls `remind_edit.py add` with the appropriate flags:
Parse natural language, then call `remind_edit.py add` with flags:
- `--text "..."`
- `--cron "0 9 * * *"` (repeatable)
- `--at "2026-06-15T18:00:00"` (repeatable)
- `--random-times-per-day N --random-window HH:MM-HH:MM [--random-days DOW] [--random-from YYYY-MM-DD] [--random-until YYYY-MM-DD]`
### List reminders
### List
```
/remind list
```
Call `remind_edit.py list` → JSON with all active reminders.
Calls `remind_edit.py list` → JSON with all active reminders and their schedules.
### Edit a reminder
### Edit
```
/remind edit keyword --text "new text"
/remind edit keyword --replace-schedules --cron "0 10 * * *"
/remind edit <keyword> --text "new text"
/remind edit <keyword> --replace-schedules --cron "0 10 * * *"
```
Calls `remind_edit.py edit --keyword <keyword>`. Keyword is matched case-insensitively against reminder text. Ambiguous matches are rejected.
Call `remind_edit.py edit --keyword <keyword>`. Keyword matches case-insensitively against reminder text. Ambiguous matches are rejected.
### Enable / Disable
```
/remind disable keyword
/remind enable keyword
/remind disable <keyword>
/remind enable <keyword>
```
### Remove a reminder
### Remove
```
/remind remove keyword
/remind remove <keyword>
```
Soft delete. Hard delete only via direct DB access.
Soft delete (sets `deleted_at`). Hard delete happens only via direct DB access.
## Scripts
## Files
| Action | Command |
|--------|---------|
| list | `uv run skills/remind/scripts/remind_edit.py list` |
| add | `uv run skills/remind/scripts/remind_edit.py add --text "..." ...` |
| edit | `uv run skills/remind/scripts/remind_edit.py edit --keyword <kw> ...` |
| remove | `uv run skills/remind/scripts/remind_edit.py remove --keyword <kw>` |
| enable | `uv run skills/remind/scripts/remind_edit.py enable --keyword <kw>` |
| disable | `uv run skills/remind/scripts/remind_edit.py disable --keyword <kw>` |
| File | Purpose |
|------|---------|
| `skills/remind/scripts/db.py` | Schema, connection factory (`get_db`), `init_db()`, audit `log_operation()` |
| `skills/remind/scripts/remind_edit.py` | CRUD CLI: `list`, `add`, `remove`, `edit`, `enable`, `disable` |
| `skills/remind/scripts/remind_send.py` | Sender: reads SQLite, finds due fires, sends Telegram, dedups |
| `skills/remind/scripts/random_times.py` | Deterministic random time generator (seeded by text + date) |
| `scripts/migrate_yaml_to_sqlite.py` | One-shot migration from old `reminder.yaml` to SQLite |
| `skills/remind/tests/` | pytest suite: `test_db.py`, `test_remind_edit.py`, `test_remind_send.py`, `test_random_times.py` |
## Crontab
```
* * * * * uv run /home/nanobot/.nanobot/workspace/skills/remind/scripts/remind_send.py >> /home/nanobot/.nanobot/workspace/log/reminder_cron.log 2>&1
```
Sender runs every minute from crontab: `uv run skills/remind/scripts/remind_send.py`
## Environment
- `REMIND_DB` — override SQLite path (used in tests).
- `python3` is required; `python` is not available in this runtime.
## Design decisions
- **SQLite WAL mode** — readers don't block writers.
- **Soft delete** — preserves history and foreign-key integrity.
- **Deterministic random** — same text + date always yields same times, so dedup works across restarts.
- **JSON output** — both edit and send scripts emit structured JSON for easy LLM parsing.
- **No YAML** — eliminated race conditions, manual string construction, and fragile parsing.
- `python3` required; `python` unavailable.