feat: cron job system for Inara (remind + note types)

- cron_runner.py: job storage (CRONS.json), schedule parsing, execution
- tools/cron.py: cron_list/add/remove/toggle + reminders_clear tools
- scheduler.py: load user crons at startup, expose get_scheduler() for
  live add/remove without restarts
- context_loader.py: auto-include REMINDERS.md in system prompt (tier 2+)
  so cron reminders surface automatically without Inara having to poll
- inara/CRONS.json + REMINDERS.md: backing files (initially empty)

Schedule formats: hourly | daily | daily:HH:MM | weekly:DOW | weekly:DOW:HH:MM
Job types: remind (→ REMINDERS.md) | note (→ SCRATCH.md)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-20 21:17:49 -04:00
parent 1b32667872
commit 6316ffa1d4
7 changed files with 510 additions and 10 deletions

View File

@@ -57,7 +57,15 @@ def load_context(
if help_path.exists():
parts.append(f"--- HELP.md ---\n{help_path.read_text()}")
# ── 4. Tiered memory — long → mid → short ─────────────────────
# ── 4. Pending reminders (tier 2+) ────────────────────────────
# Written by cron jobs; cleared by Inara after acting on them.
reminders_path = inara_dir / "REMINDERS.md"
if reminders_path.exists() and reminders_path.stat().st_size > 10:
content = reminders_path.read_text().strip()
if content:
parts.append(f"--- REMINDERS.md ---\n{content}")
# ── 5. Tiered memory — long → mid → short ─────────────────────
# Short is last so it sits closest to the conversation turn.
if include_long:
# Fall back to legacy MEMORY.md during/after migration
@@ -81,7 +89,7 @@ def load_context(
if "Not yet populated" not in content:
parts.append(f"--- MEMORY_SHORT.md ---\n{content}")
# ── 5. Raw session logs (tier 3+) ──────────────────────────────
# ── 6. Raw session logs (tier 3+) ──────────────────────────────
if tier >= 3:
sessions_dir = inara_dir / "sessions"
if sessions_dir.exists():