Skip to content

Repository files navigation

rote

A cron that remembers what it did.

CIcodecov

rote demo

Why

cron runs your jobs and forgets them. When a backup silently stops firing or a script starts exiting non-zero at 3am, there's nothing to look at — no exit code, no timing, no output, often no sign it ran at all.

rote runs jobs on a schedule and records every run: exit code, duration, whether it timed out, and the captured stdout/stderr. A terminal dashboard shows, at a glance, which jobs are healthy, when each runs next, and what the last failure actually printed.

Install

Install script (Linux and macOS) — downloads the right binary for your platform:

curl -fsSL https://raw.githubusercontent.com/zhh2001/rote/main/install.sh | sh

With Go:

go install github.com/zhh2001/rote/cmd/rote@latest

Homebrew (available once the first release is tagged):

brew install zhh2001/tap/rote

Linux packages — download the .deb/.rpm/.apk for your architecture from the Releases page, then:

sudo dpkg -i rote_*.deb # Debian/Ubuntu
sudo rpm -i rote_*.rpm # Fedora/RHEL/openSUSE
apk add --allow-untrusted rote_*.apk # Alpine

Or grab a prebuilt binary archive from the same Releases page.

Quick start

Drop a config at ~/.config/rote/jobs.toml:

[[job]]
name = "heartbeat"schedule = "every 5m"command = "curl -fsS https://example.com/health"
[[job]]
name = "nightly-backup"schedule = "daily at 03:00"command = "/usr/local/bin/backup.sh"timeout = "30m"on_failure = "notify-send 'backup failed'"

Then run the scheduler with the live dashboard:

rote

Or run it headless as a daemon (no UI):

rote start

Configuration

Jobs live in a TOML file as an array of [[job]] tables:

FieldRequiredDescription
nameyesUnique label for the job.
scheduleyesWhen to run (see below).
commandyesShell command, run via sh -c.
timeoutnoMax run time, e.g. "30m", "90s". Omit for no limit.
on_failurenoCommand run once when the job fails.

Unknown keys are rejected, so a misspelled timout is caught instead of silently ignored.

Schedule syntax

Standard 5-field cron works:

*/15 **** every 15 minutes
0 3 *** 03:00 daily
0 9 ** 1 09:00 on Mondays

So do these plain-language forms:

every 5m every 90s every 1h30m
hourly daily weekly monthly
daily at 03:00
every monday at 09:00

The smallest effective interval is about 1 second — sub-second schedules are rounded up.

Files

  • Config: your user config dir, i.e. ~/.config/rote/jobs.toml (override with -c/--config).
  • Database: your XDG state dir, i.e. ~/.local/state/rote/rote.db (override with --db).

Commands

CommandWhat it does
roteSchedule jobs and show the live dashboard together.
rote startRun the scheduler headless, as a daemon.
rote tuiRead-only dashboard for an already-running scheduler.
rote run <job>Run one job now, record it, and print a summary. Propagates the exit code (124 on timeout, 127 if the job isn't found).
rote listList jobs with their next and last run.
rote logs <job> [-n N] [-o]Recent runs for a job; -n limits the count, -o includes the last run's output.
rote versionPrint the version.

In the dashboard: / (or k/j) to move, Enter to open a job's history, Tab to switch between the history list and the output pane, Esc to go back, r to refresh, ? for help, q to quit.

Running as a service

A minimal systemd user unit:

[Unit]Description=rote job scheduler
After=network-online.target
[Service]ExecStart=%h/go/bin/rote start
Restart=on-failure
[Install]WantedBy=default.target

Save it as ~/.config/systemd/user/rote.service, then:

systemctl --user enable --now rote.service

Watch it live from another terminal with rote tui.

Caveats

Don't run two schedulers against the same database. Running both rote and rote start (or two daemons) pointed at the same --db will execute every job twice. To watch a running scheduler, use the read-only rote tui.

License

MIT

About

A cron that remembers what it did—a CLI job scheduler with run history, captured output, and a live terminal dashboard.

Topics

Resources

Stars

152 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages