← Back to PRs

#20492: feat(cron): gate script evaluated before agent turn

by clawmander open 2026-02-19 00:59 View on GitHub →
docs cli size: M
## Summary Adds an optional `gate` field to cron jobs that runs a shell script before the agent turn. The agent fires only when the gate exits with `triggerExitCode` (default 0). Any other exit code or timeout silently skips the job at **zero LLM cost**. ## Motivation A common pattern in cron-driven agents is "check if there is anything to do, then do it". Today, even when there is nothing to do, the job still spins up an isolated agent session or wakes the heartbeat — burning tokens and time. A gate lets you express the condition in a short shell script and skip the expensive part entirely. Real-world examples: ```bash # Only run PR-review agent when open PRs exist openclaw cron add \ --name "PR review" \ --cron "0 */2 * * *" \ --session isolated \ --message "Review open PRs and summarise findings." \ --gate "gh pr list --repo myorg/myrepo --state open --json number --jq 'length > 0'" \ --announce # Only alert when disk usage is above 80 % openclaw cron add \ --name "Disk alert" \ --cron "0 * * * *" \ --session main \ --system-event "Disk usage is critical — investigate and report." \ --gate "bash -c '[ \ -ge 80 ]'" # Custom exit code: trigger only when script finds work (exits 1) openclaw cron add \ --name "Queue drain" \ --cron "*/5 * * * *" \ --session isolated \ --message "Process the pending task queue." \ --gate "~/scripts/has-pending-tasks.sh" \ --gate-exit-code 1 ``` ## Schema changes ```ts // New type type CronGate = { command: string; // shell command (full shell syntax via /bin/sh -c) triggerExitCode?: number; // exit code that allows the agent; defaults to 0 timeoutMs?: number; // gate killed after this many ms; defaults to 30 000 }; // New optional field on CronJob gate?: CronGate; ``` `CronJobPatch.gate` accepts `CronGate | null` — null removes an existing gate. ## New CLI flags ``` cron add / cron edit: --gate <cmd> Shell command to run as the gate --gate-exit-code <n> Exit code that lets the agent proceed (default 0) --gate-timeout-ms <n> Max ms before the gate is killed (default 30000) cron edit only: --clear-gate Remove the gate from an existing job ``` ## Implementation | File | Change | |---|---| | `src/cron/types.ts` | `CronGate` type; `CronJob.gate` field; `CronJobPatch.gate` | | `src/cron/gate.ts` | New gate runner — `child_process.execFile` via `/bin/sh -c` / `cmd /c`, resolves immediately on timeout (SIGKILL sent async) | | `src/cron/service/timer.ts` | Gate check at the top of `executeJobCore`, before any agent or heartbeat work | | `src/cron/service/jobs.ts` | Gate normalisation and validation in `createJob` and `applyJobPatch` | | `src/cli/cron-cli/register.cron-add.ts` | `--gate`, `--gate-exit-code`, `--gate-timeout-ms` | | `src/cli/cron-cli/register.cron-edit.ts` | Same flags + `--clear-gate` | ## Tests - **8 unit tests** in `src/cron/gate.test.ts`: exit code pass/fail, custom `triggerExitCode`, timeout, shell pipeline syntax, empty command - **7 tests** appended to `src/cron/service.jobs.test.ts`: `applyJobPatch` gate set, replace, null-remove, and validation errors All 25 new + existing tests pass. ## Backward compatibility Fully additive — existing jobs without a `gate` field are unaffected. The `gate` field is optional throughout the type hierarchy and stored only when explicitly set. <!-- greptile_comment --> <h3>Greptile Summary</h3> Adds an optional `gate` field to cron jobs — a shell script that runs before the agent turn to conditionally skip job execution at zero LLM cost. The gate passes when the script exits with the configured `triggerExitCode` (default 0). **Changes:** - Added `CronGate` type with `command`, `triggerExitCode`, and `timeoutMs` fields - Implemented gate runner in `src/cron/gate.ts` using `execFile` via `/bin/sh -c` (POSIX) or `cmd /c` (Windows) - Integrated gate check at the top of `executeJobCore` in timer service - Added CLI flags: `--gate`, `--gate-exit-code`, `--gate-timeout-ms`, `--clear-gate` - Gate validation and normalization in job creation/patching - 8 unit tests for gate runner, 7 tests for service integration **Issues found:** - Timer cleanup logic in `src/cron/gate.ts:65-94` needs refinement to prevent potential memory leak <h3>Confidence Score: 4/5</h3> - Safe to merge with minor timer cleanup issue that should be addressed - The implementation is well-designed with proper validation, error handling, platform compatibility, and comprehensive test coverage. However, there's a timer cleanup issue in the gate runner that could cause a memory leak in edge cases. The feature is additive and backward compatible, with no impact on existing jobs. - src/cron/gate.ts needs timer cleanup fix in the execFile callback <sub>Last reviewed commit: aa43b8f</sub> <!-- greptile_other_comments_section --> <sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub> <!-- /greptile_comment -->

Most Similar PRs