Cron & Scheduling
Schedule and manage recurring tasks with cron and systemd timers. Use when setting up cron jobs, writing systemd timer units, handling timezone-aware scheduling, monitoring failed jobs, implementing retry patterns, or debugging why a scheduled task didn't run.
MIT-0 · Free to use, modify, and redistribute. No attribution required.
⭐ 5 · 6.8k · 49 current installs · 49 all-time installs
MIT-0
Security Scan
OpenClaw
Suspicious
high confidencePurpose & Capability
The SKILL.md focuses on cron, at, and systemd timers (systemctl, /etc/systemd/system, journalctl), which is coherent for a Linux scheduling tool. However the registry metadata lists darwin (macOS) as a supported OS even though systemd/systemctl are not standard on macOS and macOS uses launchd instead. The declared anyBins (crontab, systemctl, at) partially aligns with the content but including systemctl while advertising darwin is inconsistent and could cause surprising failures or unexpected behavior on macOS.
Instruction Scope
The instructions are detailed and stay within scheduling and debugging scope (crontab, systemd timers, at, timezone handling). They do recommend editing system files (/etc/systemd/system), enabling/disabling timers, and using sudo for other users' crontabs and systemctl operations. These are expected for this domain but are privileged actions — the user/agent will be instructed to run system-level commands that can change service behavior and require elevated rights.
Install Mechanism
Instruction-only skill with no install spec and no code files. This is low risk from an install mechanism perspective since nothing is downloaded or written by the skill bundle itself.
Credentials
The skill does not require environment variables or credentials. The doc suggests setting variables like PATH, MAILTO, TZ in crontabs, which is expected and proportional to its functionality. No unexplained credential access is requested.
Persistence & Privilege
The skill is not always-on and does not request persistent system presence. It does, however, instruct actions that modify system services and cron entries (which are persistent changes to the host). Also note the skill is allowed to be invoked autonomously by the agent by default (disable-model-invocation = false) — this by itself is normal but combined with the instructions that ask for privileged commands, it warrants caution.
What to consider before installing
This skill is largely coherent for scheduling on Linux, but review these points before installing:
- OS mismatch: The skill advertises macOS (darwin) support, yet the instructions center on systemd/systemctl (Linux). If you're on macOS, prefer a launchd-focused guide or expect missing commands (systemctl doesn't exist on macOS).
- Privileged operations: Many suggested commands (sudo systemctl enable/disable, editing /etc/systemd/system, crontab -u, crontab -r) require root and can stop/start services. Do not run agent-provided sudo commands blindly—inspect the unit files and scripts first.
- Safety of scripts run by cron/at: The skill shows how to schedule arbitrary scripts. Ensure those scripts are audited and use absolute paths, limited permissions, and safe logging to avoid accidental execution of malicious binaries via PATH or symlink attacks.
- Backups and recovery: The doc uses crontab -r and advises editing system files; back up crontabs and unit files before making changes.
- Availability of tools: 'at' and systemd may not be installed on all systems; check which binaries exist before following instructions.
- Autonomy: Because agents can invoke this skill autonomously by default, consider restricting it to user-invoked only if you don't want the agent making scheduling changes without explicit approval.
If you plan to use this on macOS, ask the publisher to provide launchd-specific guidance or remove darwin from the supported OS list. If you proceed on Linux, follow principle of least privilege, test changes in a safe environment, and review any scripts the agent schedules.Like a lobster shell, security has layers — review code before you run it.
Current versionv1.0.0
Download ziplatest
License
MIT-0
Free to use, modify, and redistribute. No attribution required.
Runtime requirements
⏰ Clawdis
OSLinux · macOS
Any bincrontab, systemctl, at
SKILL.md
Cron & Scheduling
Schedule and manage recurring tasks. Covers cron syntax, crontab management, systemd timers, one-off scheduling, timezone handling, monitoring, and common failure patterns.
When to Use
- Running scripts on a schedule (backups, reports, cleanup)
- Setting up systemd timers (modern cron alternative)
- Debugging why a scheduled job didn't run
- Handling timezones in scheduled tasks
- Monitoring and alerting on job failures
- Running one-off delayed commands
Cron Syntax
The five fields
┌───────── minute (0-59)
│ ┌─────── hour (0-23)
│ │ ┌───── day of month (1-31)
│ │ │ ┌─── month (1-12 or JAN-DEC)
│ │ │ │ ┌─ day of week (0-7, 0 and 7 = Sunday, or SUN-SAT)
│ │ │ │ │
* * * * * command
Common schedules
# Every minute
* * * * * /path/to/script.sh
# Every 5 minutes
*/5 * * * * /path/to/script.sh
# Every hour at :00
0 * * * * /path/to/script.sh
# Every day at 2:30 AM
30 2 * * * /path/to/script.sh
# Every Monday at 9:00 AM
0 9 * * 1 /path/to/script.sh
# Every weekday at 8:00 AM
0 8 * * 1-5 /path/to/script.sh
# First day of every month at midnight
0 0 1 * * /path/to/script.sh
# Every 15 minutes during business hours (Mon-Fri 9-17)
*/15 9-17 * * 1-5 /path/to/script.sh
# Twice a day (9 AM and 5 PM)
0 9,17 * * * /path/to/script.sh
# Every quarter (Jan, Apr, Jul, Oct) on the 1st at midnight
0 0 1 1,4,7,10 * /path/to/script.sh
# Every Sunday at 3 AM
0 3 * * 0 /path/to/script.sh
Special strings (shorthand)
@reboot /path/to/script.sh # Run once at startup
@yearly /path/to/script.sh # 0 0 1 1 *
@monthly /path/to/script.sh # 0 0 1 * *
@weekly /path/to/script.sh # 0 0 * * 0
@daily /path/to/script.sh # 0 0 * * *
@hourly /path/to/script.sh # 0 * * * *
Crontab Management
# Edit current user's crontab
crontab -e
# List current crontab
crontab -l
# Edit another user's crontab (root)
sudo crontab -u www-data -e
# Remove all cron jobs (be careful!)
crontab -r
# Install crontab from file
crontab mycrontab.txt
# Backup crontab
crontab -l > crontab-backup-$(date +%Y%m%d).txt
Crontab best practices
# Set PATH explicitly (cron has minimal PATH)
PATH=/usr/local/bin:/usr/bin:/bin
# Set MAILTO for error notifications
MAILTO=admin@example.com
# Set shell explicitly
SHELL=/bin/bash
# Full crontab example
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
SHELL=/bin/bash
# Backups
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
# Cleanup old logs
0 3 * * 0 find /var/log/myapp -name "*.log" -mtime +30 -delete
# Health check
*/5 * * * * /opt/scripts/healthcheck.sh || /opt/scripts/alert.sh "Health check failed"
Systemd Timers
Create a timer (modern cron replacement)
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=backup
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2 AM
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
# Enable and start the timer
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
# Check timer status
systemctl list-timers
systemctl list-timers --all
# Check last run
systemctl status backup.service
journalctl -u backup.service --since today
# Run manually (for testing)
sudo systemctl start backup.service
# Disable timer
sudo systemctl disable --now backup.timer
OnCalendar syntax
# Systemd calendar expressions
# Daily at midnight
OnCalendar=daily
# or: OnCalendar=*-*-* 00:00:00
# Every Monday at 9 AM
OnCalendar=Mon *-*-* 09:00:00
# Every 15 minutes
OnCalendar=*:0/15
# Weekdays at 8 AM
OnCalendar=Mon..Fri *-*-* 08:00:00
# First of every month
OnCalendar=*-*-01 00:00:00
# Every 6 hours
OnCalendar=0/6:00:00
# Specific dates
OnCalendar=2026-02-03 12:00:00
# Test calendar expressions
systemd-analyze calendar "Mon *-*-* 09:00:00"
systemd-analyze calendar "*:0/15"
systemd-analyze calendar --iterations=5 "Mon..Fri *-*-* 08:00:00"
Advantages over cron
Systemd timers vs cron:
+ Logs in journald (journalctl -u service-name)
+ Persistent: catches up on missed runs after reboot
+ RandomizedDelaySec: prevents thundering herd
+ Dependencies: can depend on network, mounts, etc.
+ Resource limits: CPUQuota, MemoryMax, etc.
+ No lost-email problem (MAILTO often misconfigured)
- More files to create (service + timer)
- More verbose configuration
One-Off Scheduling
at (run once at a specific time)
# Schedule a command
echo "/opt/scripts/deploy.sh" | at 2:00 AM tomorrow
echo "reboot" | at now + 30 minutes
echo "/opt/scripts/report.sh" | at 5:00 PM Friday
# Interactive (type commands, Ctrl+D to finish)
at 10:00 AM
> /opt/scripts/task.sh
> echo "Done" | mail -s "Task complete" admin@example.com
> <Ctrl+D>
# List pending jobs
atq
# View job details
at -c <job-number>
# Remove a job
atrm <job-number>
sleep-based (simplest)
# Run something after a delay
(sleep 3600 && /opt/scripts/task.sh) &
# With nohup (survives logout)
nohup bash -c "sleep 7200 && /opt/scripts/task.sh" &
Timezone Handling
# Cron runs in the system timezone by default
# Check system timezone
timedatectl
date +%Z
# Set timezone for a specific cron job
# Method 1: TZ variable in crontab
TZ=America/New_York
0 9 * * * /opt/scripts/report.sh
# Method 2: In the script itself
#!/bin/bash
export TZ=UTC
# All date operations now use UTC
# Method 3: Wrapper
TZ=Europe/London date '+%Y-%m-%d %H:%M:%S'
# List available timezones
timedatectl list-timezones
timedatectl list-timezones | grep America
DST pitfalls
Problem: A job scheduled for 2:30 AM may run twice or not at all
during DST transitions.
"Spring forward": 2:30 AM doesn't exist (clock jumps 2:00 → 3:00)
"Fall back": 2:30 AM happens twice
Mitigation:
1. Schedule critical jobs outside 1:00-3:00 AM
2. Use UTC for the schedule: TZ=UTC in crontab
3. Make jobs idempotent (safe to run twice)
4. Systemd timers handle DST correctly
Monitoring and Debugging
Why didn't my cron job run?
# 1. Check cron daemon is running
systemctl status cron # Debian/Ubuntu
systemctl status crond # CentOS/RHEL
# 2. Check cron logs
grep CRON /var/log/syslog # Debian/Ubuntu
grep CRON /var/log/cron # CentOS/RHEL
journalctl -u cron --since today # systemd
# 3. Check crontab actually exists
crontab -l
# 4. Test the command manually (with cron's environment)
env -i HOME=$HOME SHELL=/bin/sh PATH=/usr/bin:/bin /opt/scripts/backup.sh
# If it fails here but works normally → PATH or env issue
# 5. Check permissions
ls -la /opt/scripts/backup.sh # Must be executable
ls -la /var/spool/cron/ # Crontab file permissions
# 6. Check for syntax errors in crontab
# cron silently ignores lines with errors
# 7. Check if output is being discarded
# By default, cron emails output. If no MTA, output is lost.
# Always redirect: >> /var/log/myjob.log 2>&1
Job wrapper with logging and alerting
#!/bin/bash
# cron-wrapper.sh — Run a command with logging, timing, and error alerting
# Usage: cron-wrapper.sh <job-name> <command> [args...]
set -euo pipefail
JOB_NAME="${1:?Usage: cron-wrapper.sh <job-name> <command> [args...]}"
shift
COMMAND=("$@")
LOG_DIR="/var/log/cron-jobs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/$JOB_NAME.log"
log() { echo "[$(date -u '+%Y-%m-%dT%H:%M:%SZ')] $*" >> "$LOG_FILE"; }
log "START: ${COMMAND[*]}"
START_TIME=$(date +%s)
if "${COMMAND[@]}" >> "$LOG_FILE" 2>&1; then
ELAPSED=$(( $(date +%s) - START_TIME ))
log "SUCCESS (${ELAPSED}s)"
else
EXIT_CODE=$?
ELAPSED=$(( $(date +%s) - START_TIME ))
log "FAILED with exit code $EXIT_CODE (${ELAPSED}s)"
# Alert (customize as needed)
echo "Cron job '$JOB_NAME' failed with exit $EXIT_CODE" | \
mail -s "CRON FAIL: $JOB_NAME" admin@example.com 2>/dev/null || true
exit $EXIT_CODE
fi
# Use in crontab:
0 2 * * * /opt/scripts/cron-wrapper.sh daily-backup /opt/scripts/backup.sh
*/5 * * * * /opt/scripts/cron-wrapper.sh health-check /opt/scripts/healthcheck.sh
Lock to prevent overlap
# Prevent concurrent runs (job takes longer than interval)
# Method 1: flock
* * * * * flock -n /tmp/myjob.lock /opt/scripts/slow-job.sh
# Method 2: In the script
LOCKFILE="/tmp/myjob.lock"
exec 200>"$LOCKFILE"
flock -n 200 || { echo "Already running"; exit 0; }
# ... do work ...
Idempotent Job Patterns
# Idempotent backup (only creates if newer than last backup)
#!/bin/bash
BACKUP_DIR="/backups/$(date +%Y%m%d)"
[[ -d "$BACKUP_DIR" ]] && { echo "Backup already exists"; exit 0; }
mkdir -p "$BACKUP_DIR"
pg_dump mydb > "$BACKUP_DIR/mydb.sql"
# Idempotent cleanup (safe to run multiple times)
find /tmp/uploads -mtime +7 -type f -delete 2>/dev/null || true
# Idempotent sync (rsync only transfers changes)
rsync -az /data/ backup-server:/backups/data/
Tips
- Always redirect output in cron jobs:
>> /var/log/job.log 2>&1. Without this, output goes to mail (if configured) or is silently lost. - Test cron jobs by running them with
env -ito simulate cron's minimal environment. Most failures are caused by missingPATHor environment variables. - Use
flockto prevent overlapping runs when a job might take longer than its schedule interval. - Make all scheduled jobs idempotent. If a job runs twice (DST, manual trigger, crash recovery), it should produce the same result.
systemd-analyze calendaris invaluable for verifying timer schedules before deploying.- Never schedule critical jobs between 1:00 AM and 3:00 AM if DST applies. Use UTC schedules instead.
- Log the start time, end time, and exit code of every cron job. Without this, debugging failures after the fact is guesswork.
- Prefer systemd timers over cron for production services: you get journald logging, missed-run catchup (
Persistent=true), and resource limits for free.
Files
1 totalSelect a file
Select a file to preview.
Comments
Loading comments…
