无需LLM介入,定时运行bash脚本;零模型开销,热重载,纯shell。是openclaw/openclaw#80793实现前的临时方案。
Run bash scripts on a schedule — no LLM, no agent turns, zero model cost.
This is a practical workaround for the missing payload.kind: "script" in OpenClaw cron
( issue #80793,
issue #18160).
It uses a gateway startup hook to load a directory of shell scripts and schedule them with
the same croner library OpenClaw already bundles — no extra dependencies.
Use script cronUse LLM cronHealth checks, HTTP pingsSummarising logsFile/lock cleanupDeciding what to reportFixed Telegram/webhook notificationsWriting weekly digestsGit pulls, backupsAny task needing reasoningWatching directories for changesClassifying content
If a task doesn't need a brain, it shouldn't spin up one.
Copy hooks/cron-scripts-loader/handler.ts from this skill into your OpenClaw hooks directory:
bash
mkdir -p ~/.openclaw/hooks/cron-scripts-loader
cp <skill-dir>/hooks/cron-scripts-loader/handler.ts \
~/.openclaw/hooks/cron-scripts-loader/handler.ts
Then restart the gateway:
bash
openclaw gateway restart
The hook registers itself on gateway.startup and begins watching
~/.openclaw/cron-scripts/ immediately. No further config needed.
bash
mkdir -p ~/.openclaw/cron-scripts
The hook creates this automatically on first startup, but creating it now lets you add scripts before restarting.
Every script needs a short frontmatter block in the first 20 lines:
bash
#!/usr/bin/env bash
# name: my-job # required — shown in gateway logs
# schedule: 0 8 * * * # required — standard 5-field cron expression
# tz: Europe/Berlin # optional — IANA timezone (default: UTC)
# timeout: 120 # optional — seconds before SIGTERM (default: 120)
# ... your script here
The cron expression is written in wall-clock time of the given tz — do not
convert to UTC yourself.
Then drop it in ~/.openclaw/cron-scripts/ and make it executable:
bash
chmod +x ~/.openclaw/cron-scripts/my-job.sh
No restart needed. The hook watches the directory with fs.watch and hot-reloads
within ~300ms of any file change.
Scripts can post to any OpenClaw channel via the local announce API:
bash
# Post to a Telegram user
curl -sf -X POST http://localhost:3000/api/announce \
-H "Content-Type: application/json" \
-d "{\"text\": \"Hello from script cron\", \"channel\": \"telegram\", \"to\": \"<YOUR_CHAT_ID>\"}"
Or call external services directly (Telegram Bot API, Slack webhooks, etc.).
my-job.sh.disabled — the watcher ignores non- .sh filesAll script output is captured and forwarded to the gateway log under
[cron-scripts-loader][<name>]:
text
[cron-scripts-loader][my-job] Starting run
[cron-scripts-loader][my-job] some stdout line
[cron-scripts-loader][my-job] Finished ok (exit 0)
Non-zero exit codes are logged as errors but never crash other jobs.
See examples/health-check.sh for a minimal HTTP health check that posts failures
to Telegram.
protect: true) to prevent pile-upscroner from OpenClaw's own node_modules — tested against OpenClaw
2026.x; if croner moves, update the require path in the hookThis skill was built as a workaround for:
If those issues are resolved natively, this skill becomes unnecessary. Until then, it's the cleanest way to keep your cron inventory unified in one place without burning model tokens on tasks that are pure bash.