Lifecycle

Schedules

Create recurring tasks that run on a cron schedule inside a box. You can schedule shell commands or agent prompts. Available on both box.schedule and ephemeralBox.schedule.


API

Schedule a shell command

Run a shell command on a cron schedule.

box.ts
const schedule = await box.schedule.exec({  cron: "* * * * *",  command: ["bash", "-c", "date >> /workspace/home/cron.log && echo scheduled-ok"],  webhookUrl: "https://example.com/hook",          // optional  webhookHeaders: { Authorization: "Bearer ..." }, // optional  folder: "/workspace/home",                       // optional, defaults to box.cwd})console.log(schedule.id)
box.py
schedule = box.schedule.exec(    cron="* * * * *",    command=["bash", "-c", "date >> /workspace/home/cron.log && echo scheduled-ok"],    webhook_url="https://example.com/hook",            # optional    webhook_headers={"Authorization": "Bearer ..."},   # optional    folder="/workspace/home",                          # optional, defaults to box.cwd)print(schedule.id)
ParameterRequiredDescription
cronYes5-field cron expression (UTC)
commandYesstring[] — the command to run
webhookUrlNoURL to notify when the scheduled run completes
webhookHeadersNoHeaders to include in the webhook request
folderNoWorking directory. Defaults to box.cwd; relative paths resolved against it

Schedule an agent prompt

Run an agent prompt on a cron schedule. Requires an agent to be configured on the box.

box.ts
const schedule = await box.schedule.agent({  cron: "0 9 * * *",  prompt: "Run the test suite and fix any failures",  model: "anthropic/claude-sonnet-4-6",          // optional, overrides box's model  timeout: 300_000,                     // optional, kill the run after 5 minutes  options: { maxBudgetUsd: 1.0 },      // optional, provider-specific agent options})console.log(schedule.id)
box.py
schedule = box.schedule.agent(    cron="0 9 * * *",    prompt="Run the test suite and fix any failures",    model="anthropic/claude-sonnet-4-6",   # optional, overrides box's model    timeout=300_000,                        # optional, kill the run after 5 minutes    options={"max_budget_usd": 1.0},        # optional, provider-specific agent options)print(schedule.id)
ParameterRequiredDescription
cronYes5-field cron expression (UTC)
promptYesThe prompt to send to the agent
folderNoWorking directory. Defaults to box.cwd; relative paths resolved against it
modelNoOverride the box's default model for this schedule
optionsNoProvider-specific agent options (e.g. maxBudgetUsd, effort, systemPrompt, maxTurns)
timeoutNoTimeout in milliseconds — kills the run if exceeded
webhookUrlNoURL to notify when the scheduled run completes
webhookHeadersNoHeaders to include in the webhook request

List schedules

Retrieve all non-deleted schedules for the current box.

box.ts
const schedules = await box.schedule.list()for (const s of schedules) {  console.log(s.id, s.type, s.cron, s.status)}
box.py
schedules = box.schedule.list()for s in schedules:    print(s.id, s.type, s.cron, s.status)

Get a schedule

Retrieve a single schedule by ID.

box.ts
const schedule = await box.schedule.get("schedule_abc123")console.log(schedule.type)   // "exec" | "prompt"console.log(schedule.status) // "active" | "paused" | "deleted"console.log(schedule.cron)
box.py
schedule = box.schedule.get("schedule_abc123")print(schedule.type)    # "exec" | "prompt"print(schedule.status)  # "active" | "paused" | "deleted"print(schedule.cron)

Pause a schedule

Pause an active schedule so it stops running.

box.ts
await box.schedule.pause("schedule_abc123")
box.py
box.schedule.pause("schedule_abc123")

Resume a schedule

Resume a paused schedule.

box.ts
await box.schedule.resume("schedule_abc123")
box.py
box.schedule.resume("schedule_abc123")

Delete a schedule

Remove a schedule so it no longer runs.

box.ts
await box.schedule.delete("schedule_abc123")
box.py
box.schedule.delete("schedule_abc123")

Schedule response

Most schedule methods return a Schedule object:

box.ts
interface Schedule {  id: string  box_id: string  type: "exec" | "prompt"  cron: string  command?: string[]         // present when type is "exec"  prompt?: string            // present when type is "prompt"  folder?: string  model?: string  agent_options?: Record<string, unknown>  timeout?: number  status: "active" | "paused" | "deleted"  webhook_url?: string  webhook_headers?: Record<string, string>  last_run_at?: number  last_run_status?: "completed" | "failed" | "skipped"  last_run_id?: string  total_runs: number  total_failures: number  created_at: number  updated_at: number}
box.py
# Schedule is a pydantic model; access fields as attributes:schedule.id              # strschedule.box_id          # strschedule.type            # "exec" | "prompt"schedule.cron            # strschedule.command         # list[str] | None   (present when type == "exec")schedule.prompt          # str | None          (present when type == "prompt")schedule.folder          # str | Noneschedule.model           # str | Noneschedule.agent_options   # dict | Noneschedule.timeout         # float | Noneschedule.status          # "active" | "paused" | "deleted"schedule.webhook_url     # str | Noneschedule.webhook_headers # dict | Noneschedule.last_run_at     # int | Noneschedule.last_run_status # "completed" | "failed" | "skipped" | Noneschedule.last_run_id     # str | Noneschedule.total_runs      # intschedule.total_failures  # intschedule.created_at      # intschedule.updated_at      # int

Cron syntax

Schedules use standard 5-field cron expressions (UTC):

┌───────────── minute (0-59)│ ┌───────────── hour (0-23)│ │ ┌───────────── day of month (1-31)│ │ │ ┌───────────── month (1-12)│ │ │ │ ┌───────────── day of week (0-6, Sun=0)│ │ │ │ │* * * * *
ExpressionDescription
* * * * *Every minute
0 * * * *Every hour
0 9 * * *Daily at 9:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
*/5 * * * *Every 5 minutes

Examples

Periodic health check

Schedule a command that checks whether your service is healthy.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({ runtime: "node" })await box.schedule.exec({  cron: "*/5 * * * *",  command: ["bash", "-c", "curl -sf http://localhost:3000/health || echo UNHEALTHY >> /workspace/home/health.log"],})
box.py
from upstash_box import Boxbox = Box.create(runtime="node")box.schedule.exec(    cron="*/5 * * * *",    command=["bash", "-c", "curl -sf http://localhost:3000/health || echo UNHEALTHY >> /workspace/home/health.log"],)

Daily code review agent

Schedule an agent to review recent changes every morning.

box.ts
import { Agent, Box } from "@upstash/box"const box = await Box.create({  runtime: "node",  agent: {    harness: Agent.ClaudeCode,    model: "anthropic/claude-sonnet-4-5",    apiKey: process.env.ANTHROPIC_API_KEY,  },  git: { token: process.env.GITHUB_TOKEN },})await box.git.clone({ repo: "github.com/your-org/your-repo" })await box.schedule.agent({  cron: "0 9 * * 1-5",  prompt: "Pull latest changes, review the last 24h of commits, and open issues for any bugs or style violations",  timeout: 600_000,  options: { maxBudgetUsd: 2.0, effort: "high" },})
box.py
import osfrom upstash_box import Box, Agentbox = Box.create(    runtime="node",    agent={        "harness": Agent.CLAUDE_CODE,        "model": "anthropic/claude-sonnet-4-5",        "api_key": os.environ["ANTHROPIC_API_KEY"],    },    git={"token": os.environ["GITHUB_TOKEN"]},)box.git.clone(repo="github.com/your-org/your-repo")box.schedule.agent(    cron="0 9 * * 1-5",    prompt="Pull latest changes, review the last 24h of commits, and open issues for any bugs or style violations",    timeout=600_000,    options={"max_budget_usd": 2.0, "effort": "high"},)

Manage schedules

List active schedules, pause, resume, and clean up ones you no longer need.

box.ts
const schedules = await box.schedule.list()for (const s of schedules) {  console.log(`${s.id}${s.type}${s.cron}${s.status}`)}// Pause a scheduleawait box.schedule.pause(schedules[0].id)// Resume it laterawait box.schedule.resume(schedules[0].id)// Remove a specific scheduleawait box.schedule.delete(schedules[0].id)
box.py
schedules = box.schedule.list()for s in schedules:    print(f"{s.id}{s.type}{s.cron}{s.status}")# Pause a schedulebox.schedule.pause(schedules[0].id)# Resume it laterbox.schedule.resume(schedules[0].id)# Remove a specific schedulebox.schedule.delete(schedules[0].id)
Loading search…