Skip to main content
Clawboo’s Scheduler lets you put a team task on a clock so it runs automatically — a morning standup digest, a weekly code-hygiene sweep, or a one-off future cleanup — without anyone sitting at the dashboard to kick it off. Each fire materializes a fresh board task and routes it through the same executor pipeline as any hand-created task: budgets, approvals, worktree isolation, and observability all apply exactly as normal. There is no privileged “scheduled” path. This guide walks you through creating a Routine, testing it, understanding what happens when a fire fails, and cleaning up when you no longer need it.
Routines run unattended. Before you schedule work for a team, set up governance so runaway agents can’t drain your API budget. See Governance and budgets.

Prerequisites

  • At least one agent exists in Clawboo. The create dialog picks agents from GET /api/agents.
  • The agent’s runtime is connected and ready. Routines work for every runtime class — Native, Claude Code, Codex, Hermes, and OpenClaw. See Connecting runtimes.
  • The Scheduler tab is open. Navigate to it from the sidebar. Everything here also works directly against the /api/schedules REST surface.

Steps

1

Open the Scheduler panel and click Schedule

Navigate to the Scheduler tab in the sidebar. The panel shows two groups: Team work (Routines you create here) and Agent’s own life (OpenClaw-only Gateway schedules Clawboo observes). Click Schedule to open the create dialog.
2

Configure the Routine

Fill in the dialog:
  1. Agent — pick the agent that should run this task. Each option shows the agent name and its runtime.
  2. Schedule intent — leave it on A team task. The other option, Its own life, is enabled only for OpenClaw agents; for any other runtime it reads “OpenClaw only” and is disabled.
  3. Runs — pick a cadence from the cron presets (see the table below) or type your own expression.
  4. Label — an optional human-readable name. Defaults to “Scheduled task”.
PresetCron expression
Every 5 minutes*/5 * * * *
Every 15 minutes*/15 * * * *
Every 30 minutes*/30 * * * *
Every hour0 * * * *
Every 6 hours0 */6 * * *
Every 12 hours0 */12 * * *
Daily at 9 am0 9 * * *
Weekly — Monday 9 am0 9 * * 1
Any croner-parseable 5- or 6-field cron expression works, not just the presets. An unparseable spec is refused at creation with 400 code: "invalid_cron_spec".Click Create schedule. On success the dialog closes (201) and the list refreshes.
3

Create the same Routine via the API (optional)

If you prefer REST, source, domain, agentId, and cronSpec are required. taskTemplate.title is required inside the template; kind defaults to code (which provisions a worktree).
curl -X POST http://localhost:18790/api/schedules \
  -H 'Content-Type: application/json' \
  -d '{
    "source": "clawboo-routine",
    "domain": "team-task",
    "agentId": "<agent-id>",
    "teamId": "<team-id>",
    "cronSpec": "0 9 * * 1",
    "label": "Weekly standup digest",
    "taskTemplate": {
      "title": "Weekly standup digest",
      "kind": "code"
    }
  }'
To schedule a one-off future run instead of a recurring cadence, use the once@<ISO-8601> form — only available via the API, not the dialog:
curl -X POST http://localhost:18790/api/schedules \
  -H 'Content-Type: application/json' \
  -d '{
    "source": "clawboo-routine",
    "domain": "team-task",
    "agentId": "<agent-id>",
    "cronSpec": "once@2026-07-01T09:00:00Z",
    "label": "Mid-year cleanup",
    "taskTemplate": { "title": "Mid-year cleanup", "kind": "code" }
  }'
A one-shot Routine re-enters idle with nextRunAt: null after it fires successfully — it self-disables and never repeats.
4

Verify the Routine is saved

The new Routine appears under the Team work group with a live nextRunAt countdown (in 5m, in 1h, …). The panel re-fetches every 8 seconds, so the countdown and status stay current.Confirm over REST:
curl http://localhost:18790/api/schedules
Your new row should appear with "status": "idle" and a populated nextRunAt.
5

Test it with Run Now

Click the run-now (refresh-arrow) button on the row to force-fire immediately without waiting for the cron tick:
curl -X POST http://localhost:18790/api/schedules/clawboo-routine:<row-id>/run
This returns 202 — an enqueue acknowledgement, not a synchronous result. The row flips to queued and the ticker picks it up on the next pass. Watch the trace in the Observability dashboard to see the outcome. A fire also materializes a task on the board — open it to confirm.
6

Pause a Routine

Click the pause button on the row to stop the Routine from auto-firing until you resume it:
curl -X PATCH http://localhost:18790/api/schedules/clawboo-routine:<row-id> \
  -H 'Content-Type: application/json' \
  -d '{"action": "pause"}'
A paused Routine never auto-fires. Resume it with the play button (or {"action": "resume"}) when you’re ready — Clawboo recomputes nextRunAt from the current time.
7

Delete the Routine when you no longer need it

Click the trash button on the row. The panel asks you to confirm, then sends:
curl -X DELETE http://localhost:18790/api/schedules/clawboo-routine:<row-id>
Deletion is permanent. If you only want to stop it temporarily, pause it instead.

What happens when a Routine fires

When a Routine is due, the ticker flips it to queued, atomically claims it, materializes the board task, and routes it to the correct runtime:
  • Native, Claude Code, Codex, Hermes — runs through the one-shot executor: claim the board task, provision a worktree if the task kind requires it, run the adapter, verify, complete.
  • OpenClaw — runs over its live Gateway connection through a separate operator dispatcher, bounded by a configurable watchdog (default 10 minutes, set CLAWBOO_ROUTINE_OPENCLAW_TIMEOUT_MS to override).
Each fire emits observability events (routine_fired, routine_dispatched, then routine_completed or routine_error) so you can follow a scheduled run in the Observability dashboard exactly like any hand-created task.

Understand the error-halts policy

When a recurring Routine’s fire fails, the Routine parks itself: status goes to error, the failure is recorded in lastError, and nextRunAt is set to null. It will not fire again until you manually resume it.
This is intentional. An autonomous scheduled task that silently retries a broken fire every tick would burn budget, churn the board, and hide the real problem. Parking surfaces the failure immediately and stops the bleeding. Fix the underlying cause, then click Resume to re-arm the Routine (error → idle).
A successful fire re-arms cleanly at its next occurrence. A one-shot Routine that fires successfully self-disables — that is not an error state.

Change the cadence

Update the cron spec, label, or task template on an existing Routine with a PATCH:
curl -X PATCH http://localhost:18790/api/schedules/clawboo-routine:<row-id> \
  -H 'Content-Type: application/json' \
  -d '{"patch": {"cronSpec": "0 8 * * 1-5"}}'
Changing the cron spec recomputes nextRunAt only for an already-armed (idle) row. A paused or parked row stays disarmed until you resume it.

Troubleshooting

A recurring Routine stopped firing on its own. It hit the error-halts policy — a fire failed, the row parked in error, and nextRunAt is null. Check lastError on the row and the run’s observability trace, fix the cause, then click Resume.
Create returns 409. You tried to bind the Routine to an existing board task (teamTaskId) that another non-manual owner already fires. This is a data conflict, not a transient error — do not retry. Bind to a different task, or leave teamTaskId unset so each fire mints its own fresh task.
Create returns 400 with code: "bound_recurring_schedule". You bound a recurring cron spec to an existing team task. A bound task is claimable exactly once, so a recurring fire would park forever after the first run. Use a once@<ISO-8601> spec to bind to an existing task, or drop teamTaskId for a recurring Routine.
Server restart lost my Routines. It shouldn’t — the scheduled_runs ledger in SQLite is the source of truth. The ticker holds no durable state and reconstructs every active Routine at boot. A claimed orphan re-fires; a recurring running orphan re-arms; a one-shot running orphan parks in error for a human to inspect.

Governance and budgets

Cap what a scheduled fire can spend before you let it run unattended.

Scheduling concept

The two cron domains, the ledger, the rebuildable ticker, and the fire path.

Schedules API

Full request/response shapes and status codes.

Observability dashboard

Watch a scheduled run’s trace end to end.

Cross-runtime handoff

Another way scheduled work composes across runtimes.

The board

Where each fire lands and how the atomic claim works.