feat(services): cron-based scheduling with natural language conversion#41
Merged
Conversation
New module services/cron.py with CronSchedule dataclass (is_overdue, validate), interval_days_to_cron() converter, and nl_to_cron() for natural language schedule parsing (daily, weekly, monthly, weekdays, day names, "every N days/hours", time extraction). Add croniter>=2.0,<3 dependency for cron expression evaluation.
…allback Add cron_expr field to ScheduledJob — when set, is_overdue() delegates to CronSchedule instead of timedelta comparison. Add resolve_cron_expr() that accepts explicit cron, natural language schedule, or falls back to interval_days_to_cron(). LoopsConfig gains insight_schedule, evolution_schedule, procedural_schedule fields (empty = derive from interval_days). CLI job creation wired through resolve_cron_expr(). Old interval_days configs preserved for backward compatibility.
31 tests across 5 classes: CronSchedule validation and overdue checks (5), nl_to_cron natural language patterns (14), interval_days_to_cron conversion (5), resolve_cron_expr fallback chain (4), and ScheduledJob cron_expr integration with interval fallback (3).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the rigid
interval_daysscheduling with cron expression support and a natural language schedule converter, inspired by SivaRamSV/paaw'sJobCreatorNL-to-cron pattern. Users can now configure loop schedules as cron expressions ("0 9 * * 1-5") or natural language ("every monday at 9am","weekdays","every 3 days"), with automatic fallback to the existinginterval_daysfor backward compatibility.Schedule Resolution Chain
Supported Natural Language Patterns
"daily"/"every day"0 0 * * *"weekly"/"every week"0 0 * * 0"monthly"0 0 1 * *"every monday"/"every fri"0 0 * * 1/0 0 * * 5"weekdays"0 0 * * 1-5"weekends"0 0 * * 0,6"every 3 days"0 0 */3 * *"every 4 hours"0 */4 * * *"daily at 9:30 AM"30 9 * * *"every monday at 3pm"0 15 * * 1Time extraction (
at HH:MM AM/PM) combines with any day pattern.Changes
New Files
src/vaultmind/services/cron.py(172 lines) —CronSchedulefrozen dataclass withis_overdue()andvalidate()methods.interval_days_to_cron()for integer-to-cron conversion.nl_to_cron()regex-based NL parser supporting 10+ patterns with time extraction. Pure pattern matching, no LLM costtests/test_cron.py(205 lines) — 31 tests across 5 classesModified Files
pyproject.toml— Addedcroniter>=2.0,<3dependencyuv.lock— Updated with croniter + pytzsrc/vaultmind/services/scheduler.py— Addedcron_expr: str = ""field toScheduledJob.is_overdue()delegates toCronSchedule.is_overdue()whencron_expris set, falls back to timedelta comparison otherwise. Addedresolve_cron_expr(schedule, interval_days)module-level function implementing the resolution chainsrc/vaultmind/config.py— Addedinsight_schedule,evolution_schedule,procedural_schedulefields toLoopsConfig(all default""= derive frominterval_days)config/default.toml— Expanded[loops]section with schedule fields alongside existing interval_dayssrc/vaultmind/cli.py— Updated insight_loop, evolution_loop, and procedural_loop job creation to callresolve_cron_expr()and passcron_exprtoScheduledJobBackward Compatibility
interval_daysconfigs continue to work —schedule=""triggers automatic conversionScheduledJobintervalfield preserved;cron_expris additive and takes priority only when non-emptyScheduledJob(name=..., interval=..., execute=...)still worksScheduledJob.legacy()factory unmodifiedNew Dependency
croniter>=2.0,<3— production-ready cron expression evaluator, widely used, lightweight (only pullspytz)Test plan
test_cron.pyacross 5 classes:ruff check— cleanmypy --ignore-missing-imports— cleaninsight_schedule = "every monday at 9am"triggers correctly in botinterval_daysfallback produces identical behavior to pre-change