Every scheduled job on one screen, systemd timers and cron together
A terminal UI (TUI) for systemctl and crontab on Linux: everything scheduled on a machine.
v0.2.2betaschedulingMIT
Every scheduled job on one list: systemd timers and cron together, with the schedule as written and how the last run went
A terminal UI for everything scheduled on a machine. systemd timers and cron are two schedulers with two syntaxes and two ways of reporting what happened; tui-cron puts them on one list — the name, the schedule as written, the next run, the last run and how it went.
Next to every expression is what it means, in English. 17 3 * * 1 and *-*-01..07 12:00:00 are both precise and neither is readable, and the mistakes people make with them are mistakes of reading. The reading comes from the tool's own describer, and the detail screen adds the next five runs as systemd-analyze calendar computes them.
Changes are previewed. A timer's schedule goes to a drop-in, checked with systemd-analyze calendar first; the unit file is never rewritten. A crontab is replaced through crontab <file>, cron's own interface, with the diff on screen; as root, into another account's table or /etc/cron.d. A cron line can become a timer, written but not enabled. A timer this tool wrote says so in its files, and only those can be re-pointed or deleted.
Run tui-cron --demo to drive a sample machine: every key works, every command is built and previewed for real, and nothing touches your system.
Keys
Key
Action
tab / 1-4
Move between all jobs, timers, cron and the schedulers themselves
enter
Open the selected job: its unit or table, the next runs, and its log
e
Change when the selected job runs — and what it runs, for a timer this tool wrote
a
Add a cron line: your own table, or as root another account's or /etc/cron.d
d
Remove the selected cron line, or a timer this tool wrote, after typing its name
c
Create a systemd timer and the service it runs
t
Write a timer for the selected cron line, not enabled
E / D
Enable or disable the selected timer at boot
n
Run the selected job now, off its schedule
/
Filter the rows of the current screen
?
Help
q
Quit
Press ? inside the tool for the full help screen, which is generated from the same action table as the key map.
Compatibility
This tool is a face on the program below, so its version matters. Tested is not a claim: a version lands there only after the tool's own suite passed against it on a real machine in the lab, and the run is kept as evidence in the repository. At startup the tool probes the backend once and says what it found in its header — a version nobody has run against is shown as (untested) in the warning colour, one older than the minimum as (below minimum) in the error colour. Neither stops it: the backend still refuses what it cannot do, in its own words.
systemd
systemctl ≥ 245
Binary
systemctl
Minimum
245
Probed with
systemctl --version
Tested
255259261
Needs a version this new
timers-jsonsince 250
What changes on older versions
systemd <250
systemctl list-timers --output=json does not exist, so the timers are enumerated from systemctl list-units --type=timer instead; nothing is lost, because every column shown is read from systemctl show either way
systemd >=245
systemd-analyze calendar --iterations is what computes the next runs and validates a new OnCalendar. It arrived in 242, below this minimum, so it is not gated: on every version this tool supports it is simply there
systemd >=245
a timer in your own manager is read through systemctl --user, which needs a user bus; over a serial console or a bare sudo -i shell there is none, and the tool says the user timers were not read rather than that there are none
cron
Binary
crontab
Tested
No recorded run yet. The tool still runs and reports the version it found as untested.
What changes on older versions
cron >=1
cron declares no version command. cronie answers crontab -V with "cronie 1.7.2"; Debian's vixie cron has no such flag and no sibling program that prints one, so a version would appear on Fedora and be blank on Ubuntu. The header shows cron without a number
cron >=1
there is no portable way to have cron check a table: cronie ships crontab -T, Debian's cron ships nothing equivalent. A line is therefore parsed by this tool before it is written, with the same check on every machine
cron >=1
cron records that a command started, and cronie also that it returned; neither records an exit status anywhere. A cron job's last result is therefore "it ran" at best, and the screen says so rather than implying it worked
cron >=1
a machine may have no cron at all — Omarchy Server is one — and that is a normal machine, not a failure: the timers are listed, and cron reports itself as absent with the reason
cron >=1
a machine with no cron may still carry run-parts scripts: Omarchy Server ships /etc/cron.hourly/snapper and nothing that walks the directory. They are listed anyway, and each row says nothing runs it rather than showing a file that looks scheduled as active
Maintain systemd or cron? You are welcome to help shape this tool. About → maintainers
Install
Once per machine, then every tool in the family is one pacman away.
Add the repository
$ curl -fsSL https://pkgs.tui.tools/install.sh | sh
Or run the same thing yourself, one command at a time
A family whose whole promise is preview before you run is not going to insist you pipe a script into a shell. These are the commands that script runs.
Upgrades then arrive with the rest of your system updates.
!
Not published yet. The command is what it will be once the package repository at pkgs.tui.tools is live. Until then, use the static binary or build from source.
Arch Linux (AUR) · tui-cron-bincoming soon
$ paru -S tui-cron-bin
The -bin package installs the released static binary.
Once per machine, then every tool in the family is one apt away.
Add the repository
$ curl -fsSL https://pkgs.tui.tools/install.sh | sh
Or run the same thing yourself, one command at a time
A family whose whole promise is preview before you run is not going to insist you pipe a script into a shell. These are the commands that script runs.
Upgrades then arrive with the rest of your system updates.
!
Not published yet. The command is what it will be once the package repository at pkgs.tui.tools is live. Until then, use the static binary or build from source.
Needs the tui-tools repository, a one-time setup you do once per machine.
openSUSE · tui-croncoming soon
$ sudo zypper install tui-cron
The rpm repository is shared with dnf; zypper support is not tested yet.
One static binary. Verify it against checksums.txt from the same release.
From source · tui-cron
$ git clone https://github.com/tui-tools/tui-cron
cd tui-cron && make build
sudo install -m0755 bin/tui-cron /usr/local/bin/tui-cron
Needs Go 1.27 or newer.
What it can do to your machine
✓
Preview, then confirm
Every change is shown as an exact command line and confirmed before it runs. The dialog and the runner receive the same value, so the preview cannot drift from what executes.
•
Escalates for actions
Reading needs nothing: systemctl show, crontab -l for your own table and the journal all answer to any user. Every change escalates through sudo -n, which never prompts — installing a drop-in, replacing a crontab, enabling a timer or running one now.
✓
No daemon, no state of its own
Nothing keeps running after you quit, and nothing is installed to run later. The system is the source of truth; the tool re-reads it after every change.
✓
No network access
The tool opens no network connection of its own. No telemetry, no update check, no phone home.
✓
Static binary
Released statically linked, with no runtime dependencies to install.
✓
Signed release, with provenance
checksums.txt carries a keyless cosign signature from this repository's release workflow, every archive has a CycloneDX SBOM, and every archive, package and the checksum file carry SLSA build provenance. The security page shows the three commands that check it.
Reporting
Report a security issue privately, through GitHub's private vulnerability reporting on the repository's Security tab. The family-wide policy, and what counts as in scope, is on the security page.
## tui-cron v0.2.2
tui-cron 0.2.2: tui-kit v0.4.4
tui-cron 0.2.2 moves to tui-kit v0.4.4: every command now runs in its own session without a controlling terminal, so a step that would prompt fails at once instead of hanging behind the UI, and a failed step reports its meaningful line, cleaned of escape codes. Command previews are POSIX shell-quoted (a calendar expression now reads as `'*-*-* 03:00:00'`), the README screenshots are re-rendered with continuous box borders, and the README banner now carries the kit's stability markers.
Built by this repository's CI on the tag itself. Each archive ships a
CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and
every file has SLSA build provenance — see the README's "Verify a
download" for the two commands that check them.
The commits in this release:
## Changelog
* 8ef23ccc6ebf0fb9cb269443999bf3fd8fa8728a 0.2.2: tui-kit v0.4.4 (#20)
* b4da2db748070a520debd2db1aa358054a46ed11 Bump anchore/sbom-action/download-syft in the github-actions group (#18)
* 0b6a76dbd0a28a41f6ca8339a601019812b832f3 Bump the github-actions group with 4 updates (#19)
* ff82f571cae60d03b26cb99208fa0940510e3eb7 README: link the tool's page on tui.tools (#17)
* a8169214b847543184e0d05d855c25d2152647b5 README: point the install snippet at the current release (#16)
## tui-cron v0.2.1
List the timer unit files on disk, not only the loaded timers.
Also: tui-kit v0.3.0 — dialogs wrap and scroll instead of clipping the
command preview, and the picker filters as you type.
Built by this repository's CI on the tag itself. Each archive ships a
CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and
every file has SLSA build provenance — see the README's "Verify a
download" for the two commands that check them.
The commits in this release:
## Changelog
* bbf9277553b7a6f1f01d9c47470fc5c05f7acea2 Bump tui-kit to v0.3.0 (#15)
* 7b588d1bf56a4338f9312d2c991dec14fe8f65e3 List the timer unit files on disk, not only the loaded timers (#14)
## tui-cron v0.2.0
Manage, not view (wave 3): create what does not exist, edit what does; lab-validated.
Built by this repository's CI on the tag itself. Each archive ships a
CycloneDX SBOM, `checksums.txt` carries a keyless cosign signature, and
every file has SLSA build provenance — see the README's "Verify a
download" for the two commands that check them.
The commits in this release:
## Changelog
* bef2630dbf6a532237c212b9a956e390e3c86876 A code of conduct that fits on one screen (#10)
* bdd0280ccf7612faf588acd9622b892081aba9d9 Add --report, and a bug form that asks for it (#11)
* 70025af001f8f3f2a2766d6da20a8ae17450c388 Bump anchore/sbom-action/download-syft (#4)
* 90803d2d258dc854aee6d828c4a4a5d8e42da20e Carry the OpenSSF Best Practices badge (#8)
* e9b3e5efc31e7c79740a256633c8db58f422f1cd Carry the family's gitleaks configuration unchanged (#2)
* 837beecff1a5d6dbe73b43d6f0ce5a1b32901c89 Delete and edit the timers the tool wrote; add for any user (#13)
* deb0e08916d38dbbe9abd801671faf8877fac274 Do not search the distro line for the host name (#12)
* 4e3efbcb51f46e2e0565b53356645442ac4f29dd Fetch the tag annotation before releasing (#6)
* 482b61fe40c5081780ae417715e218f233765225 Pin what CI runs, fuzz the parsers, and say the releases are signed (#3)
* 355c4a4fea32ec26824fb1c85d3bb04b0bfcdd80 Print the whole tag message, not only its body (#7)
* 181d7217cecded941b01904a4ac8e204680eff07 Say beta once (#5)
* 59ad3ff0d2f26c2cc475ac5f38fd1b0ed602fa06 Take tui-kit v0.2.8: hashed pip install, provenance bundle on the release (#9)
## Changelog
* 769f54293dd080a2ea81d8e95d68e2553ff7ff64 Drop cross-repo dispatch; the package repo and the site poll releases
* e30ed342f31e886aa63e123c41c95bbfa1492a58 Gate the release on a security job, and sign what it publishes (#1)
* 1ff47d77f6925f972503cebe3dbc53947716d78b Stop telling readers the packages are unpublished
## Changelog
* 8f8d260c65d36b17df15a571ed686a9dfbb664df Add the kind counts up without bc, which two of three guests do not have
* 9bce42a82b4c661f6bd0b139bf072a8df3487681 Fit the run-parts note inside the manifest's 300-character impact limit
* 3f78a3d4dda18f12bcc9e48dbbf2a83d85c68c48 List run-parts scripts on a machine that has no cron
* ec9c7c62fb69ed104578382d247987e16dd5cda4 Packages are available from pkgs.tui.tools
* 954a57ceb98e76dd0e51f631e9a51fd76f097b2c Re-pin the kit at v0.2.3
* 35d6986e2939d5178f295451c0a9920094c2b12e Ship the tool as a .deb, an .rpm and a pacman package
## Changelog
* d2fe6a7b4daa05010b09d237b5774c1ce5b42c26 Build tui-cron: every scheduled job on one screen, in English
* 4d5768e7384a701e5d82d041dfe1bddf54862297 Initial commit