CronLab

March 2026 → May 2026

Code sourceTéléchargements

CronLab started from a concrete need: running my GitLab to GitHub sync every day, on Windows. I needed a scheduler. Windows Task Scheduler does the job, but its interface is an antique and setting up a simple recurring command takes half a dozen windows. I figured I'd build one my own way.

It's a desktop application that schedules commands from cron expressions, with a modern interface, system notifications and execution history. It's also my first real desktop application, and the first project I shipped as a download rather than deployed to the web.

Why Tauri and not Electron

The difference comes down to one number: the binary weighs a few megabytes where the Electron equivalent would weigh hundreds.

Tauri uses the system's native WebView, already present on Windows 11, instead of bundling a full browser. The interface is web, the core is Rust. For a utility you leave running permanently in the tray, resident memory matters, and that's what tipped the balance.

It was also a chance to learn Rust, which I didn't know. The language turned out to be a good fit for what the program does.

What the Rust core does

  • scheduling, via the cron crate to parse expressions,
  • command execution, with per-task environment variables and a timeout,
  • running a task manually on demand, in one click, without waiting for its next occurrence,
  • capturing stdout and stderr, each capped at ten kilobytes so a chatty command doesn't bloat the logs,
  • keeping the recent runs, ten by default and adjustable,
  • native notifications on success, failure or timeout,
  • a system tray icon with close-to-tray behaviour, and autostart with Windows.

That's where Rust's ownership model becomes concrete. The configuration and tasks live in state shared between the interface and the scheduler; several runs can touch it at once, and the compiler simply refuses to produce a binary if that access isn't properly synchronised. Those are bugs I never had to hunt: the compiler rules them out upfront.

Matching the Windows look

The interface uses Microsoft's Fluent UI components, to look like a native Windows 11 app rather than a web page dropped into a window. It's bilingual, French and English, including the system notifications.

A human-readable configuration

Everything lives in ~/.cronlab/: a config.json holding the settings and tasks, plus one execution log per task in a subfolder.

That file is deliberately readable and hand-editable. You can edit it, copy it to another machine to migrate your setup, or back it up, without going through the app. I'd rather have a format you can read and pick up yourself than a configuration locked inside an opaque one.

The distribution chain

This is the part I'm proudest of, because it took the most invisible work.

On every version bump, a GitHub Actions workflow takes over. A first, light job reads the version and checks whether the release already exists, so nothing is published twice. If a release is needed, a second job builds the app on Windows, with Rust dependency caching to avoid recompiling everything each time, signs the binaries, generates the installer and publishes the release automatically.

The update channel is wired into it: the app checks for new versions on startup and updates itself, after verifying the package signature. It's my first run-in with a constraint you don't have on the web: once the app is installed on someone's machine, you can't hotfix it. Without a signed update channel, the smallest mistake stays on the user's machine.

The companion to gitlab-sync

CronLab and the GitLab to GitHub sync form a pair: the latter is a command-line tool built to be re-run regularly, the former is what re-runs it. In practice, a CronLab task runs the sync every day and warns me if it fails. That's the use case that motivated the project in the first place, before it became a general-purpose scheduler.

What I took from it

It's my move into desktop applications: a different way of thinking about a program's life cycle, where you no longer control the runtime and where shipping means signing and distributing a binary.

It's also one of the first projects I built with Claude Code, and the start of a shift in habit. Before, when a tool was missing, I'd let it go: I had neither the time nor all the skills to build it. Now I started making more and more of them, simply to save myself time. CronLab and the GitLab sync are the first of that series. I'll devote a separate article to it.

Technologies used