Operating System
Cron Jobs
Schedule recurring commands and agent sessions in agentOS VMs.
- Cron expressions for flexible scheduling (e.g.
"0 9 * * *"for 9 AM daily) - Two action types:
execfor commands,sessionfor agent sessions - Overlap modes:
allow,skip, orqueueconcurrent executions - Event streaming via
cronEventfor monitoring job execution
Schedule a command
Run a shell command on a recurring schedule.
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);
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
Schedule an agent session
Create a recurring agent session that runs a prompt on a schedule.
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" },
},
});
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
Overlap modes
Control what happens when a cron job triggers while a previous execution is still running.
| Mode | Behavior |
|---|---|
"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 |
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",
},
});
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
Monitor cron events
Subscribe to cronEvent to track job execution.
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"] },
});
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
List and cancel cron jobs
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);
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
Example: Heartbeat pattern
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.
Recommendations
- 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
idwhen scheduling to make it easier to manage and cancel jobs later.