#9088: fix(cron): ensure nextRunAtMs is computed when enabled is undefined (#9056)
stale
Cluster:
Cron Job Fixes
## Summary
Fixes #9056 - cron.add agent tool doesn't set state.nextRunAtMs, causing jobs to never auto-execute.
## Root Cause
When creating a job via the agent tool, <code>input.enabled</code> could be <code>undefined</code>, which passed the typeof check but resulted in <code>enabled</code> being falsy. This caused <code>computeJobNextRunAtMs()</code> to return <code>undefined</code>.
## Changes
- Fixed enabled default logic to handle <code>undefined</code>, <code>null</code>, and <code>false</code> correctly
- Added explicit state initialization before computing nextRunAtMs
- Ensures jobs created via agent tool execute the same as CLI-created jobs
## Testing
- [x] Bug #9056 reproduction case now works
- [x] Jobs created via agent tool now have state.nextRunAtMs set
- [x] Backward compatible with existing job creation paths
## Impact
| Method | Before | After |
|--------|--------|-------|
| Agent tool (cron.add) | ❌ state.nextRunAtMs empty | ✅ state.nextRunAtMs set |
| CLI (openclaw cron add) | ✅ Works | ✅ Still works |
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates cron job creation so jobs added via the `cron.add` agent tool always get `state.nextRunAtMs` computed. In `src/cron/service/jobs.ts`, the `enabled` defaulting logic is adjusted to treat `undefined`/missing as enabled (while preserving explicit `false`), and `job.state` is defensively initialized before setting `job.state.nextRunAtMs = computeJobNextRunAtMs(job, now)`. This aligns agent-created jobs with the CLI creation path so they auto-execute as expected.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Change is small, localized to cron job creation, and adds defensive state initialization plus clearer enabled defaulting to prevent jobs being created without nextRunAtMs. No behavioral change for explicit enabled=false, and the new code follows an existing pattern already used elsewhere.
- src/cron/service/jobs.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#8701: fix: default enabled to true for cron jobs created via tool API
by maximus-claw · 2026-02-04
86.7%
#11813: fix(cron): ensure 'at' schedule type correctly registers nextWakeAt...
by leo-reifying · 2026-02-08
84.8%
#12303: fix(cron): correct nextRunAtMs calculation and prevent timer stall
by colddonkey · 2026-02-09
84.1%
#8811: fix(cron): handle atMs fallback for kind=at jobs
by hlibr · 2026-02-04
84.1%
#5428: fix(Cron): prevent one-shot loop on skip
by imshrishk · 2026-01-31
83.3%
#8698: fix(cron): default enabled to true for new jobs
by emmick4 · 2026-02-04
83.0%
#7984: fix undefined variable in cron
by ThunderDrag · 2026-02-03
82.9%
#12443: fix(cron): don't advance past-due jobs that haven't been executed
by rummangeminicode · 2026-02-09
82.9%
#12747: fix: catch up missed cron-expression job runs on restart
by obin94-commits · 2026-02-09
82.4%
#8837: fix(cron): guard against undefined job.state in printCronList
by fxd-jason · 2026-02-04
82.0%