Skip to content

[Improvement]: cron: native script execution payload (bypass LLM for deterministic jobs) #11

@Arry8

Description

@Arry8

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:

  1. Model ignores the command and responds conversationally
  2. Model tries to recreate or modify the script before running it
  3. Model hallucinates output instead of executing
  4. Wastes tokens on full agent turn overhead (system prompt, bootstrap, tool dispatch) for a deterministic task
  5. Non-deterministic — same job produces different behavior across runs

Acceptance criteria

  • New payload.kind: "script" with command, args?, env?, cwd?, timeoutSeconds? fields
  • Scripts execute via child_process.execFile (no shell — no injection risk)
  • Script paths resolved via resolveUserPath with workspace base dir
  • stdout captured as summary; stderr captured as error on non-zero exit
  • Timeout enforcement via abort signal (default: job-level timeoutSeconds or 300s)
  • File existence validated before spawn (clear error message)
  • Optional deliver: true routes stdout through existing delivery pipeline
  • CLI --script flag on openclaw cron add sets payload.kind = "script"
  • Zod schema and gateway protocol schema updated
  • Existing agentTurn and systemEvent jobs unaffected
  • Unit tests for: script execution, timeout, path validation, env merging, error handling

Implementation plan

  1. Add CronScriptPayload type to src/cron/types.ts
  2. Create src/cron/exec-script.tsexecCronScript() function (~60 lines): resolve path, validate, spawn, capture output, handle timeout
  3. Add payload.kind === "script" branch in executeJobCore (src/cron/service/timer.ts)
  4. Add Zod schema for script payload fields (src/config/zod-schema.ts)
  5. Update gateway cron schema (src/gateway/protocol/schema/cron.ts)
  6. Add CLI --script, --script-args, --script-env options to src/cli/cron-cli/register.cron-add.ts
  7. Add unit tests (src/cron/exec-script.test.ts)
  8. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions