Skip to content
Back to skills

Cron Doctor

BSecurity

Diagnose and validate cron expressions before they ship. Catches the five silent death-traps: impossible dates that never fire, OR-semantics that fire too often, midnight spikes, uneven step drift, an

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 11, 2026
devopsjavascriptgojavabashnodeexpressdockerkubernetesdebugginggit

Works with

  • cli

Security analysis

B77/100
  • highCreates or modifies cron jobs for persistent execution
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 11, 2026

npx -y skills add ranbot-ai/awesome-skills --skill cron-doctor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cron Doctor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cron Doctor
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/ranbot-ai-cron-doctor/badge)](https://www.skillsdirectory.com/skills/ranbot-ai-cron-doctor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cron-doctor
description: Diagnose and validate cron expressions before they ship. Catches the five silent death-traps: impossible dates that never fire, OR-semantics that fire too often, midnight spikes, uneven step drift, an
category: Document Processing
source: antigravity
tags: [javascript, node, claude, ai, agent, security, docker, kubernetes, cro]
url: https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/cron-doctor
---


# cron-doctor

## Overview

Cron is deceptively error-prone. The failure mode is **silent** — a syntactically
valid expression that simply never fires, or fires far more often than intended.
`0 0 30 2 *` parses cleanly and then sits dead forever (February has no 30th).
`0 0 1,15 * 1` looks like "1st and 15th if Monday" but actually means "1st, 15th,
**OR** every Monday" — ~6 fires/month instead of ~2.

This skill teaches an agent to catch those before they reach production. It comes
with a zero-dependency validation engine (`scripts/cron-engine.js`, no install
needed) that parses, describes, deep-validates, and computes next fire times.

## When to Use This Skill

- Use when a user writes, edits, reviews, or deploys a cron expression — in a
  crontab, a Kubernetes `CronJob`, a GitHub Actions `schedule`, an Airflow DAG,
  a Celery beat schedule, a systemd timer, or any scheduled task.
- Use when debugging a job that "didn't fire" or "fired at the wrong time."
- Use when a user asks "what does this cron expression mean?" or "when will this
  run next?" or "how often does this run per year?"
- Use when reviewing a CI/CD pipeline or infrastructure config that contains a
  `schedule` field.
- Use when a user pastes a 5-field cron expression and asks for a sanity check.

## How It Works

### Step 1: Parse the expression

Split on whitespace into 5 fields: minute, hour, day-of-month, month, day-of-week.
Confirm valid ranges:

| Field | Position | Range | Notes |
|-------|----------|-------|-------|
| minute | 1 | 0–59 | |
| hour | 2 | 0–23 | |
| day-of-month | 3 | 1–31 | |
| month | 4 | 1–12 | names (JAN–DEC) accepted |
| day-of-week | 5 | 0–7 | 0 and 7 both = Sunday; names (SUN–SAT) accepted |

### Step 2: Describe it in plain English

State what the user *thinks* it does vs. what it *actually* does. Be explicit
about OR-vs-AND semantics for day-of-month + day-of-week (see death-trap #2).

### Step 3: Run the trap checklist

Check the five death-traps below and flag any that apply.

### Step 4: Calculate next runs and annual fire count

Compute the next 5 fire times as concrete dates so the user can verify the
schedule behaves as expected. Estimate annual fire count — a schedule that fires
365×/year vs. 12×/year is a ~30× cost and load difference.

## The Five Cron Death-Traps

These are the bugs that pass `crontab -l` validation but break in production.

### 1. Impossible dates — the "never fires" bug

```
0 0 30 2 *
```

**Valid syntax. Never fires.** February has no 30th. This schedule is a dead job
that silently sits forever. The same applies to day 31 in any 30-day month:
`0 0 31 4 *`, `0 0 31 6 *`, `0 0 31 9 *`, `0 0 31 11 *`.

**Fix:** use `0 0 28-31 * *` and check for end-of-month in the script, or use `L`
(last day) syntax if your scheduler supports it.

### 2. OR-semantics — the "fires too often" bug

```
0 0 1,15 * 1
```

**Does NOT mean** "midnight on the 1st and 15th if it's Monday."
**Does mean** "midnight on the 1st, the 15th, **OR** every Monday." That's ~6
fires/month instead of ~2.

This is the single most misunderstood cron rule. When **both** day-of-month AND
day-of-week are restricted (neither is `*`), cron uses OR logic, not AND.

**Fix:** if you need "1st and 15th only if Monday," run daily and check in the
script:

```bash
0 0 * * 1 [ "$(date +%d)" = "01" -o "$(date +%d)" = "15" ] && your-command
```

### 3. Midnight spike — the "everything at once" bug

```
0 0 * * *
```

Every job scheduled at `0 0` competes for resources at exactly 00:00. Database
backups, log rotations, cert renewals, report generation — all fire simultaneously.
This causes load spikes, connection-pool exhaustion, and cascading timeouts.

**Fix:** stagger jobs across the hour. Use `17 2 * * *` or `43 3 * * *` instead of
`0 0`. Jitter is your friend.

### 4. Uneven steps — the "drift" bug

```
*/7 * * * *
```

**Does NOT mean** "every 7 minutes evenly." It means "every 7 minutes starting at
0, then resets at 60." So: 0, 7, 14, 21, 28, 35, 42, 49, 56 — then 0 again
(a 4-minute gap). The intervals drift: 7,7,7,7,7,7,7,7,**4**.

**Fix:** 60 is not divisible by 7. Use step values that divide 60 evenly: `*/5`,
`*/10`, `*/15`, `*/20`, `*/30`. If you truly need every-7-minutes, use a loop with
`sleep 420`.

### 5. Leap-year February 29 — the "annual surprise"

```
0 0 29 2 *
```

Fires only on leap years — February 29, 2024 / 2028 / 2032… If someone writes this
expecting "end of February," they'll be confused for 3 out of every 4 years.

**Fix:** use `0 0 28 2 *` and handle the 29th case in the script if needed.

## Using the validation script

This skill ships a zero-dependency engine at `scripts/cron-engine.js` (Node.js, no
`npm install` needed). You can use it programmatically or from the CLI:

```javascript
// Programmatic — Node.js, zero dependencies
const { describe, validate, nextRuns, formatNextRuns } = require('./scripts/cron-engine.js');

// Parse + describe -> returns { text, error, parsed }
const d = describe('0 0

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…