@mastra/core
Version:
201 lines (147 loc) • 9.05 kB
Markdown
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
# Schedules
**Added in:** `@mastra/core@1.50.0`
> **Beta:** This feature is in beta. Breaking changes may occur without a major version bump until the API is stable.
A schedule runs an agent on a cron cadence. On each fire, Mastra sends a prompt to the agent, either as a [signal](https://mastra.ai/docs/long-running-agents/signals) into a thread or as a threadless [`agent.generate()`](https://mastra.ai/reference/agents/generate) run. Use schedules for recurring agent work such as daily summaries, periodic checks, or scheduled nudges into a conversation.
Schedules are persisted, so they survive restarts and redeploys. Manage them at runtime through [`mastra.schedules`](https://mastra.ai/reference/schedules/overview), the canonical create, read, update, and delete (CRUD) surface. The same surface also manages [workflow schedules](https://mastra.ai/docs/workflows/scheduled-workflows) (pass `workflowId` instead of `agentId` to schedule a workflow).
> **Note:** Schedules require a [storage](https://mastra.ai/docs/memory/storage) adapter that implements the schedules domain. See the [`mastra.schedules` reference](https://mastra.ai/reference/schedules/overview) for supported adapters and API behavior.
## Quickstart
The following schedule runs the `pinger` agent every hour. It has no thread, so each fire is an isolated `agent.generate()` run.
```typescript
import { Mastra } from '@mastra/core'
import { Agent } from '@mastra/core/agent'
import { LibSQLStore } from '@mastra/libsql'
const pinger = new Agent({
id: 'pinger',
name: 'Pinger',
instructions: 'Report the current system status in one sentence.',
model: 'openai/gpt-5.5',
})
const mastra = new Mastra({
agents: { pinger },
storage: new LibSQLStore({ url: 'file:./mastra.db' }),
})
await mastra.schedules.create({
agentId: 'pinger',
cron: '0 * * * *',
prompt: 'Give me a status update.',
})
```
Mastra starts the scheduler the first time a schedule is created, then fires the agent on the cron you specify.
## Cadence
Schedules fire on a cron expression. The `cron` field accepts a standard 5-, 6-, or 7-part cron expression, and it's validated when you create or update the schedule.
`croner` nicknames also work, for example `@hourly`, `@daily`, `@weekly`, `@monthly`, and `@midnight`. For day-and-time combinations, write the cron field directly:
```typescript
// Every weekday at 9am
await mastra.schedules.create({
agentId: 'pinger',
cron: '0 9 * * 1-5',
prompt: 'Start-of-day check.',
})
```
Set `timezone` to an IANA timezone, for example `America/New_York`, so fire times don't depend on the host's locale. When omitted, the cron resolves against the host's local timezone.
For more readable cron construction, you can use a userland builder such as [`cron-time-generator`](https://www.npmjs.com/package/cron-time-generator) and pass its output to `cron`.
## Threadless and threaded schedules
An agent schedule fires in one of two modes, decided by whether you pass a `threadId`.
### Threadless
Without a `threadId`, each fire is an isolated `agent.generate()` run. Nothing is written to a conversation thread. This is the simplest mode and suits status checks, reports, and other work that doesn't need conversation context.
### Threaded
With a `threadId`, the schedule sends a [signal](https://mastra.ai/docs/long-running-agents/signals) into that thread, so the prompt joins the agent's conversation. Threaded schedules require a `resourceId` alongside the `threadId`.
```typescript
await mastra.schedules.create({
agentId: 'pinger',
cron: '0 9 * * *',
prompt: 'Summarize anything new since yesterday.',
threadId: 'thread-123',
resourceId: 'user-456',
})
```
Threaded schedules accept extra fields that control how the signal behaves, including the signal type, XML tag, tag attributes, and active-or-idle delivery behavior. They mirror the options [`agent.sendSignal()`](https://mastra.ai/docs/long-running-agents/signals) accepts and stay JSON-serializable so they persist with the schedule.
These fields require a `threadId`. For the full threaded input shape, see the [agent schedule input reference](https://mastra.ai/reference/schedules/overview).
```typescript
await mastra.schedules.create({
agentId: 'pinger',
cron: '0 9 * * *',
prompt: 'Summarize anything new since yesterday.',
threadId: 'thread-123',
resourceId: 'user-456',
tagName: 'check-in', // renders as <check-in>…</check-in>
attributes: { source: 'cron' },
ifActive: { behavior: 'discard' }, // skip if the thread is mid-stream
ifIdle: {
behavior: 'wake', // wake the agent if the thread is idle
streamOptions: { requestContext: { locale: 'en-US' } },
},
})
```
`providerOptions` are merged into the signal payload on every fire and apply to both threaded and threadless schedules.
## Managing schedules
Use `mastra.schedules` for all schedule operations. The service can create, read, update, pause, resume, manually run, and delete schedules.
```typescript
const schedule = await mastra.schedules.create({
agentId: 'pinger',
cron: '0 * * * *',
prompt: 'Status check.',
})
await mastra.schedules.pause(schedule.id)
await mastra.schedules.resume(schedule.id)
await mastra.schedules.run(schedule.id) // Fire once now, off-schedule
```
`pause` and `resume` are durable. `run` fires the schedule once immediately without affecting its cadence. For the complete method list, filters, and patch fields, see the [`mastra.schedules` reference](https://mastra.ai/reference/schedules/overview).
### Workflow schedules
The same service creates schedules that run a workflow instead of an agent. Pass `workflowId` and the workflow-shaped fields:
```typescript
await mastra.schedules.create({
workflowId: 'daily-report',
cron: '0 9 * * *',
inputData: { userId: 'system' },
})
```
Workflow schedules created this way are independent of the declarative `schedule` field on `createWorkflow` — see [scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows) for the declarative form and Studio views.
### Custom IDs
Pass `id` when you need a predictable handle to look up, update, or delete later.
```typescript
await mastra.schedules.create({
id: 'nightly-summary',
agentId: 'pinger',
cron: '0 9 * * *',
prompt: 'Summarize anything new since yesterday.',
})
```
See the [`create(input)` reference](https://mastra.ai/reference/schedules/overview) for ID normalization rules and duplicate ID behavior.
### From the client
The same operations are available from `@mastra/client-js` over the `/api/schedules` routes, so you can manage schedules from a separate process or a UI. See the [client-js agent schedules reference](https://mastra.ai/reference/client-js/agents) for the client method list.
## Lifecycle hooks
Hooks let you run code at key points in an agent schedule's lifecycle, for example to compute fire-time parameters or react to the outcome. Configure them on the `Mastra` constructor under `schedules`. The hooks are a single flat bundle that runs for every agent's schedules; each hook context carries the firing `agentId`, so branch on it when you need per-agent behavior. Hooks live at the `Mastra` level so they apply to both code-defined and stored agents.
```typescript
const mastra = new Mastra({
agents: { pinger },
storage: new LibSQLStore({ url: 'file:./mastra.db' }),
schedules: {
prepare: async ({ agentId, schedule, trigger }) => {
// Return overrides, null to skip this fire, or undefined for defaults
return { prompt: `Status as of ${trigger.firedAt.toISOString()}` }
},
onFinish: async ({ agentId, outcome, runId }) => {
// Runs on any non-error, non-abort outcome
},
onError: async ({ agentId, phase, error }) => {
// Runs when prepare, the signal, or the agent run threw
},
onAbort: async ({ agentId, runId }) => {
// Runs when the run was aborted mid-stream
},
},
})
```
The hooks are:
- `prepare`: runs before the fire. Return an object to override fire-time parameters such as `prompt` or `threadId`, `null` to skip the fire, or `undefined` to use the stored defaults.
- `onFinish`: runs once per trigger that reached a non-error, non-abort terminal state.
- `onError`: runs when `prepare`, the signal, or the agent run threw.
- `onAbort`: runs when the run was aborted mid-stream.
Every hook context includes `agentId` (the agent the schedule fired for) alongside `schedule` and `trigger`.
Hook exceptions are caught and logged. They never re-route the worker or trigger another hook.
## Related
- [`mastra.schedules`](https://mastra.ai/reference/schedules/overview): API reference for creating and managing schedules.
- [Signals](https://mastra.ai/docs/long-running-agents/signals): the delivery mechanism behind threaded schedules.
- [Scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows): declare a cron schedule on a workflow definition.