croncron
README.md
# croncron
**The easiest way to run cron jobs.** Plain-English schedules, automatic logs & run history, missed-run detection, and an MCP server so AI agents can manage your jobs. Zero dependencies — one folder of TypeScript that Node ≥23.6 runs directly.
```
$ croncron add "every 5 minutes" ./backup.sh
✓ backup — every 5 minutes (*/5 * * * *)
runs: ./backup.sh in /Users/you/project
next run in 3m (8/3/2026, 4:05:00 PM)
logs: croncron logs backup · test now: croncron run backup
```
No cron syntax to remember, no `>> /tmp/foo.log 2>&1` boilerplate, no wondering whether it ran.
## Why
Raw crontab has six chronic problems — croncron fixes each one:
| crontab pain | croncron |
|---|---|
| unreadable syntax | `"weekdays at 9:30"`, `"every monday at 8pm"` — cron syntax still accepted |
| no logs without redirect boilerplate | every run's output auto-captured → `croncron logs <name>` |
| no run history / silent failures | `croncron runs <name>`: when, duration, exit code; failures flagged in `list` |
| crontab = unowned junk drawer | named jobs in a registry; `croncron import` adopts your existing lines |
| cron's minimal PATH breaks commands | PATH + shell + cwd captured at add time, replayed at run time |
| macOS sleep silently skips runs | `list` shows a ⚠ + the watchdog re-runs missed jobs after wake |
| failures go unnoticed for weeks | native notification (+ optional Telegram) on failure and on recovery |
Your crontab stays yours: croncron manages one clearly marked block and never touches anything outside it. Every real crontab write is backed up to `~/.croncron/backups/` first.
## Install
```sh
npm install -g git+https://github.com/itsnotrwanman/croncron.git
croncron doctor # sanity-check the wiring
```
Requires Node ≥ 23.6. Website: [croncron.vercel.app](https://croncron.vercel.app)
From a clone: `pnpm link --global`.
## Commands
```
croncron add "<schedule>" <command...> # --name --cwd --retry N --ping URL --no-notify
croncron edit <name> [--schedule ...] # change anything without rm/re-add
croncron list # schedule · next run · last result · missed-run warnings
croncron run <name> # run right now, streamed
croncron logs <name> [lines]
croncron runs <name> # run history
croncron pause <name> / resume <name>
croncron rm <name>
croncron import [--apply] # adopt existing crontab entries (dry-run by default)
croncron watchdog install|remove|status # 24/7 mode (see below)
croncron catchup # run missed jobs now
croncron notify test · croncron config # failure alerts (macOS built-in, Telegram optional)
croncron doctor # env/wiring checks + macOS caveats
croncron mcp # MCP server on stdio
```
## Reliability
- **Alerts on state change only** — one notification when a job starts failing, one when it
recovers. A failing every-2-minutes job never becomes an alert storm. macOS notifications
work out of the box; add Telegram in `~/.croncron/config.json`.
- **Retries** — `--retry 2` re-attempts a failed run (10s apart) before it counts as failed.
- **No overlap** — if a run is still going when the next fire comes, the new one is skipped
and recorded as skipped (visible in `croncron runs`).
- **Monitor pings** — `--ping https://hc-ping.com/UUID` hits a healthchecks-style URL after
every run (`/fail` on failure), for off-machine monitoring.
- **Bounded disk** — logs rotate past ~1 MB, history is trimmed; nothing grows forever.
- **Watchdog** — launchd (macOS) or systemd user timer (Linux) re-runs schedules missed
while the machine slept.
Schedules: `every 5 minutes` · `hourly` · `daily at 9am` · `weekdays at 9:30` · `every monday at 8pm` · `weekends at 10am` · `monthly on the 1st at 9am` · any raw cron expression.
## For AI agents
### Claude Code
```sh
claude mcp add --scope user croncron -- croncron mcp
```
Then just ask: *"schedule my backup script every night at 3am"*. Tools exposed: `cron_add`, `cron_list`, `cron_remove`, `cron_pause`, `cron_run_now`, `cron_logs`.
### Codex CLI (`~/.codex/config.toml`)
```toml
[mcp_servers.croncron]
command = "croncron"
args = ["mcp"]
```
### Kimi CLI / any MCP client
```json
{ "mcpServers": { "croncron": { "command": "croncron", "args": ["mcp"] } } }
```
### Shell-only agents (no MCP)
Every read/write command takes `--json` for machine-readable output:
```sh
croncron add "every 10 minutes" "curl -s https://api.example.com/ping" --json
croncron list --json # includes nextRun, lastRun, missedLastScheduledRun
croncron run backup --json
```
## 24/7 mode (the macOS sleep trap)
cron only fires while the machine is awake — a job scheduled during sleep is skipped
forever, silently. `croncron watchdog install` fixes this with a launchd LaunchAgent
(launchd *does* run after wake) that calls `croncron catchup` every 5 minutes:
- any enabled job whose last scheduled fire has no run record gets executed once
- jobs cron will fire again within 10 minutes are skipped (no duplicate runs)
- catch-up runs are marked `catchup: true` in history and in the job log
So a `daily at 3am` backup on a laptop that was closed at 3am runs minutes after you
open the lid, instead of never.
## How it works
- `~/.croncron/jobs.json` — the registry (name, schedule, command, cwd, shell, PATH)
- `~/.croncron/logs/<name>.log` — every run's output, timestamped
- `~/.croncron/history/<name>.jsonl` — one line per run: start, duration, exit code
- crontab gets one managed block; each entry calls `croncron exec <name>` with absolute paths, so cron's minimal environment doesn't matter
## Development
```sh
node --test "test/*.test.ts" # 57 tests: parser, crontab block, importer, CLI e2e, MCP over stdio
```
Tests run against a sandboxed `CRONCRON_HOME` and a fake crontab file (`CRONCRON_CRONTAB_FILE`) — they never touch your real crontab.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues