openclaw - ✅(Solved) Fix feat: preHook gate for cron and heartbeat pre-run script checks [1 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#62185Fetched 2026-04-08 03:07:52
View on GitHub
Comments
1
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
referenced ×2commented ×1cross-referenced ×1

Error Message

| Any other | Error (increments consecutiveErrors, triggers backoff/alerts) |

  • Exit code 10 skips without incrementing error counters

Fix Action

Fixed

PR fix notes

PR #62195: feat(cron): add preHook gate for pre-run script checks

Description (problem / solution / changelog)

Summary

Adds an optional preHook configuration for cron jobs and heartbeat triggers that runs a shell command before agent execution. This gates agent runs on system preconditions (disk space, network, API availability) — eliminating wasteful runs on resource-constrained hosts.

  • Exit 0: proceed with agent execution
  • Exit 10: skip (not counted as a failure, consecutiveErrors stays at 0)
  • Any other: error (increments consecutiveErrors, triggers backoff/alerts)

Config example (cron)

{
  schedule: "cron 0 8 * * 1-5",
  preHook: {
    command: "ping -c1 -W2 api.openai.com > /dev/null 2>&1",
    timeoutSeconds: 10,
  },
}

Config example (heartbeat)

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        preHook: {
          command: "/usr/local/bin/check-should-run.sh",
          timeoutSeconds: 30,
        },
      },
    },
  },
}

Changes

  • New: src/cron/pre-hook.ts — core preHook runner with cross-platform shell support, timeout, maxBuffer handling, AbortSignal forwarding
  • New: src/cron/pre-hook.test.ts — 9 tests covering all exit paths
  • Types: preHook field on CronJobBase (flows to CronJob/Create/Patch), heartbeat config, zod schema
  • Cron integration: preHook gate in executeJobCore() before session-target dispatch; AbortSignal propagated from timer through server-cron bridge to heartbeat runner
  • Heartbeat integration: preHook gate after preflight + session lane check, before agent turn; emits heartbeat events on skip/error
  • Normalization: validates command string, clamps timeoutSeconds 1-300, rejects bare strings/primitives
  • Protocol schemas: CronPreHookSchema added to CronJob, CronAdd, CronJobPatch (nullable in patch)
  • Tool schemas: preHook in CRON_RECOVERABLE_OBJECT_KEYS and both add/update tool schemas
  • Docs: pre-run hooks sections in cron-jobs.md, heartbeat.md, configuration-reference.md

Review feedback addressed (from prior PRs #17529, #49415, #53789, #54239)

#IssueFix
1maxBuffer unknown exit treated as skipNow always "error"
2preHook ran before preflightPlaced after preflight + session lane check
3stdout/stderr missing from logsIncluded in both cron and heartbeat log context
4AbortSignal not propagatedThreaded through state.ts → server-cron.ts → heartbeat-runner.ts
5No abort check before spawnChecked in pre-hook.ts before execFile
6Missing heartbeat event on skip/erroremitHeartbeatEvent on both paths
7Docs exit-code mismatchCorrected in all 3 doc files
8Bare string preHook acceptedRejected in normalize.ts
9Typed tool schemas missing preHookAdded to both add and update schemas

Closes #62185

Test plan

  • pnpm test src/cron/pre-hook.test.ts — 9/9 passing
  • pnpm test src/cron/normalize.test.ts — 60/60 passing (10 new preHook tests)
  • pnpm check — no new errors (12 pre-existing on main)
  • pnpm test — full suite
  • Manual: cron job with preHook: { command: "exit 0" } → job runs
  • Manual: preHook: { command: "exit 10" } → job skipped, no error count
  • Manual: preHook: { command: "exit 1" } → job blocked, errors increment

Changed files

  • docs/automation/cron-jobs.md (modified, +27/-0)
  • docs/gateway/configuration-reference.md (modified, +3/-0)
  • docs/gateway/heartbeat.md (modified, +28/-0)
  • src/agents/tools/cron-tool.ts (modified, +29/-0)
  • src/config/types.agent-defaults.ts (modified, +2/-0)
  • src/config/zod-schema.agent-runtime.ts (modified, +7/-0)
  • src/cron/normalize.test.ts (modified, +65/-0)
  • src/cron/normalize.ts (modified, +35/-0)
  • src/cron/pre-hook.test.ts (added, +77/-0)
  • src/cron/pre-hook.ts (added, +123/-0)
  • src/cron/service/jobs.ts (modified, +4/-0)
  • src/cron/service/state.ts (modified, +1/-0)
  • src/cron/service/timer.ts (modified, +28/-0)
  • src/cron/types-shared.ts (modified, +4/-0)
  • src/cron/types.ts (modified, +6/-1)
  • src/gateway/protocol/schema/cron.ts (modified, +11/-0)
  • src/gateway/server-cron.ts (modified, +1/-0)
  • src/infra/heartbeat-runner.ts (modified, +41/-0)

Code Example

{
  // Cron job preHook
  "preHook": {
    "command": "ping -c1 -W2 api.openai.com > /dev/null 2>&1",
    "timeoutSeconds": 10
  }
}

---

{
  // Heartbeat preHook
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "preHook": {
          "command": "/usr/local/bin/check-should-run.sh",
          "timeoutSeconds": 30
        }
      }
    }
  }
}
RAW_BUFFERClick to expand / collapse

Problem

Operators running OpenClaw on resource-constrained hosts (Raspberry Pi, shared VMs, metered cloud) have no native way to gate cron or heartbeat agent runs on system preconditions — disk space, network reachability, API availability, or dependent service health. Everyone rebuilds custom wrapper logic independently, which is fragile and hard to maintain.

Proposal

Add an optional preHook configuration for both cron jobs and heartbeat triggers that runs a shell command before agent execution, using exit codes to decide whether to proceed, skip, or abort.

Exit Code Contract

Exit CodeBehavior
0Proceed with agent execution
10Skip this run (not a failure, consecutiveErrors stays at 0)
Any otherError (increments consecutiveErrors, triggers backoff/alerts)

Configuration Example

{
  // Cron job preHook
  "preHook": {
    "command": "ping -c1 -W2 api.openai.com > /dev/null 2>&1",
    "timeoutSeconds": 10
  }
}
{
  // Heartbeat preHook
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "preHook": {
          "command": "/usr/local/bin/check-should-run.sh",
          "timeoutSeconds": 30
        }
      }
    }
  }
}

Behavior

  • Pre-hook runs before agent execution (after heartbeat preflight checks)
  • Captures stdout, stderr, and exit code for logging
  • Timeout enforced via timeoutSeconds (default 30s, max 300s)
  • Cross-platform: /bin/sh -c on Unix, cmd.exe /c on Windows
  • AbortSignal propagation from cron timeout through to shell process

Acceptance Criteria

  • Cron jobs support preHook configuration
  • Heartbeat trigger supports preHook configuration
  • Exit code 10 skips without incrementing error counters
  • stdout/stderr captured in structured logs
  • Timeout enforcement works correctly
  • AbortSignal properly cancels running pre-hook processes
  • Cron tool schemas declare preHook for add/update actions

Related

  • Supersedes discussion in #49370
  • Prior attempts: #17529, #49415, #53789, #54239

extent analysis

TL;DR

Implement the proposed preHook configuration for cron jobs and heartbeat triggers to gate agent runs based on system preconditions.

Guidance

  • Review the proposed preHook configuration and its exit code contract to understand how it can be used to control agent execution.
  • Test the preHook configuration with different shell commands and exit codes to verify its behavior, including the handling of exit code 10 to skip agent execution without incrementing error counters.
  • Ensure that the timeoutSeconds parameter is properly enforced and that AbortSignal propagation works correctly to cancel running pre-hook processes.
  • Validate that the preHook configuration is properly declared in the cron tool schemas for add and update actions.

Example

{
  "preHook": {
    "command": "df -h / | awk '{print $5}' | sed 's/%//g' | awk '{if ($1 < 10) exit 10; else exit 0}'",
    "timeoutSeconds": 10
  }
}

This example checks the available disk space and skips the agent execution if it's below 10%.

Notes

The proposed solution relies on the correct implementation of the preHook configuration and its integration with the existing cron and heartbeat mechanisms. It's essential to thoroughly test the solution to ensure it works as expected in different scenarios.

Recommendation

Apply the proposed preHook configuration workaround to gate agent runs based on system preconditions, as it provides a flexible and customizable solution to the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING