Skip to main content

Cron Jobs

Cron jobs start account agents on a schedule. They are included in the default infrastructure as a small add-on surface on top of the existing account and harness services.

Model

Cron jobs store the selected agent and the run payload directly. The payload mirrors the agent run input: provide a single input string (wrapped into one user message) or a full events model-message list — exactly one of the two. The stored canonical form is always events.

{
"agentId": "agent_maintainer",
"conversationKey": "cron:daily-maintenance",
"input": "Run daily maintenance."
}

This keeps the add-on small. Developers who need custom workflow code can deploy their own Lambda, worker, or scheduler and call the existing direct/async API.

Code-First Configuration

Define cron jobs as resources alongside your agents:

broods/index.ts
import { defineAgent, defineCron } from "broods";

export const maintainer = defineAgent({
name: "maintainer",
config: {
provider: { openai: { apiKey: env.OPENAI_API_KEY } },
model: { provider: "openai", modelId: "gpt-5.5" },
agent: { system: "You are a maintenance assistant." },
},
});

export const dailyMaintenance = defineCron({
name: "daily-maintenance",
config: {
agent: maintainer,
conversationKey: "cron:daily-maintenance",
input: "Run daily maintenance.",
scheduleExpression: "cron(0 8 * * ? *)",
timezone: "Europe/Amsterdam",
},
});

Use events instead of input for multimodal or multi-message payloads:

export const weeklyDigest = defineCron({
name: "weekly-digest",
config: {
agent: maintainer,
events: [
{ role: "user", content: [{ type: "text", text: "Summarize this week." }] },
],
scheduleExpression: "cron(0 9 ? * MON *)",
timezone: "Europe/Amsterdam",
},
});

Account API

Create a cron job directly via the account API:

curl -X POST "$ACCOUNT_SERVICE_URL/accounts/me/crons" \
-H "Authorization: Bearer $ACCOUNT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily maintenance",
"agentId": "agent_maintainer",
"conversationKey": "cron:daily-maintenance",
"input": "Run daily maintenance.",
"scheduleExpression": "cron(0 8 * * ? *)",
"timezone": "Europe/Amsterdam"
}'

Supported schedule expressions are AWS EventBridge Scheduler expressions: cron(...), rate(...), and at(...). The cron form is cron(minutes hours day-of-month month day-of-week year) — one of day-of-month / day-of-week must be ?.

CadenceExpression
Every hourrate(1 hour)
Every Monday 09:00cron(0 9 ? * MON *)
1st of each month 08:00cron(0 8 1 * ? *)
Yearly, Jan 1 09:00cron(0 9 1 1 ? *)
Once, at a fixed timeat(2027-01-01T09:00:00)

timezone maps to EventBridge Scheduler ScheduleExpressionTimezone. When omitted, schedules are evaluated in UTC. Use an IANA timezone such as Europe/Amsterdam when account owners expect local wall-clock time. This only controls schedule evaluation; it is not injected into the agent prompt.

Pause a job:

curl -X PATCH "$ACCOUNT_SERVICE_URL/accounts/me/crons/$CRON_ID" \
-H "Authorization: Bearer $ACCOUNT_SECRET" \
-H "Content-Type: application/json" \
-d '{ "status": "paused" }'

Delete a job:

curl -X DELETE "$ACCOUNT_SERVICE_URL/accounts/me/crons/$CRON_ID" \
-H "Authorization: Bearer $ACCOUNT_SECRET"

List jobs with GET /accounts/me/crons or fetch one with GET /accounts/me/crons/{cronId}. Responses include the run state: status, lastInvokedAt, lastStatus, and lastError. Paused jobs are skipped at invoke time.

SDK and Dynamic Creation

Cron jobs are not limited to declarative defineCron resources synced by broods dev — clients can create, update, and delete them at runtime through the SDK, which calls the same account API (so EventBridge Scheduler stays in sync):

import { BroodsClient } from "broods";
import { api } from "./broods/_generated/api";

const client = new BroodsClient();

await client.createCron({
name: "Weekly digest",
agent: api.agents.support,
input: "Summarize this week's tickets.",
scheduleExpression: "cron(0 9 ? * MON *)",
timezone: "Europe/Amsterdam",
});

Pass events: [...] instead of input for multimodal or multi-message payloads.