crontab-ish interface for systemd user timers (and services)
https://code.opennomad.com/opennomad/systab/
| demo | ||
| CLAUDE.md | ||
| README.md | ||
| systab | ||
| test.sh | ||
systab
A cron/at-like interface for systemd user timers. Create, manage, and monitor scheduled jobs without writing unit files by hand.
![]() |
![]() |
![]() |
| Quick start | Edit mode | Notifications |
Install
Copy the systab script somewhere on your $PATH:
cp systab ~/.local/bin/
Requires bash, systemctl, and optionally notify-send (for -i) and sendmail/msmtp (for -m).
Quick start
# Run a command every 5 minutes (with a name for easy reference)
systab -t "every 5 minutes" -n healthcheck -c "curl -s https://example.com/health"
# Run a backup script every day at 2am
systab -t "every day at 2am" -n backup -f ~/backup.sh
# Run a one-time command in 30 minutes
systab -t "in 30 minutes" -c "echo reminder"
# Check status of all jobs
systab -S
# View logs
systab -L
Time formats
systab accepts several time formats:
| Format | Example | Type |
|---|---|---|
| Natural recurring | every 5 minutes |
Recurring |
| Natural recurring | every 2 hours |
Recurring |
| Natural recurring | every 30 seconds |
Recurring |
| Natural recurring | every day at 2am |
Recurring |
| Natural recurring | every monday at 9am |
Recurring |
| Natural recurring | every month |
Recurring |
| Relative | in 5 minutes |
One-time |
| Relative | tomorrow |
One-time |
| Absolute | 2025-06-15 14:30 |
One-time |
| Absolute | next tuesday at noon |
One-time |
| Systemd keyword | hourly, daily, weekly, monthly |
Recurring |
| Systemd OnCalendar | *:0/15 (every 15 min) |
Recurring |
| Systemd OnCalendar | *-*-* 02:00:00 (daily at 2am) |
Recurring |
| Systemd OnCalendar | Mon *-*-* 09:00 (Mondays at 9am) |
Recurring |
Relative and absolute formats are parsed by date -d. Systemd OnCalendar values are passed through directly.
Note: date -d does not technically like the "in 5 minutes" syntax. systab removes the offending "in".
Usage
Creating jobs
# Command string (with optional name)
systab -t "every 5 minutes" -n ping -c "echo hello"
# Script file
systab -t "every day at 2am" -n backup -f ~/backup.sh
# From stdin
echo "ls -la /tmp" | systab -t daily
# With desktop notification (success/failure with status icon)
systab -t "in 1 hour" -c "make build" -i
# With email notification (via sendmail)
systab -t "every day at 6am" -c "df -h" -m user@example.com
# Include last 10 lines of output in notification
systab -t "every day at 6am" -c "df -h" -i -o
Managing jobs
# Edit all jobs in your $EDITOR (crontab-style)
systab -e
# Show status of all jobs
systab -S
# Show status of a specific job (by ID or name)
systab -S a1b2c3
systab -S backup
# View logs (all jobs)
systab -L
# View logs for a specific job (by ID or name)
systab -L a1b2c3
systab -L backup
# View logs (filtered)
systab -L error
# Disable/enable a job (by ID or name)
systab -D backup
systab -E backup
# Clean up completed one-time jobs
systab -C
Edit mode
systab -e opens your editor with a pipe-delimited job list:
a1b2c3:n=backup | daily | /home/user/backup.sh
d4e5f6:i | *:0/15 | curl -s https://example.com
g7h8i9:n=weekly-backup,e=user@host | weekly | ~/backup.sh
# aabbcc | hourly | echo "this job is disabled"
- Edit the schedule or command to update a job
- Delete a line to remove a job
- Add a line with
newas the ID to create a job:new | every 5 minutes | echo hello - Comment out a line (
#) to disable, uncomment to enable - Append flags after the ID with
:—n=namefor naming,ifor desktop notification,e=addrfor email,ofor output (default 10 lines),o=Nfor custom count, comma-separated (e.g.,a1b2c3:n=backup,i,o,e=user@host)
Job IDs and names
Each job gets a 6-character hex ID (e.g., a1b2c3) displayed on creation and in status output. You can also assign a human-readable name with -n at creation time. Names can be used interchangeably with hex IDs in -D, -E, -S, and -L. Names must be unique and cannot contain whitespace, pipes, or colons.
How it works
systab creates systemd .service and .timer unit file pairs in ~/.config/systemd/user/. Each managed unit is tagged with a # SYSTAB_MANAGED marker comment. One-time jobs auto-unload after firing. Job output (stdout/stderr) is captured in the systemd journal and viewable via systab -L.
Notifications use ExecStopPost so they fire after the service completes regardless of success or failure. Desktop notifications show dialog-information or dialog-error icons based on $SERVICE_RESULT. Notification flags are persisted as # SYSTAB_FLAGS= comments in service files, so they survive across edit sessions.
Options
Job Creation:
-t <time> Time specification (required for job creation)
-c <command> Command string to execute
-f <script> Script file to execute (reads stdin if neither -c nor -f)
-n <name> Give the job a human-readable name (usable in place of hex ID)
-i Send desktop notification on completion (success/failure)
-m <email> Send email notification to address (via sendmail)
-o [lines] Include job output in notifications (default: 10 lines)
Management:
-D <id> Disable a job
-E <id> Enable a disabled job
-e Edit jobs in crontab-like format
-L [id] [filter] List job logs (optionally for a specific job and/or filtered)
-S [id] Show status of all managed jobs (or a specific job)
-C Clean up completed one-time jobs
-h Show help
FAQ
What's the difference between -c and -f?
-f validates that the file exists and is executable at creation time, catching typos and permission issues early. With -c, errors only surface when systemd runs the job later (visible via systab -L). Under the hood, both produce the same ExecStart line.


