Summary
Add a payload.kind: "script" option to cron jobs that executes scripts directly via child_process.execFile — no LLM agent turn, no token cost, deterministic execution.
Problem
61 of 63 cron jobs use a workaround: the agentTurn payload tells the model "Run: cd ~/.openclaw/workspace && node scripts/foo.cjs". The model spins up a full agent session just to invoke execFile. This fails frequently because:
- Model ignores the command and responds conversationally
- Model tries to recreate or modify the script before running it
- Model hallucinates output instead of executing
- Wastes tokens on full agent turn overhead (system prompt, bootstrap, tool dispatch) for a deterministic task
- Non-deterministic — same job produces different behavior across runs
Acceptance criteria
Implementation plan
- Add
CronScriptPayload type to src/cron/types.ts
- Create
src/cron/exec-script.ts — execCronScript() function (~60 lines): resolve path, validate, spawn, capture output, handle timeout
- Add
payload.kind === "script" branch in executeJobCore (src/cron/service/timer.ts)
- Add Zod schema for script payload fields (
src/config/zod-schema.ts)
- Update gateway cron schema (
src/gateway/protocol/schema/cron.ts)
- Add CLI
--script, --script-args, --script-env options to src/cli/cron-cli/register.cron-add.ts
- Add unit tests (
src/cron/exec-script.test.ts)
- Create one-time migration script for existing 61 jobs (
scripts/migrate-cron-to-script-payload.ts)
Files affected
src/cron/types.ts (modify — add CronScriptPayload)
src/cron/exec-script.ts (new)
src/cron/exec-script.test.ts (new)
src/cron/service/timer.ts (modify — add script branch in executeJobCore)
src/config/zod-schema.ts (modify — add script payload schema)
src/gateway/protocol/schema/cron.ts (modify)
src/cron/normalize.ts (modify — normalize script fields)
src/cli/cron-cli/register.cron-add.ts (modify — add --script flag)
src/cli/cron-cli/shared.ts (modify — script payload construction)
scripts/migrate-cron-to-script-payload.ts (new)
Additional notes
- Full plan:
.claude/plans/cron-script-payload.md
- Security:
execFile (not exec) prevents shell injection; no pipes, redirects, or command chaining
- Migration: a one-time script parses
Run: cd ... && node scripts/... patterns from existing jobs and converts to { kind: "script" } payloads
- The 2 jobs that genuinely need the LLM ("On This Day Mystery Image", "Daily Investment Analysis") stay as
agentTurn
- This is an upstream-worthy feature — will PR to openclaw/openclaw after local validation
Summary
Add a
payload.kind: "script"option to cron jobs that executes scripts directly viachild_process.execFile— no LLM agent turn, no token cost, deterministic execution.Problem
61 of 63 cron jobs use a workaround: the
agentTurnpayload tells the model "Run: cd ~/.openclaw/workspace && node scripts/foo.cjs". The model spins up a full agent session just to invokeexecFile. This fails frequently because:Acceptance criteria
payload.kind: "script"withcommand,args?,env?,cwd?,timeoutSeconds?fieldschild_process.execFile(no shell — no injection risk)resolveUserPathwith workspace base dirsummary; stderr captured as error on non-zero exittimeoutSecondsor 300s)deliver: trueroutes stdout through existing delivery pipeline--scriptflag onopenclaw cron addsetspayload.kind = "script"agentTurnandsystemEventjobs unaffectedImplementation plan
CronScriptPayloadtype tosrc/cron/types.tssrc/cron/exec-script.ts—execCronScript()function (~60 lines): resolve path, validate, spawn, capture output, handle timeoutpayload.kind === "script"branch inexecuteJobCore(src/cron/service/timer.ts)src/config/zod-schema.ts)src/gateway/protocol/schema/cron.ts)--script,--script-args,--script-envoptions tosrc/cli/cron-cli/register.cron-add.tssrc/cron/exec-script.test.ts)scripts/migrate-cron-to-script-payload.ts)Files affected
src/cron/types.ts(modify — add CronScriptPayload)src/cron/exec-script.ts(new)src/cron/exec-script.test.ts(new)src/cron/service/timer.ts(modify — add script branch in executeJobCore)src/config/zod-schema.ts(modify — add script payload schema)src/gateway/protocol/schema/cron.ts(modify)src/cron/normalize.ts(modify — normalize script fields)src/cli/cron-cli/register.cron-add.ts(modify — add --script flag)src/cli/cron-cli/shared.ts(modify — script payload construction)scripts/migrate-cron-to-script-payload.ts(new)Additional notes
.claude/plans/cron-script-payload.mdexecFile(notexec) prevents shell injection; no pipes, redirects, or command chainingRun: cd ... && node scripts/...patterns from existing jobs and converts to{ kind: "script" }payloadsagentTurn