Skip to content

feat: add scheduled tasks / cron system#63

Merged
priyanshujain merged 29 commits intomasterfrom
feat-scheduled-tasks
Mar 12, 2026
Merged

feat: add scheduled tasks / cron system#63
priyanshujain merged 29 commits intomasterfrom
feat-scheduled-tasks

Conversation

@priyanshujain
Copy link
Copy Markdown
Collaborator

Summary

  • Add a scheduled tasks system supporting recurring (cron) and one-shot schedules
  • Scheduled tasks run as headless agents with full tool access, delivering results via Telegram or Slack
  • Uses robfig/cron/v3 for recurring schedules and a 30s poll loop for one-shot tasks
  • River job queue handles execution with 1 retry after 15 min; final failures notify the user
  • Daemon reloads schedules from DB every 60s to pick up changes from agent tools

New components

  • source/scheduler/ — Types, schema (SQLite + Postgres), and CRUD store
  • channel/push*.goPusher interface with Telegram and Slack implementations + factory
  • agent/tools/auto_approve.goAutoApproveInteractor for headless task execution
  • agent/tools/schedule.gocreate_schedule, list_schedules, delete_schedule tools
  • daemon/scheduler.go — Core scheduler with cron engine, one-shot polling, and DB reload
  • daemon/jobs/scheduled_task.go — River worker that runs agents and pushes results
  • skills/schedule-task/ — Skill definition and reference docs

Modified files

  • config/config.goSchedulerConfig, DSN helper, defaults
  • daemon/river.go — Register ScheduledTaskWorker
  • daemon/daemon.go — Wire scheduler start/stop into daemon lifecycle
  • agent/tools/prompt.go — Conditional "Scheduled Tasks" system prompt section
  • channel/telegram/session.go — Register schedule tools in Telegram agent
  • channel/telegram/telegram.go — Add ChatID() accessor
  • internal/server/server.go — Add scheduler migration to startup

Validations

  • Timezone validation via time.LoadLocation()
  • Cron expression validation; minimum 1-hour frequency enforced
  • One-shot scheduled_at must be in the future
  • Min frequency checked both at tool level and scheduler load level

Test plan

  • source/scheduler/ — Types JSON round-trip, schema migration, full CRUD round-trip, ListDueOneShot with past/future, MarkCompleted
  • agent/tools/ — Create recurring/one-shot, invalid timezone, too-frequent cron, past one-shot, list + delete round-trip
  • agent/tools/ — AutoApproveInteractor returns true
  • daemon/ — isValidFrequency, loadSchedules add/remove entries, one-shot integration test
  • daemon/jobs/ — ScheduledTaskArgs Kind() and JSON serialization
  • channel/ — Pusher interface compliance, factory error for unsupported channel
  • All existing tests continue to pass (go test ./... — only pre-existing external API failures)

Allows tests to inject mock pushers and custom agent runners
without requiring real Telegram/Slack bots or config-based LLM setup.
Prevents double-completion race between pollOneShot and the worker.
The scheduler now only disables the schedule; the worker marks it
completed after successful execution.
…ding

Pusher creation and push failures now return errors so River can
retry the job, and record the error in last_run.
…anSchedule

Previously parseTime silently returned nil on unparseable strings and
channel_meta unmarshal errors were ignored.
Use parameterized queries instead of literal 1/0 for the enabled
column, and scan via interface{} to handle both SQLite INTEGER and
Postgres BOOLEAN types.
…round

Ensures cron-triggered job inserts respect shutdown signals.
@priyanshujain priyanshujain merged commit 14eaee0 into master Mar 12, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant