OpenClaw cron

Scheduled background jobs (mcp__openclaw__cron) that spawn their own session and run autonomously — daily self-improvement cycles, nightly job-hunt digests, apartment-search sankeys.

Dogfooded continuously since at least 2026-08-08 through the daily 6am self-improving cycle (this entry is being written by one), plus two nightly report jobs (job-opportunities-sankey-daily, apartment-hunt-sankey-daily).

Goals

Run recurring prompts on a schedule, in an isolated session, without a human in the loop — the daily self-improvement reflection, nightly job-hunt and apartment-hunt sankey digests, PR watchers, and similar. The job's own session should be inspectable later to confirm it ran and see what it did.

Effectiveness

Adequate, with a real asymmetry. The scheduling itself is solid: jobs have fired on time, every day, for at least five days straight, with real side effects (files written, emails checked, reports delivered). But a session spawned by a cron job cannot see the real mcp__openclaw__cron tool at all — ToolSearch only ever resolves the session-scoped CronList/CronDelete built-ins, which track jobs created via CronCreate in-session and see zero of the actual persistent jobs. Confirmed independently five days running (2026-08-08 through today), across different jobs and different sessions. A cron job cannot list itself, disable itself, or edit its own stored step definition — any of that requires a human, or an agent, acting from an unrelated live session that happens to expose the real tool.

What made it effective

Friction, pain points, surprises

A cron session can't act on itself. job-opportunities-sankey-daily's render step has shelled out to the now-removed rtk binary since 2026-08-13, and every run since has silently worked around it with a PUPPETEER_EXECUTABLE_PATH fallback rather than actually fixing the stored step — because the session doing the work has no path to mcp__openclaw__cron's edit capability to fix its own definition. Same story for an unrelated PR-watcher job that confirmed its own watched PRs had merged and tried, and failed, to disable itself three days running. The fix has to come from a session outside the loop.

A three-day "silent failure" that wasn't. Two report-generating cron jobs left nothing but a two-line stub in their own session file — handoff prompt in, no assistant response ever written back — which read, for three consecutive daily reviews, as jobs silently dying mid-run. Cross-referencing message-level timestamps resolved it today: the actual completed reports (an evening job-hunt digest, an apartment-search sankey image) appear a few minutes later in the destination channel's session (the main WhatsApp thread), not in the cron run's own file. The work was never failing — the output is delivered to wherever the job messages the user, and the cron session itself simply never gets the assistant's final response appended to it. Auditing "did this job actually run" from the cron session alone will get the wrong answer; the real record lives in the channel it reported to.

Verdict: adequate. The scheduler does its one job — fire prompts on time, autonomously, for real work — without a single missed cycle observed. But a cron-spawned session is structurally blind to the tool that manages its own kind, which turns "the job needs a one-line edit" into "flag it and wait for a human," and turns "did it run" into a small forensic exercise across two different session files.

Update, 2026-08-25/26: the mystery finally cracked, in two wrong turns before the right one

The above described a pattern that recurred across five separate dated entries (2026-08-08, 09, 10, 20, 25) without ever finding the actual root cause — every attempt assumed mcp__openclaw__cron was a real agent-facing tool that some sessions simply couldn't reach, and chased tool-grant theories: maybe it's a tools.deny allowlist gap, maybe it's session staleness, maybe it's a claude-cli vs. embedded-runtime split. On 2026-08-25, delegating a genops daily-reflection cron unblocked the real investigation:

  1. First theory (wrong): missing tools grant. genops's agent entry had no tools key at all, unlike main's {"deny": []}. Patched it to match, restarted the gateway. Still no mcp__openclaw__cron.
  2. Second theory (wrong): stale session. Spawned a completely fresh genops session to rule out an 18-hour-old session just not having picked up the new grant. Still nothing — and checking directly, main's own long-running WhatsApp session already has {"deny": []} and still can't see the tool. Tool-grant theories were dead.
  3. Third theory (also wrong, briefly): "it's not wired as an MCP tool to agents at all." A coding-agent investigation found the actual working mechanism — the openclaw cron CLI, talking directly to the Gateway, state under /home/user/.openclaw/cron/ — and concluded the MCP tool simply doesn't exist for any agent. This closed the loop enough to create the real job (genops-daily-self-improving), but it was still wrong: cron is a real, documented agent-facing tool (docs/automation/cron-jobs.md, part of group:automation), and a separate fresh CLI session loaded it directly the same day with no special config.

The actual, still-not-fully-explained state, confirmed again 2026-08-26 from this very cron job's own execution context: cron is a real tool that some sessions get and claude-cli-runtime sessions (WhatsApp/direct, cron-spawned runs, fresh genops spawns — every variant tried) never do, regardless of tools.deny config. Nobody chasing this for 18 days thought to check the docs first, which would have shown the internal contradiction immediately (the very next TOOLS.md section already referenced mcp__openclaw__cron action=list as real).

What made the eventual resolution effective: treating the CLI as the reliable fallback path unblocked all real work immediately (the genops job now runs daily) even before the "why" was fully understood — the mechanism didn't need to be theoretically complete to be usable. What extended the friction unnecessarily: each of the first two wrong theories was tested and disproven with real evidence (config diffs, fresh-session spawns) rather than being caught by the cheaper check of just reading the docs first — an 18-day, five-separate-incident mystery had its actual shape sitting in docs/automation/cron-jobs.md the entire time.

Updated verdict: still adequate, mystery half-solved. Any session with Bash access has a fully reliable, documented workaround (openclaw cron add/list/show/edit/enable/disable/rm) that never needed to wait on this investigation. What remains genuinely open — why claude-cli-runtime chat/cron sessions specifically never get a real, documented, agent-facing tool bundled — is now a precisely scoped question instead of an amorphous one, which is its own kind of progress even without a final answer.