# systab
[](https://code.opennomad.com/opennomad/systab/actions?workflow=ci.yml)
[](badges/tests.json)
[](LICENSE)
A cron/at-like interface for systemd user timers and services. Create, manage, and monitor scheduled jobs and persistent services without writing unit files by hand.
Because you want to use systemd, but miss the ease of ~crontab~`systab -e`!
- 🚀 create one-time or recurring jobs with one command
- 🔧 run persistent services that start on login and auto-restart on failure
- ✏️ use your $EDITOR to manage `systab` jobs in a single line format
- 📊 quickly see the status of your timers and services
- 📋 access the logs of any job
- 💪 enable and disable timers and services
Quick start
Edit mode
Notifications
Services
## Install
Copy the `systab` script somewhere on your `$PATH`:
```bash
cp systab ~/.local/bin/
```
Requires `bash`, `systemctl`, and optionally `notify-send` (for `-i`) and `sendmail`/`msmtp` (for `-m`).
## Quick start
```bash
# 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"
# Run a persistent service (starts on login, auto-restarts on failure)
systab -s -n monitor -c "/usr/bin/my-monitor.sh"
# Check status of all jobs and services
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 9am` | 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 "*in* 5 minutes" or "*at*" between day and time. `systab` strips "in" and "at" before passing to `date -d`.
## Usage
### Creating timer jobs
```bash
# 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 desktop notification and a name (notification shows "build (name): completed")
systab -t "in 1 hour" -n build -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
```
### Creating persistent services
Use `-s` instead of `-t` to create a service that starts on login and auto-restarts on failure (`Restart=on-failure`). No timer is involved — the service runs continuously.
```bash
# Persistent service (starts immediately, restarts on failure)
systab -s -n monitor -c "/usr/bin/my-monitor.sh"
# With a name for easy reference
systab -s -n syncthing -c "/usr/bin/syncthing --no-browser"
```
Disable/enable work the same as for timer jobs — disable stops the service and prevents it from starting on login; enable starts it immediately and re-enables it.
### Managing jobs
```bash
# Print all jobs in crontab-like format to stdout (useful for scripting)
systab -l
# 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 `new` as the ID to create a job: `new | every 5 minutes | echo hello`
- Add a service with `new:s` and `service` as the schedule: `new:s,n=monitor | service | /usr/bin/my-monitor.sh`
- Comment out a line (`#`) to disable, uncomment to enable
- Append flags after the ID with `:` — `s` for service, `n=name` for naming, `i` for desktop notification, `e=addr` for email, `o` for output (default 10 lines), `o=N` for 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
**Timer jobs** (`-t`): systab creates a `.service` + `.timer` unit file pair in `~/.config/systemd/user/`. One-time jobs auto-unload after firing. Notifications use `ExecStopPost` so they fire after the service completes regardless of success or failure, with `dialog-information` or `dialog-error` icons based on `$SERVICE_RESULT`. When a job has a name, notifications display it as `ID (name)` — looked up dynamically so the label stays current even if the name is changed after creation.
**Service jobs** (`-s`): systab creates a single `.service` unit file with `Type=simple`, `Restart=on-failure`, and `WantedBy=default.target`. No timer is created. The service starts immediately on creation and restarts on login. Disable stops the service; enable starts it again.
All managed units are tagged with a `# SYSTAB_MANAGED` marker comment and a 6-char hex ID. Job output (stdout/stderr) is captured in the systemd journal and viewable via `systab -L`. Flags (names, notification settings, service type) are persisted as `# SYSTAB_FLAGS=` comments in service files so they survive edit sessions.
## Options
```
Job Creation:
-t