Skip to content

feat: Schedules — cron, interval, and once-off triggers for sessions #54

Description

@saucam

Summary

Add a schedule system so agents can be triggered autonomously on a cron, interval, or one-shot basis — without a human sending a message. This enables use cases like "run the nightly code health check at 2am", "poll CI every 15 minutes after a push", or "run the migration script once at 08:00 on Monday".

Background

Currently codeoid is entirely reactive — an agent only does work when a human sends a message or when an external hook fires. Schedules make agents proactive actors, which is fundamental to autonomous coding workflows.

Proposed Design

Schedule types

  • cron — standard cron expression (e.g. 0 2 * * *)
  • interval — repeat every N seconds/minutes/hours
  • once — fire at a specific timestamp, then expire

Schedule definition

```typescript
interface Schedule {
id: string
name: string
sessionName: string // which named session to wake
taskMode: 'message' | 'task' | 'mission'
message?: string // for taskMode=message: the prompt to send
taskPrompt?: string // for taskMode=task: creates a Task entry
missionId?: string // for taskMode=mission: wakes the mission session
scheduleType: 'cron' | 'interval' | 'once'
cron?: string // for cron type
intervalMs?: number // for interval type
runAt?: number // for once type
timezone?: string // IANA timezone for cron evaluation
status: 'active' | 'paused' | 'completed' | 'archived'
lastRunAt?: number
nextRunAt?: number
createdAt: number
}
```

Runtime

  • A scheduler loop runs inside the daemon (started in server.ts alongside frontend init)
  • Evaluates all active schedules every 60 seconds
  • Fires any schedule whose nextRunAt <= now
  • Sends a message to the named session (creating it if it doesn't exist, resuming if it does)
  • Updates lastRunAt, computes nextRunAt for recurring schedules

Timezone support

IANA timezone names (e.g. America/New_York) for cron evaluation. UTC default.

Stagger window

Optional staggerSec to randomize fire time within a window — avoids thundering herd if multiple schedules fire at the same cron tick.

Storage

New schedules table in SQLite. The daemon reads it on startup and maintains in-memory state for the scheduler loop.

CLI additions

```
codeoid schedule create --session --cron "0 2 * * *" --message "run nightly check"
codeoid schedule create --session --interval 900 --message "poll CI"
codeoid schedule create --session --at "2026-07-05T08:00:00" --message "run migration"
codeoid schedule ls
codeoid schedule pause
codeoid schedule resume
codeoid schedule destroy
```

Acceptance criteria

  • Schedule CRUD in SQLite
  • Scheduler loop fires schedules within ±5s of their target time
  • Cron, interval, and once-off types all work with correct next-run computation
  • IANA timezone support for cron
  • Session is created if it doesn't exist, resumed if it does
  • Paused/archived schedules are not evaluated
  • CLI for full lifecycle management
  • Web UI: schedule list with next-run time, last-run status
  • Mission integration: schedules can trigger a mission session wake

Related

  • Mission system (missions can be woken on a schedule)
  • Task board (schedules can create tasks rather than raw messages)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions