team-task domain — recurring team work owned by the scheduled_runs SQLite ledger) and the OpenClaw Gateway cron (the runtime-own-life domain — an OpenClaw agent’s standalone cron). You can read both sources together and write to either, with each write routed automatically based on the composite schedule id.
The two sources are never conflated. A Routine schedules team work fired on a cadence for any runtime class. A Gateway-cron row schedules an OpenClaw agent’s own standalone life. Clawboo never registers a team task into the Gateway cron.
<source>:<rawId> — for example clawboo-routine:123 or openclaw-gateway-cron:abc. Mutation routes URL-decode and parse the id back to its owning source. An id that matches no source returns 404.
Routes
| Method | Path | Summary |
|---|---|---|
GET | /api/schedules | Merged list across both sources |
POST | /api/schedules | Create a schedule |
PATCH | /api/schedules/:id | Pause/resume or patch a schedule |
DELETE | /api/schedules/:id | Remove a schedule |
POST | /api/schedules/:id/run | Force-fire now |
The ScheduleRecord shape
Every source normalizes its rows to this shape:
Composite
<source>:<sourceScheduleId> — treat as opaque.'clawboo-routine' | 'openclaw-gateway-cron''team-task' (Routine) | 'runtime-own-life' (Gateway cron)A cron expression (e.g.
"0 9 * * *"), once@<iso> for a one-shot, or every:<ms>[@anchor:<ms>].'queued' | 'claimed' | 'running' | 'idle' | 'paused' | 'error'Epoch ms of the next scheduled fire.
null when disarmed.'managed' — Clawboo owns the row. 'external-write' — the runtime owns the store. 'observe-only' — read-only.| Source | Domain | Manageability | Backed by |
|---|---|---|---|
clawboo-routine | team-task | managed | scheduled_runs SQLite ledger |
openclaw-gateway-cron | runtime-own-life | external-write | Gateway cron over operator WS-RPC |
GET /api/schedules
Returns the merged schedule list across both sources. A source that fails or is disconnected contributes a degraded sources[] entry rather than failing the request. This route always returns 200.
Response 200 OK
Merged schedule records from both sources.
Per-source status. A degraded source is noted here but does not fail the response.
POST /api/schedules
Creates a schedule. The body routes the write to spec.source. Clawboo enforces that a team-task schedule cannot be aimed at the Gateway cron source (422), and that a recurring spec cannot be bound to an existing board task (400) — a bound task is claimable exactly once.
Request body
'clawboo-routine' | 'openclaw-gateway-cron''team-task' | 'runtime-own-life'The agent this schedule targets.
A cron expression (
"0 9 * * *"), once@<iso> for a one-shot, or an every: interval.Human-readable label for the schedule.
Team scope for Routine schedules.
Bind this schedule to an existing board task. Only valid with a one-shot
once@<iso> spec — recurring specs cannot bind to a one-shot-only task.For Routine rows: the task template to create when the schedule fires.
Response 201 Created
| Code | Status | Meaning |
|---|---|---|
invalid_body | 400 | Body failed the shape check |
invalid_cron_spec | 400 | The cron spec is unparseable |
bound_recurring_schedule | 400 | A recurring spec was bound to an existing board task |
unknown_schedule | 404 | spec.source matched no registered source |
duplicate_firing_owner | 409 | The bound task already has a different firing owner — do not retry |
team_task_domain_violation | 422 | A team-task create aimed at the Gateway cron |
schedule_source_unavailable | 503 | The Gateway cron source is disconnected |
PATCH /api/schedules/:id
Pauses or resumes a schedule, or patches its cron spec, label, task template, or payload. The body must be exactly one of the two shapes below.
Composite schedule id (URL-decoded). Returns
404 if no source matches.Request body — action
'pause' or 'resume'.Request body — patch
Fields to update. For Routines:
cronSpec, label, taskTemplate. For Gateway cron: cronSpec, label, payload.Response 200 OK
{ "schedule": null } when the read-back after update cannot reload the job.
DELETE /api/schedules/:id
Removes a schedule. For a Routine, deletes the ledger row. For the Gateway cron, calls cron.remove on the operator connection.
Response 200 OK
POST /api/schedules/:id/run
Force-fires a schedule immediately. This is an enqueue-style acknowledgement, not a synchronous run. A Routine moves to queued (the ticker picks it up); the Gateway cron receives a cron.run { mode: 'force' } call. Watch the observability event log for the actual execution result.
Response 202 Accepted
Error codes reference
All error responses include acode field for stable branch-on logic:
code | Status | Meaning |
|---|---|---|
invalid_body | 400 | Body failed shape check |
invalid_cron_spec | 400 | Unparseable cron spec |
bound_recurring_schedule | 400 | Recurring spec bound to a one-shot board task |
unsupported_schedule_write | 403 | Target source’s manageability forbids this action |
unknown_schedule | 404 | Id matched no source or is unknown within it |
duplicate_firing_owner | 409 | Bound task already has a different owner — do not retry |
illegal_schedule_transition | 409 | Pause/resume/run is illegal from the current status |
team_task_domain_violation | 422 | team-task create aimed at a runtime-own-life source |
schedule_source_unavailable | 503 | Source backing connection is down |
See also
- Scheduling concepts — Routines vs Gateway cron, the durable ledger
- Recurring team work guide — practical walkthrough
- Scheduler UI — the dashboard over this surface
- REST API overview