schedule (synthetic checks)
The optional schedule MCP tool stores time-based jobs and run history in a local SQLite schedule store. In v1, the supported action kind is synthetic HTTP checks with assertion-based pass/fail.
- Enable:
CLAWQL_ENABLE_SCHEDULE=1(ortrue/yes). - Storage: default
.clawql/schedule.dbunder the server working directory; override withCLAWQL_SCHEDULE_DB_PATH. - Execution model: background worker runs due jobs automatically (
cron,interval,one_shot) and you can still run ad hoc checks withtrigger. - Operations:
create,list,get,delete,trigger. - Frequency:
cron,interval,one_shot. - Safety controls:
CLAWQL_SCHEDULE_URL_ALLOWLIST_PREFIXESand optional synthetic caps underCLAWQL_SCHEDULE_SYNTHETIC_*. - Worker cadence: optional
CLAWQL_SCHEDULE_POLL_MS(default 5000 ms).
Canonical design and repository reference: schedule-synthetic-checks.md · mcp-tools.md § schedule · issue #76.
Setup and usage guide
1) Enable and configure
Set at minimum:
CLAWQL_ENABLE_SCHEDULE=1
Common production env set:
CLAWQL_ENABLE_SCHEDULE=1
CLAWQL_SCHEDULE_DB_PATH=/data/clawql/schedule.db
CLAWQL_SCHEDULE_POLL_MS=5000
CLAWQL_SCHEDULE_HISTORY_LIMIT=50
CLAWQL_SCHEDULE_INTERVAL_MIN_SECONDS=60
CLAWQL_SCHEDULE_INTERVAL_MAX_SECONDS=31536000
CLAWQL_SCHEDULE_URL_ALLOWLIST_PREFIXES=https://api.example.com,https://status.example.com
CLAWQL_SCHEDULE_SYNTHETIC_TIMEOUT_MS_DEFAULT=10000
CLAWQL_SCHEDULE_SYNTHETIC_TIMEOUT_MS_MAX=60000
CLAWQL_SCHEDULE_SYNTHETIC_MAX_RESPONSE_BYTES_DEFAULT=1048576
CLAWQL_SCHEDULE_SYNTHETIC_MAX_REDIRECTS_DEFAULT=3
Optional notify bridge (best-effort):
CLAWQL_SCHEDULE_NOTIFY_CHANNEL=C0123456789
CLAWQL_SCHEDULE_NOTIFY_ON_FAILURE=1
CLAWQL_SCHEDULE_NOTIFY_ON_RECOVERY=1
2) Create checks
Interval check (every 5 minutes)
{
"operation": "create",
"schedule": {
"frequency": {
"type": "interval",
"seconds": 300
}
},
"action": {
"kind": "synthetic",
"synthetic_test": {
"name": "api-health",
"request": {
"method": "GET",
"url": "https://api.example.com/health",
"headers": {
"accept": "application/json"
},
"body": null
},
"limits": {
"timeout_ms": 10000,
"max_response_bytes": 1048576,
"max_redirects": 3
},
"assert": {
"status_in": [200],
"latency_ms_max": 2000,
"body_contains": "\"ok\":true"
}
}
}
}
Expected create result shape:
{
"ok": true,
"operation": "create",
"job": {
"id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147",
"schedule": {
"frequency": {
"type": "interval",
"seconds": 300
}
},
"action": {
"kind": "synthetic",
"synthetic_test": {
"name": "api-health"
}
},
"enabled": true,
"created_at": "2026-04-24T01:05:00.000Z",
"updated_at": "2026-04-24T01:05:00.000Z"
}
}
Cron check (UTC)
{
"operation": "create",
"schedule": {
"frequency": {
"type": "cron",
"expression": "*/5 * * * *"
}
},
"action": {
"kind": "synthetic",
"synthetic_test": {
"name": "api-health-cron",
"request": {
"method": "GET",
"url": "https://status.example.com/healthz"
},
"assert": {
"status_in": [200]
}
}
}
}
One-shot check
{
"operation": "create",
"schedule": {
"frequency": {
"type": "one_shot",
"run_at": "2026-04-25T12:00:00.000Z"
}
},
"action": {
"kind": "synthetic",
"synthetic_test": {
"name": "release-window-check",
"request": {
"method": "GET",
"url": "https://api.example.com/health"
},
"assert": {
"status_in": [200]
}
}
}
}
3) Trigger now (manual ad hoc run)
{
"operation": "trigger",
"job_id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147"
}
Expected result shape:
{
"ok": true,
"operation": "trigger",
"job_id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147",
"run": {
"id": "e4e18f32-4bf8-49f6-9dcf-8f0f0f8f6535",
"triggered_at": "2026-04-24T01:06:03.000Z",
"dry_run": false,
"status": "pass",
"latency_ms": 183,
"http_status": 200,
"error_text": null,
"response_excerpt": "{\"ok\":true}"
}
}
4) Inspect runs and debug failures
{
"operation": "get",
"job_id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147",
"include_runs": true,
"runs_limit": 10
}
If you want a non-persisting validation probe, trigger with:
{
"operation": "trigger",
"job_id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147",
"dry_run": true
}
dry_run: true executes request + assertions but does not append to run history.
List all jobs:
{
"operation": "list",
"limit": 50
}
Delete a job:
{
"operation": "delete",
"job_id": "4cae2b9a-3ca2-4ed7-9618-4a1c52f6b147"
}
5) Runtime behavior
- The background worker polls every
CLAWQL_SCHEDULE_POLL_MSand runs due jobs automatically. cronjobs run at matching UTC minute boundaries.intervaljobs run when the last persisted run is older thanseconds.one_shotjobs run once afterrun_at.- Manual
triggeruses the same execution/assertion path as worker ticks.
Pairing with notify
schedule is designed to pair with optional notify for failure and recovery messages:
- route failed runs to Slack with Slack notify,
- persist incident notes with
memory_ingestfor postmortems, - keep retrieval runbooks in Onyx where relevant via Onyx knowledge search.
See Tools for the full MCP tool matrix.
