openclaw-scheduler 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +302 -0
- package/BEST-PRACTICES.md +506 -0
- package/CHANGELOG.md +82 -0
- package/CODE_OF_CONDUCT.md +22 -0
- package/CONTEXT.md +26 -0
- package/CONTRIBUTING.md +73 -0
- package/IMPLEMENTATION_SPEC.md +170 -0
- package/INSTALL-ADDITIONAL-HOST.md +333 -0
- package/INSTALL-LINUX.md +419 -0
- package/INSTALL-WINDOWS.md +305 -0
- package/INSTALL.md +364 -0
- package/JOB-QUICK-REF.md +222 -0
- package/LICENSE +21 -0
- package/QUICK-START.md +256 -0
- package/README.md +2170 -0
- package/SECURITY.md +34 -0
- package/UNINSTALL.md +129 -0
- package/UPGRADING.md +436 -0
- package/agents.js +67 -0
- package/approval.js +107 -0
- package/backup.js +390 -0
- package/bin/openclaw-scheduler.js +138 -0
- package/cli.js +1083 -0
- package/db.js +122 -0
- package/dispatch/529-recovery.mjs +204 -0
- package/dispatch/README.md +372 -0
- package/dispatch/config.example.json +24 -0
- package/dispatch/deliver-watcher.sh +57 -0
- package/dispatch/hooks.mjs +171 -0
- package/dispatch/index.mjs +1836 -0
- package/dispatch/watcher.mjs +1396 -0
- package/dispatch-queue.js +112 -0
- package/dispatcher-approvals.js +96 -0
- package/dispatcher-delivery.js +43 -0
- package/dispatcher-maintenance.js +242 -0
- package/dispatcher-shell.js +29 -0
- package/dispatcher-strategies.js +1280 -0
- package/dispatcher-utils.js +81 -0
- package/dispatcher.js +855 -0
- package/docs/adr-schedule-ownership.md +73 -0
- package/docs/gateway-contract.md +904 -0
- package/docs/plans/2026-03-09-fix-typescript-types.md +91 -0
- package/docs/plans/2026-03-09-test-coverage-gaps.md +83 -0
- package/docs/plans/2026-03-10-dispatcher-refactor.md +801 -0
- package/docs/trust-architecture.md +266 -0
- package/gateway.js +473 -0
- package/idempotency.js +119 -0
- package/index.d.ts +864 -0
- package/index.js +17 -0
- package/jobs.js +1224 -0
- package/messages.js +357 -0
- package/migrate-consolidate.js +694 -0
- package/migrate.js +125 -0
- package/package.json +130 -0
- package/paths.js +79 -0
- package/prompt-context.js +94 -0
- package/retrieval.js +176 -0
- package/runs.js +270 -0
- package/scheduler-schema.js +101 -0
- package/schema.sql +480 -0
- package/scripts/dispatch-cli-utils.mjs +65 -0
- package/scripts/inbox-consumer.mjs +288 -0
- package/scripts/stuck-detector.sh +18 -0
- package/scripts/stuck-run-detector.mjs +333 -0
- package/scripts/telegram-webhook-check.mjs +238 -0
- package/setup.mjs +724 -0
- package/shell-result.js +214 -0
- package/task-tracker.js +300 -0
- package/team-adapter.js +335 -0
- package/v02-runtime.js +599 -0
package/INSTALL.md
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Installing OpenClaw Scheduler on macOS
|
|
2
|
+
|
|
3
|
+
Step-by-step guide to deploy the scheduler on a macOS OpenClaw instance.
|
|
4
|
+
|
|
5
|
+
If you just want the fastest path to a working local install, start with the npm-first flow and [Five-Minute Setup in the README](README.md#five-minute-setup). This document is the full host deployment guide.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
| Requirement | Notes |
|
|
12
|
+
|-------------|-------|
|
|
13
|
+
| macOS or Linux | Tested on macOS arm64 |
|
|
14
|
+
| Node.js >= 20 | `node --version` |
|
|
15
|
+
| OpenClaw gateway running | With auth token |
|
|
16
|
+
| Git or SCP access | To clone/copy the repo |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Step 1: Install Scheduler Files
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cd ~/.openclaw
|
|
24
|
+
git clone https://github.com/amittell/openclaw-scheduler.git scheduler
|
|
25
|
+
cd scheduler
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or copy from an existing host:
|
|
29
|
+
```bash
|
|
30
|
+
scp -r user@source-host:~/.openclaw/scheduler ~/.openclaw/scheduler
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or npm-first install (no git clone):
|
|
34
|
+
```bash
|
|
35
|
+
mkdir -p ~/.openclaw/scheduler
|
|
36
|
+
npm install --prefix ~/.openclaw/scheduler openclaw-scheduler@latest
|
|
37
|
+
npm exec --prefix ~/.openclaw/scheduler openclaw-scheduler -- help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Runtime state for npm installs defaults to `~/.openclaw/scheduler/`, not the package directory under `node_modules/`.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Step 2: Install Dependencies
|
|
45
|
+
|
|
46
|
+
If you used the npm-first install path in Step 1, dependencies are already installed; skip to Step 3.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd ~/.openclaw/scheduler
|
|
50
|
+
npm install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Installs `better-sqlite3` (native, compiles for your arch) and `croner`.
|
|
54
|
+
|
|
55
|
+
If `better-sqlite3` fails: `xcode-select --install` (macOS).
|
|
56
|
+
|
|
57
|
+
If Node changes later under this checkout, rebuild the native module before restarting the scheduler:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd ~/.openclaw/scheduler
|
|
61
|
+
npm rebuild better-sqlite3
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Typical cases:
|
|
65
|
+
- `brew upgrade node` on macOS
|
|
66
|
+
- switching major Node versions with `nvm`, `fnm`, or `asdf`
|
|
67
|
+
- distro package upgrades that replace the Node binary
|
|
68
|
+
|
|
69
|
+
On Linux, install build deps first:
|
|
70
|
+
```bash
|
|
71
|
+
sudo apt install build-essential python3 # Ubuntu/Debian
|
|
72
|
+
sudo dnf install gcc gcc-c++ make python3 # Fedora/RHEL
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Step 2.5: Fix macOS shell PATH and completions
|
|
78
|
+
|
|
79
|
+
If you use `zsh` on macOS, make sure Homebrew is available to non-interactive shells too.
|
|
80
|
+
|
|
81
|
+
This matters for commands like:
|
|
82
|
+
- `ssh host 'node cli.js status'`
|
|
83
|
+
- remote admin scripts
|
|
84
|
+
- one-off maintenance commands that do not run inside an interactive terminal
|
|
85
|
+
|
|
86
|
+
`~/.zprofile` is not enough for that case. Put the minimal PATH bootstrap in `~/.zshenv`:
|
|
87
|
+
|
|
88
|
+
```zsh
|
|
89
|
+
# ~/.zshenv — sourced by all zsh instances, including non-interactive SSH commands
|
|
90
|
+
if [ -x /opt/homebrew/bin/brew ]; then
|
|
91
|
+
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
export PATH="$HOME/.local/bin:$HOME/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If you load OpenClaw completions in `~/.zshrc`, run `compinit` before sourcing them:
|
|
98
|
+
|
|
99
|
+
```zsh
|
|
100
|
+
autoload -Uz compinit
|
|
101
|
+
compinit
|
|
102
|
+
|
|
103
|
+
if [ -f "$HOME/.openclaw/completions/openclaw.zsh" ]; then
|
|
104
|
+
source "$HOME/.openclaw/completions/openclaw.zsh"
|
|
105
|
+
fi
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Avoid version-pinned Node PATH entries like `/opt/homebrew/opt/node@22/bin`. Use `/opt/homebrew/bin/node` instead so normal `brew upgrade node` keeps working.
|
|
109
|
+
|
|
110
|
+
Verify:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
ssh "$HOST" 'command -v node && node -v'
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Step 3: Run Tests
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
SCHEDULER_DB=:memory: node test.js
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**All tests must pass before proceeding.**
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Step 4: Enable Chat Completions on Gateway
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
openclaw config set gateway.http.endpoints.chatCompletions.enabled true
|
|
132
|
+
openclaw gateway restart
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Verify:
|
|
136
|
+
```bash
|
|
137
|
+
curl -s -o /dev/null -w "%{http_code}" \
|
|
138
|
+
-X POST \
|
|
139
|
+
-H "Authorization: Bearer YOUR_GATEWAY_TOKEN" \
|
|
140
|
+
-H "Content-Type: application/json" \
|
|
141
|
+
-d '{"model":"openclaw:main","messages":[{"role":"user","content":"reply OK"}]}' \
|
|
142
|
+
http://127.0.0.1:18789/v1/chat/completions
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Expected: `200`
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Step 5: Migrate Jobs from OC Cron
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
cd ~/.openclaw/scheduler
|
|
153
|
+
node migrate.js
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This imports jobs from `~/.openclaw/cron/jobs.json` → SQLite, converting schedule formats:
|
|
157
|
+
- `cron` → direct expression
|
|
158
|
+
- `every` → approximate cron (e.g., 30min → `*/30 * * * *`)
|
|
159
|
+
- `at` → one-shot with `delete_after_run=true`
|
|
160
|
+
|
|
161
|
+
Good default approach:
|
|
162
|
+
- if the old job was just a script, keep it as a `shell` job
|
|
163
|
+
- if the old job was really “run a prompt on a schedule,” rewrite it as an `isolated` job
|
|
164
|
+
- if two jobs depended on manual ordering, convert them into a parent/child chain instead of two independent schedules
|
|
165
|
+
|
|
166
|
+
For copy-paste examples, see [Starter Recipes in the README](README.md#starter-recipes) and [Common Migrations](README.md#common-migrations).
|
|
167
|
+
|
|
168
|
+
Verify:
|
|
169
|
+
```bash
|
|
170
|
+
node cli.js jobs list
|
|
171
|
+
node cli.js status
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Step 6: Disable OC Built-in Cron
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
openclaw cron list
|
|
180
|
+
# For each enabled job:
|
|
181
|
+
openclaw cron edit <job-id> --disable
|
|
182
|
+
openclaw config set cron.enabled false
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Also set `OPENCLAW_SKIP_CRON=1` in your OpenClaw gateway service environment (launchctl/systemd/pm2), then restart the gateway.
|
|
186
|
+
|
|
187
|
+
Verify: `openclaw cron list` shows no enabled jobs (or "No cron jobs").
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Step 7: Disable OC Heartbeat
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
openclaw config set agents.defaults.heartbeat.every "0m"
|
|
195
|
+
# If you have per-agent heartbeat overrides, set/remove those too:
|
|
196
|
+
# agents.list[].heartbeat.every = "0m"
|
|
197
|
+
openclaw gateway restart
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Step 8: Choose a macOS launchd mode
|
|
203
|
+
|
|
204
|
+
OpenClaw Scheduler supports both common macOS service styles:
|
|
205
|
+
|
|
206
|
+
- **LaunchAgent**: best for a personal Mac that auto-logs in and should run the scheduler inside your user session
|
|
207
|
+
- **LaunchDaemon**: best for a headless Mac or for starting before login
|
|
208
|
+
|
|
209
|
+
The simplest path is to let the setup wizard install the launchd plist for you:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
cd ~/.openclaw/scheduler
|
|
213
|
+
node setup.mjs --service-mode agent
|
|
214
|
+
# or:
|
|
215
|
+
node setup.mjs --service-mode daemon
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
If you installed from npm:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm exec --prefix ~/.openclaw/scheduler openclaw-scheduler -- setup --service-mode agent
|
|
222
|
+
# or:
|
|
223
|
+
npm exec --prefix ~/.openclaw/scheduler openclaw-scheduler -- setup --service-mode daemon
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
What each mode does:
|
|
227
|
+
|
|
228
|
+
- `agent` writes `~/Library/LaunchAgents/ai.openclaw.scheduler.plist` and bootstraps `gui/$UID/ai.openclaw.scheduler`
|
|
229
|
+
- `daemon` writes `/Library/LaunchDaemons/ai.openclaw.scheduler.plist` and bootstraps `system/ai.openclaw.scheduler`
|
|
230
|
+
|
|
231
|
+
Verify the mode you chose:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# LaunchAgent
|
|
235
|
+
launchctl print gui/$UID/ai.openclaw.scheduler
|
|
236
|
+
|
|
237
|
+
# LaunchDaemon
|
|
238
|
+
sudo launchctl print system/ai.openclaw.scheduler
|
|
239
|
+
|
|
240
|
+
# Either mode
|
|
241
|
+
sleep 5 && tail -5 /tmp/openclaw-scheduler.log
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Step 9: Smoke Tests
|
|
247
|
+
|
|
248
|
+
> **Note:** These smoke test commands use direct file imports and are for the git-clone install path. For npm installs, use `openclaw-scheduler` CLI commands instead.
|
|
249
|
+
|
|
250
|
+
### Isolated dispatch
|
|
251
|
+
```bash
|
|
252
|
+
cd ~/.openclaw/scheduler
|
|
253
|
+
node --input-type=module -e "
|
|
254
|
+
import { initDb, getDb } from './db.js';
|
|
255
|
+
import { createJob } from './jobs.js';
|
|
256
|
+
initDb();
|
|
257
|
+
const job = createJob({
|
|
258
|
+
name: 'Smoke Test',
|
|
259
|
+
schedule_cron: '0 0 31 2 *',
|
|
260
|
+
payload_message: 'Reply with exactly: SCHEDULER_OK',
|
|
261
|
+
delivery_mode: 'none',
|
|
262
|
+
delete_after_run: true,
|
|
263
|
+
origin: 'system',
|
|
264
|
+
run_timeout_ms: 300000,
|
|
265
|
+
});
|
|
266
|
+
getDb().prepare(\"UPDATE jobs SET next_run_at = datetime('now', '-1 second') WHERE id = ?\").run(job.id);
|
|
267
|
+
console.log('Created smoke test:', job.id);
|
|
268
|
+
"
|
|
269
|
+
sleep 20 && tail -10 /tmp/openclaw-scheduler.log
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Look for: `Dispatching: Smoke Test` → `Completed: Smoke Test`
|
|
273
|
+
|
|
274
|
+
### Telegram delivery
|
|
275
|
+
```bash
|
|
276
|
+
node --input-type=module -e "
|
|
277
|
+
import { initDb, getDb } from './db.js';
|
|
278
|
+
import { createJob } from './jobs.js';
|
|
279
|
+
initDb();
|
|
280
|
+
const job = createJob({
|
|
281
|
+
name: 'Telegram Test',
|
|
282
|
+
schedule_cron: '0 0 31 2 *',
|
|
283
|
+
payload_message: 'Confirm scheduler is working. Send a brief greeting.',
|
|
284
|
+
delivery_mode: 'announce',
|
|
285
|
+
delivery_channel: 'telegram',
|
|
286
|
+
delivery_to: 'YOUR_CHAT_ID',
|
|
287
|
+
delete_after_run: true,
|
|
288
|
+
origin: 'system',
|
|
289
|
+
run_timeout_ms: 300000,
|
|
290
|
+
});
|
|
291
|
+
getDb().prepare(\"UPDATE jobs SET next_run_at = datetime('now', '-1 second') WHERE id = ?\").run(job.id);
|
|
292
|
+
console.log('Created Telegram test:', job.id);
|
|
293
|
+
"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
You should receive a Telegram message within 30 seconds.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Step 10: Review Migrated Jobs
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
node cli.js jobs list
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
- Disable expired one-shot jobs: `node cli.js jobs disable <id>`
|
|
307
|
+
- Delete unwanted jobs: `node cli.js jobs delete <id>`
|
|
308
|
+
- Adjust timeouts: `node cli.js jobs update <id> '{"run_timeout_ms":600000}'`
|
|
309
|
+
- Verify cron conversions are correct for `every`-based schedules
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Step 11: Verify First Real Job
|
|
314
|
+
|
|
315
|
+
Wait for the next scheduled job and confirm:
|
|
316
|
+
```bash
|
|
317
|
+
tail -f /tmp/openclaw-scheduler.log
|
|
318
|
+
# Or after it fires:
|
|
319
|
+
node cli.js runs list <job-id>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Rollback
|
|
325
|
+
|
|
326
|
+
If anything goes wrong:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# 1. Stop scheduler
|
|
330
|
+
launchctl bootout gui/$UID/ai.openclaw.scheduler # if using LaunchAgent
|
|
331
|
+
sudo launchctl bootout system/ai.openclaw.scheduler # if using LaunchDaemon
|
|
332
|
+
|
|
333
|
+
# 2. Re-enable OC cron
|
|
334
|
+
openclaw cron edit <job-id> --enable # for each job
|
|
335
|
+
openclaw config set cron.enabled true
|
|
336
|
+
# remove OPENCLAW_SKIP_CRON=1 from gateway service env
|
|
337
|
+
|
|
338
|
+
# 3. Re-enable heartbeat
|
|
339
|
+
openclaw config set agents.defaults.heartbeat.every "5m"
|
|
340
|
+
openclaw gateway restart
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
For a complete removal (deleting all data), see [UNINSTALL.md](UNINSTALL.md).
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Upgrading
|
|
348
|
+
|
|
349
|
+
Already have the scheduler installed and need to update to a newer version? See [UPGRADING.md](UPGRADING.md).
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Validation Checklist
|
|
354
|
+
|
|
355
|
+
- [ ] `SCHEDULER_DB=:memory: node test.js` -- all passing, 0 failed
|
|
356
|
+
- [ ] `node cli.js status` → shows jobs, 0 stale
|
|
357
|
+
- [ ] `launchctl print gui/$UID/ai.openclaw.scheduler` or `sudo launchctl print system/ai.openclaw.scheduler` → running
|
|
358
|
+
- [ ] Log file has startup lines, no errors
|
|
359
|
+
- [ ] OC cron → all disabled
|
|
360
|
+
- [ ] OC heartbeat → `0m`
|
|
361
|
+
- [ ] Chat completions → 200
|
|
362
|
+
- [ ] Smoke test → dispatched + completed in log
|
|
363
|
+
- [ ] Telegram test → message received
|
|
364
|
+
- [ ] First real job → fires on schedule
|
package/JOB-QUICK-REF.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Job Quick Reference
|
|
2
|
+
|
|
3
|
+
Copy-paste patterns for common scheduler jobs.
|
|
4
|
+
|
|
5
|
+
## Shell job with cron schedule
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"name": "Daily Backup",
|
|
10
|
+
"schedule_cron": "0 2 * * *",
|
|
11
|
+
"schedule_tz": "America/New_York",
|
|
12
|
+
"session_target": "shell",
|
|
13
|
+
"payload_kind": "shellCommand",
|
|
14
|
+
"payload_message": "/usr/local/bin/backup.sh",
|
|
15
|
+
"run_timeout_ms": 600000,
|
|
16
|
+
"delivery_mode": "announce",
|
|
17
|
+
"delivery_channel": "telegram",
|
|
18
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
19
|
+
"origin": "system"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Agent task (isolated session)
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"name": "Morning Briefing",
|
|
28
|
+
"schedule_cron": "0 8 * * 1-5",
|
|
29
|
+
"schedule_tz": "America/New_York",
|
|
30
|
+
"session_target": "isolated",
|
|
31
|
+
"agent_id": "main",
|
|
32
|
+
"payload_kind": "systemEvent",
|
|
33
|
+
"payload_message": "Prepare the morning briefing with overnight alerts.",
|
|
34
|
+
"run_timeout_ms": 300000,
|
|
35
|
+
"delivery_mode": "announce-always",
|
|
36
|
+
"delivery_channel": "telegram",
|
|
37
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
38
|
+
"origin": "YOUR_CHAT_ID"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Main session event (inject into persistent session)
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"name": "Pending Acks Check",
|
|
47
|
+
"schedule_cron": "*/30 * * * *",
|
|
48
|
+
"session_target": "main",
|
|
49
|
+
"agent_id": "main",
|
|
50
|
+
"payload_kind": "systemEvent",
|
|
51
|
+
"payload_message": "Check for unacknowledged messages and follow up.",
|
|
52
|
+
"run_timeout_ms": 120000,
|
|
53
|
+
"delivery_mode": "none",
|
|
54
|
+
"origin": "system"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## One-shot job (run once at a specific time)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
openclaw-scheduler jobs add '{
|
|
62
|
+
"name": "Deploy v2.1",
|
|
63
|
+
"session_target": "shell",
|
|
64
|
+
"payload_kind": "shellCommand",
|
|
65
|
+
"payload_message": "deploy.sh v2.1",
|
|
66
|
+
"run_timeout_ms": 600000,
|
|
67
|
+
"delivery_mode": "announce-always",
|
|
68
|
+
"delivery_channel": "telegram",
|
|
69
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
70
|
+
"origin": "system"
|
|
71
|
+
}' --at '2026-04-01T14:00:00-04:00'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Or with relative time:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
openclaw-scheduler jobs add '{ ... }' --in '30m'
|
|
78
|
+
openclaw-scheduler jobs add '{ ... }' --in '2h'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Workflow chain (parent triggers child)
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
[
|
|
85
|
+
{
|
|
86
|
+
"name": "Nightly Score Capture",
|
|
87
|
+
"schedule_cron": "30 0 * * *",
|
|
88
|
+
"session_target": "shell",
|
|
89
|
+
"payload_kind": "shellCommand",
|
|
90
|
+
"payload_message": "capture-scores.sh",
|
|
91
|
+
"run_timeout_ms": 300000,
|
|
92
|
+
"delivery_mode": "announce",
|
|
93
|
+
"delivery_channel": "telegram",
|
|
94
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
95
|
+
"origin": "system"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "Auto-Settle Bets",
|
|
99
|
+
"parent_id": "<SCORE_CAPTURE_JOB_ID>",
|
|
100
|
+
"trigger_on": "success",
|
|
101
|
+
"session_target": "shell",
|
|
102
|
+
"payload_kind": "shellCommand",
|
|
103
|
+
"payload_message": "settle-bets.sh",
|
|
104
|
+
"run_timeout_ms": 300000,
|
|
105
|
+
"delivery_mode": "announce",
|
|
106
|
+
"delivery_channel": "telegram",
|
|
107
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
108
|
+
"origin": "system"
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Create parent first, then child with `parent_id` set to the parent's ID.
|
|
114
|
+
|
|
115
|
+
## Job with retries
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"name": "API Sync",
|
|
120
|
+
"schedule_cron": "0 */4 * * *",
|
|
121
|
+
"session_target": "shell",
|
|
122
|
+
"payload_kind": "shellCommand",
|
|
123
|
+
"payload_message": "sync-api.sh",
|
|
124
|
+
"run_timeout_ms": 120000,
|
|
125
|
+
"max_retries": 3,
|
|
126
|
+
"delivery_mode": "announce",
|
|
127
|
+
"delivery_channel": "telegram",
|
|
128
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
129
|
+
"origin": "system"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Job with approval gate
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"name": "Production Deploy",
|
|
138
|
+
"session_target": "shell",
|
|
139
|
+
"payload_kind": "shellCommand",
|
|
140
|
+
"payload_message": "deploy-prod.sh",
|
|
141
|
+
"run_timeout_ms": 600000,
|
|
142
|
+
"approval_required": true,
|
|
143
|
+
"approval_timeout_s": 3600,
|
|
144
|
+
"delivery_mode": "announce-always",
|
|
145
|
+
"delivery_channel": "telegram",
|
|
146
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
147
|
+
"origin": "system"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Approve or reject:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
openclaw-scheduler jobs approve <id>
|
|
155
|
+
openclaw-scheduler jobs reject <id> "not ready yet"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Multi-agent job (target a specific agent)
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"name": "Ops Agent Task",
|
|
163
|
+
"schedule_cron": "0 9 * * *",
|
|
164
|
+
"session_target": "isolated",
|
|
165
|
+
"agent_id": "ops",
|
|
166
|
+
"payload_kind": "systemEvent",
|
|
167
|
+
"payload_message": "Check infrastructure health.",
|
|
168
|
+
"run_timeout_ms": 300000,
|
|
169
|
+
"delivery_mode": "announce-always",
|
|
170
|
+
"delivery_channel": "telegram",
|
|
171
|
+
"delivery_to": "YOUR_CHAT_ID",
|
|
172
|
+
"origin": "YOUR_CHAT_ID"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Trigger conditions
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{ "trigger_on": "success" }
|
|
180
|
+
{ "trigger_on": "failure" }
|
|
181
|
+
{ "trigger_on": "complete" }
|
|
182
|
+
{ "trigger_on": "success", "trigger_condition": "contains:DEPLOYED" }
|
|
183
|
+
{ "trigger_on": "success", "trigger_condition": "regex:status:\\s*healthy" }
|
|
184
|
+
{ "trigger_on": "success", "trigger_delay_s": 60 }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Field reference
|
|
188
|
+
|
|
189
|
+
| Field | Type | Required | Description |
|
|
190
|
+
|-------|------|----------|-------------|
|
|
191
|
+
| `name` | string | yes | Job name |
|
|
192
|
+
| `schedule_cron` | string | yes* | Cron expression (5-field). *Not needed for triggered children or at-jobs |
|
|
193
|
+
| `schedule_tz` | string | no | Timezone (default: UTC) |
|
|
194
|
+
| `session_target` | string | yes | `shell`, `isolated`, or `main` |
|
|
195
|
+
| `agent_id` | string | no | Target agent (default: `main`) |
|
|
196
|
+
| `payload_kind` | string | yes | `shellCommand`, `systemEvent`, or `agentTurn` |
|
|
197
|
+
| `payload_message` | string | yes | Shell command or agent prompt |
|
|
198
|
+
| `payload_model` | string | no | Model override for agent tasks |
|
|
199
|
+
| `run_timeout_ms` | integer | yes | Max run duration in ms (no default) |
|
|
200
|
+
| `delivery_mode` | string | no | `none`, `announce`, `announce-always` |
|
|
201
|
+
| `delivery_channel` | string | no | Channel name (telegram, discord, etc.) |
|
|
202
|
+
| `delivery_to` | string | no | Chat ID, channel ID, or @alias |
|
|
203
|
+
| `origin` | string | yes (root jobs only; child jobs inherit) | Source chat ID or `system` |
|
|
204
|
+
| `parent_id` | string | no | Parent job ID (for chains) |
|
|
205
|
+
| `trigger_on` | string | no | `success`, `failure`, `complete` |
|
|
206
|
+
| `trigger_condition` | string | no | `contains:X` or `regex:X` |
|
|
207
|
+
| `trigger_delay_s` | integer | no | Delay before trigger fires |
|
|
208
|
+
| `max_retries` | integer | no | Retry count on failure |
|
|
209
|
+
| `overlap_policy` | string | no | `allow`, `skip`, `queue` |
|
|
210
|
+
| `approval_required` | boolean | no | Require HITL approval |
|
|
211
|
+
| `approval_timeout_s` | integer | no | Approval window in seconds |
|
|
212
|
+
| `enabled` | integer | no | 1 (enabled) or 0 (disabled) |
|
|
213
|
+
|
|
214
|
+
For the full field list, run `openclaw-scheduler schema jobs`.
|
|
215
|
+
|
|
216
|
+
## Delivery channels
|
|
217
|
+
|
|
218
|
+
All channels supported by the OpenClaw gateway work with the scheduler:
|
|
219
|
+
Telegram, Discord, WhatsApp, Signal, iMessage, and Slack.
|
|
220
|
+
|
|
221
|
+
Examples in this document use `telegram` as the delivery_channel.
|
|
222
|
+
Replace with your channel of choice.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenClaw Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|