Skip to content
GitHub Get Started
Operating System

Cron Jobs

  • Cron expressions for flexible scheduling (e.g. "0 9 * * *" for 9 AM daily)
  • Two action types: exec for commands, session for agent sessions
  • Overlap modes: allow, skip, or queue concurrent executions
  • Event streaming via cronEvent for monitoring job execution

Run a shell command on a recurring schedule.

client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);
// Schedule a cleanup script every hour
const { id } = await agent.scheduleCron({
schedule: "0 * * * *",
action: {
type: "exec",
command: "rm",
args: ["-rf", "/tmp/cache/*"],
},
});
console.log("Cron job ID:", id);

Create a recurring agent session that runs a prompt on a schedule.

client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);
// Run an agent every day at 9 AM to check for issues
await agent.scheduleCron({
schedule: "0 9 * * *",
action: {
type: "session",
agentType: "pi",
prompt: "Review the logs in /home/user/logs/ and summarize any errors",
options: { cwd: "/home/user" },
},
});

Control what happens when a cron job triggers while a previous execution is still running.

ModeBehavior
"skip"Skip this trigger if the previous run is still active
"allow"Allow concurrent executions (default)
"queue"Queue this trigger and run it after the previous one finishes
client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);
// Queue overlapping executions
await agent.scheduleCron({
schedule: "*/5 * * * *",
overlap: "queue",
action: {
type: "session",
agentType: "pi",
prompt: "Process the next batch of tasks",
},
});

Subscribe to cronEvent to track job execution.

client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);
agent.on("cronEvent", (data) => {
console.log("Cron event:", data.event);
});
await agent.scheduleCron({
schedule: "*/1 * * * *",
action: { type: "exec", command: "echo", args: ["heartbeat"] },
});
client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);
// List all cron jobs
const jobs = await agent.listCronJobs();
for (const job of jobs) {
console.log(job.id, job.schedule);
}
// Cancel a specific job
await agent.cancelCronJob(jobs[0].id);

Schedule a recurring agent session to periodically check on a task. This is the core pattern behind OpenClaw, where an agent wakes up on a schedule to review progress, take action, and go back to sleep.

await agent.scheduleCron({
schedule: "*/30 * * * *",
overlap: "skip",
action: {
type: "session",
agentType: "pi",
prompt: "Check the status of open issues and take any necessary action",
},
});

The agent sleeps between executions and only consumes resources when the cron job fires.

  • Use "skip" overlap mode for most jobs. This prevents unbounded concurrency if a job takes longer than the interval. The default is "allow".
  • Use "queue" when every trigger must execute, even if they back up.
  • Cron jobs keep the actor alive while executing. The actor can sleep between executions.
  • Provide a custom id when scheduling to make it easier to manage and cancel jobs later.