A beautiful terminal UI for managing cron jobs, built with Bubble Tea and Lip Gloss.
Short Linux / WSL CLI flow: add a cron job, confirm it in the managed list, and create a backup.
- Interactive TUI — browse, add, edit, delete, and toggle cron jobs visually
- Live validation — cron expressions are validated in real-time as you type
- Next-run preview — see upcoming execution times before saving
- Stable managed IDs — job IDs stay stable across deletes and rewrites
- Schedule presets — quick-pick common schedules (hourly, daily, weekly, etc.)
- Search & filter — find jobs by command or filter by enabled/disabled
- Backup & restore — automatic backups before every write, with restore support
- CLI mode — every operation is also available as a non-interactive subcommand
- Export / Import — export jobs as JSON or crontab format, import from JSON
CronTUI manages real schedules on:
- Linux via the system
crontab - macOS via the system
crontab - WSL2 distributions such as Ubuntu via the distro's
crontab - Native Windows via Windows Task Scheduler for CronTUI-managed tasks
On native Windows, CronTUI manages only the tasks it owns inside a dedicated Task Scheduler folder:
- default path:
\CronTUI\ - configurable via
windows_task_pathorCRONTUI_WINDOWS_TASK_PATH - stable IDs are stored in task names like
job-42 - backups are JSON manifests of the logical CronTUI job set, not raw Task Scheduler XML dumps
CronTUI does not attempt to import or edit arbitrary existing Task Scheduler jobs outside that folder.
Short native Windows CLI flow: add a managed task, confirm it in Task Scheduler, and create a backup.
Choose the environment based on the semantics you need:
- Use native Windows when you want CronTUI to manage Task Scheduler jobs under
\CronTUI\. - Use WSL2 when you want full Unix cron behavior, especially cron-only semantics such as
@reboot.
For WSL2:
wsl --install -d Ubuntu
wsl
sudo apt update
sudo apt install -y cron golang
sudo service cron start
go install github.com/meru143/crontui@latest
~/go/bin/crontuiJobs created this way run inside the WSL/Linux environment, not in native Windows Task Scheduler.
go install github.com/meru143/crontui@latest@latest installs the newest semver tag, not necessarily the newest commit on master.
Use this path when you want CronTUI to manage native Windows Task Scheduler jobs instead of WSL cron jobs.
Requirements:
- Windows with the built-in
ScheduledTasksPowerShell cmdlets available - Go installed locally
- a normal interactive user account; admin is not required for standard time-based tasks
Install and run without relying on PATH:
go install github.com/meru143/crontui@latest
$gobin = go env GOBIN
if (-not $gobin) { $gobin = Join-Path (go env GOPATH) "bin" }
& (Join-Path $gobin "crontui.exe") version
& (Join-Path $gobin "crontui.exe")If you prefer calling crontui directly, add that same bin directory to your user PATH.
- Download the latest Windows
.zipasset from GitHub Releases. - Extract
crontui.exeto a directory you control, such as%USERPROFILE%\\bin\\crontui. - Run it directly or add that directory to
PATH.
Example:
cd $HOME\bin\crontui
.\crontui.exe version
.\crontui.exego install github.com/meru143/crontui@masterUse this when you want the newest unreleased changes before the next tagged release.
Download the latest release artifacts from the GitHub Releases page:
git clone https://github.com/meru143/crontui.git
cd crontui
make buildAfter installing on native Windows, verify that CronTUI can create and see managed Task Scheduler jobs:
crontui add "0 9 * * 1-5" "Write-Output hello-from-crontui" --desc "weekday hello"
crontui list --json
Get-ScheduledTask -TaskPath '\CronTUI\'Expected result:
crontui list --jsonshows the managed jobGet-ScheduledTaskshows a task such asjob-1under\CronTUI\
If you changed windows_task_path, replace \CronTUI\ with your configured path.
crontuicrontui list # List all cron jobs
crontui list --json # List as JSON
crontui add "*/5 * * * *" "/usr/bin/backup.sh" --desc "Backup every 5 min"
crontui delete 3 # Delete job #3
crontui enable 2 # Enable job #2
crontui disable 2 # Disable job #2
crontui validate "0 */2 * * *" # Validate a cron expression
crontui preview "0 9 * * 1-5" 5 # Show next 5 runs
crontui backup # Create a backup
crontui restore <filename> # Restore from backup
crontui export --format=json # Export as JSON (default)
crontui export --format=crontab # Export as raw crontab
crontui import jobs.json # Import jobs from JSON
crontui version # Show version
crontui help # Show help- CronTUI preserves non-job crontab content such as environment variable lines and unrelated comments.
- Managed jobs get stable internal IDs so
delete,enable,disable, andrunkeep pointing at the same jobs after other mutations. - Native Windows manages only CronTUI-owned tasks under the configured Task Scheduler path; Unix and WSL continue to manage the user's real crontab.
- Windows accepts only the cron subset that maps exactly to Task Scheduler. Unsupported expressions fail before save or import instead of being approximated silently.
@rebootis supported on Unix and WSL cron backends, but it is rejected on native Windows because non-admin Task Scheduler startup triggers are not reliably available per user.- Every mutating write creates a backup first. Restoring a backup also creates a pre-restore backup of the current managed job set.
runnow/runexecutes the saved command immediately outside the normal schedule:- Unix / WSL: through
sh -c - native Windows: through
powershell.exe -NoProfile -NonInteractive -Command
- Unix / WSL: through
- Disabled jobs cannot be executed through
runnow/run.
*/5 * * * * # every 5 minutes
0 * * * * # every hour
0 9 * * 1-5 # 9:00 on weekdays
30 2 * * * # 02:30 every day
0 0 1 * * # first day of every month
0 0 1 1 * # every January 1st
@hourly # hourly shortcut
@daily # daily shortcut
@reboot # run once on reboot| Key | Action |
|---|---|
↑ / k |
Move up |
↓ / j |
Move down |
Home / g |
Jump to first job |
End / G |
Jump to last job |
a |
Add new job |
e / Enter |
Edit selected job |
d |
Delete selected job |
t |
Toggle enabled/disabled |
/ |
Search jobs |
x |
Run selected job now |
f |
Cycle filter (all → enabled → disabled) |
b |
Open backup list |
? |
Open help |
R |
Remove all managed jobs |
r |
Refresh job list |
q |
Quit |
| Key | Action |
|---|---|
Tab / Shift+Tab |
Move between fields |
Alt+1–Alt+6 |
Apply schedule preset |
Ctrl+S |
Save job |
? |
Open help |
Esc |
Cancel and return to list |
| Key | Action |
|---|---|
↑ / ↓ |
Navigate backups |
Enter |
Restore selected backup |
? |
Open help |
Esc |
Return to list |
| Key | Action |
|---|---|
Esc / Enter / q / ? |
Return to previous screen |
crontui/
├── main.go # Entry point: CLI dispatch or TUI launch
├── internal/
│ ├── cli/cli.go # CLI subcommand handler
│ ├── config/config.go # Defaults + file/env config loading
│ ├── cron/
│ │ ├── validator.go # Cron expression validation (robfig/cron)
│ │ └── preview.go # Next-run calculation & formatting
│ ├── crontab/
│ │ ├── reader.go # Read system crontab
│ │ ├── writer.go # Write system crontab
│ │ ├── parser.go # Parse crontab lines into CronJob structs
│ │ └── backup.go # Backup create/restore/prune/list
│ ├── scheduler/ # Unix crontab and Windows Task Scheduler backends
│ ├── model/
│ │ ├── model.go # Bubble Tea model (Init/Update/View)
│ │ ├── list.go # List view rendering & key handling
│ │ ├── form.go # Add/edit form view
│ │ ├── backup.go # Backup list view
│ │ ├── help.go # TUI help screen
│ │ ├── run_remove.go # Run output & remove-all confirmation
│ │ └── helpers.go # Utility functions
│ └── styles/styles.go # Lip Gloss styles & color palette
└── pkg/types/cronjob.go # CronJob struct
CronTUI starts from built-in defaults, then merges:
~/.config/crontui/config.jsonby defaultCRONTUI_CONFIG=/path/to/config.jsonif setCRONTUI_...environment variables as the final override
Supported config keys:
{
"max_backups": 10,
"show_next_runs": 5,
"backup_dir": "/home/user/.config/crontui/backups",
"log_level": "info",
"date_format": "2006-01-02 15:04:05",
"windows_task_path": "\\\\CronTUI\\\\"
}Supported environment variables:
CRONTUI_CONFIG
CRONTUI_MAX_BACKUPS
CRONTUI_SHOW_NEXT_RUNS
CRONTUI_BACKUP_DIR
CRONTUI_LOG_LEVEL
CRONTUI_DATE_FORMAT
CRONTUI_WINDOWS_TASK_PATHFor maintainers, @latest moves only when a new semver tag is created.
- Push the verified release commit to
master. - Open GitHub Actions and run the
Manual Release Tagworkflow. - Choose
patch,minor, ormajor. - The workflow creates and pushes the next
v*tag frommaster. - The tag triggers the
Releaseworkflow, which builds and publishes GitHub release artifacts and uploads the committed demo GIFs frommedia/demo/.
The manual tag workflow is defined in .github/workflows/manual-release.yml. The tag-driven release workflow is .github/workflows/release.yml. For a short maintainer checklist, see RELEASING.md.
Native Windows only accepts the schedule subset that maps exactly to Task Scheduler. Examples that are intentionally rejected include:
@reboot- mixed day-of-month and day-of-week expressions such as
0 9 1 * 1 - minute intervals that Task Scheduler cannot represent exactly, such as
*/7 * * * *
Use WSL2 if you need full Unix cron semantics.
By default, native Windows tasks live under \CronTUI\ in Task Scheduler.
Inspect them directly with PowerShell:
Get-ScheduledTask -TaskPath '\CronTUI\'If you changed windows_task_path, use that path instead.
Get-ScheduledTask -TaskPath '\CronTUI\' |
Unregister-ScheduledTask -Confirm:$falseReplace \CronTUI\ with your configured task path if needed.
Install cron for your environment first. On Ubuntu or WSL:
sudo apt update
sudo apt install -y cron
sudo service cron startgo install writes the binary to GOBIN, or to $(go env GOPATH)\bin when GOBIN is unset.
Check the location directly:
$gobin = go env GOBIN
if (-not $gobin) { $gobin = Join-Path (go env GOPATH) "bin" }
Get-ChildItem $gobin\crontui.exeRun the binary by full path or add that directory to your user PATH.
runnow executes the saved command immediately through sh -c on Unix/WSL or PowerShell on native Windows. A real scheduled run may still differ because the scheduler supplies a different runtime environment.
Restore writes the selected crontab content back, but it also creates a fresh pre-restore backup so you can undo the restore if needed.

