Repository navigation
v0.9.0
What's New
⏰ Cron System — Scheduled Agent Autonomy
The headline feature of v0.9.0 is the Cron System, giving the MsClaw agent the ability to self-program recurring and one-shot work on a schedule — without human initiation.
Architecture highlights:
- CronEngine —
IHostedServicewith a 2-secondPeriodicTimerthat evaluates due jobs and dispatches to the appropriate executor. - CronToolProvider — 7 bundled tools (
cron_create,cron_list,cron_get,cron_update,cron_delete,cron_pause,cron_resume) registered viaIToolProvider, always visible in every session. - PromptJobExecutor — creates isolated LLM sessions per execution via
SessionPool. Each run gets a freshcron:{jobId}:{runId}session with full tool access. - CommandJobExecutor — runs shell commands via
Process.Start()with timeout enforcement. No LLM session, no token cost. - CronJobStore — in-memory
ConcurrentDictionarycache with atomic write-temp-then-rename persistence to~/.msclaw/cron/jobs.json. - ICronJobExecutor — pluggable executor abstraction. Adding a new job type requires only a new executor and payload variant — zero engine changes.
📅 Three Schedule Types
- One-shot — "Remind me in 20 minutes" fires once and finalizes
- Fixed interval — "Check every 30 minutes" fires repeatedly
- Cron expression — "Weekdays at 9am EST" →
0 9 * * 1-5with IANA timezone support via Cronos
🛡️ Reliability
- Transient/permanent error classification via
ICronErrorClassifier— exponential backoff (30s → 1m → 5m → 15m → 60m) on transient errors, immediate finalization on permanent errors - Atomic persistence — write-temp-then-rename prevents corruption on crash
- Overdue-on-startup — jobs that missed their window during downtime fire on the first engine tick
- Concurrency control — configurable limit (default: serial execution) prevents runaway parallel jobs
🎨 UI Integration
Cron job results now appear as purple-striped entries in the browser activity sidebar. Click to expand the full CronRunEvent JSON payload.
📐 Design Refinements
ICronRunHistoryStoresplit fromICronJobStoreper Interface Segregation Principle — consumers inject only the interface they needCronJobLifecycleextracted as a pure static helper for state transitions (success/failure/backoff), independently testable from the engineICronOutputSinkdecouples the engine from SignalR — future sinks (file logging, webhooks) require no engine changesCronStaggerCalculatorapplies deterministic per-job offsets to prevent load spikes from jobs at common times
📊 By the Numbers
- 77 tasks across 6 implementation phases (50 test, 27 impl)
- 19 source files in
Services/Cron/ - 11 test files with full unit test coverage
- Built with strict TDD (red → green → refactor) throughout
Full Changelog: v0.8.0...v0.9.0
