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
Related
- Mission system (missions can be woken on a schedule)
- Task board (schedules can create tasks rather than raw messages)
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
0 2 * * *)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
server.tsalongside frontend init)nextRunAt <= nowlastRunAt, computesnextRunAtfor recurring schedulesTimezone support
IANA timezone names (e.g.
America/New_York) for cron evaluation. UTC default.Stagger window
Optional
staggerSecto randomize fire time within a window — avoids thundering herd if multiple schedules fire at the same cron tick.Storage
New
schedulestable 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
Related