Schedule usage
After the quickstart works, most Schedule code falls into four patterns: define a Static Schedule Definition, opt in Runtime Schedule targets, manage Runtime Schedule records, and attach Agent Schedules or Schedule Capability tools.
Define Static Schedules
Default-export defineSchedule({ cron, handler, allowRuntimeSchedules? }) from a discovered schedule file.
import { defineSchedule } from '@vitehub/schedule'
export default defineSchedule({
cron: '0 9 * * *',
handler: async (context) => {
console.log(context.scheduleId, context.scheduledAt)
},
})
Cron expressions are five-field UTC cron strings: minute, hour, day of month, month, and day of week.
Control Schedule Ids
By default, ids come from discovered file names:
src/daily-digest.schedule.tsbecomesdaily-digestsrc/reports/daily.schedule.tsbecomesreports/daily
Schedule v1 does not support overriding the discovered id. Keep the file path stable when Runtime Schedule targets depend on it.
// `src/reports/daily.schedule.ts` is discovered as `reports/daily`.
Allow Runtime Schedules
Runtime Schedules can only target discovered definitions that opt in:
export default defineSchedule({
allowRuntimeSchedules: true,
cron: '0 9 * * *',
handler,
})
The integration generates typed Runtime Schedule Targets from those opted-in definitions. Application code can import the generated type from the stable ViteHub import path:
import { schedules } from '@vitehub/schedule'
import type { ScheduleTargetName } from '#vitehub/schedule/targets'
const target = 'daily-digest' satisfies ScheduleTargetName
await schedules.create({
cron: '0 9 * * *',
target,
})
Runtime Schedule target names are not standalone definitions in v1. They come from Static Schedule Definitions with allowRuntimeSchedules: true.
Manage Runtime Schedules
Use schedules from @vitehub/schedule to manage recurring Runtime Schedule records:
import { schedules } from '@vitehub/schedule'
const created = await schedules.create({
cron: '0 9 * * *',
enabled: true,
id: 'daily-digest-9am',
target: 'daily-digest',
})
const all = await schedules.list()
const same = await schedules.get(created.id)
await schedules.update(created.id, {
cron: '15 9 * * *',
})
await schedules.disable(created.id)
await schedules.enable(created.id)
await schedules.delete(created.id)
Runtime Schedule records are recurring cron records. create() does not create a one-time or deferred run.
Start Automatic Execution
Runtime Schedules do not execute automatically until a process starts the Basic Self-Hosted Schedule Runner.
import { startScheduleRunner } from '@vitehub/schedule'
const runner = startScheduleRunner()
process.once('SIGTERM', () => runner.stop())
Read Boundaries before running more than one process against the same schedule store.
Use Agent Schedules
Use inline Agent Schedules when the Agent Definition itself should be invoked on recurring cron entries:
import { defineAgent, schedule } from '@vitehub/agent'
export default defineAgent({
capabilities: [
schedule({
schedules: [
'0 9 * * *',
{ cron: '0 17 * * 1-5', id: 'weekday-summary' },
],
}),
],
model,
adapter: 'ai-sdk',
})
String entries get ids from the cron expression, such as schedule-0-9. Object entries can set an explicit id.
Expose Schedule Capability Tools
Use schedule({ mode, policy }) when the model should read or manage scoped Runtime Schedules:
import { defineAgent, schedule } from '@vitehub/agent'
import type { ScheduleTargetName } from '#vitehub/schedule/targets'
export default defineAgent({
capabilities: [
schedule<ScheduleTargetName>({
mode: 'write',
policy: 'require-approval',
targets: ['daily-digest'],
}),
],
model,
adapter: 'ai-sdk',
})
mode: 'read' exposes schedule_read. mode: 'write' also exposes schedule_edit, which can create, update, enable, disable, and delete Runtime Schedules inside the target allowlist.
Self-targeting Runtime Schedules require explicit permission:
schedule({
allowSelfTarget: true,
mode: 'write',
policy: 'require-approval',
selfTarget: 'agent/digest',
targets: ['agent/digest'],
})
V1 Boundaries
Schedule v1 intentionally excludes:
everyinterval syntax.- One-time or deferred schedules.
- Timezone options beyond five-field UTC cron.
- Standalone Runtime Schedule target definitions.
- Distributed runner leases or leader election.
- Backfill.
- Configurable retry, overlap, or dedupe policy.
Use provider docs for provider-specific scheduling behavior. General Schedule code should stay provider-neutral.

