27 Dec 2023 • Configuring launchd scheduled tasks with Nix home manager

macOS has a thing called launchd which amongst other things can run scripts periodically. I use it to schedule backups and auto-update youtube-dl. I thought it would be nice to manage that through home manager so it's one less thing to forget about. You can do it out of the box and it is ostensibly documented in places like this but that's hard to turn into something that actually works, so here are some examples:

launchd.agents = {
    restic = {
        enable = true;
        config = {
            Program = /Users/mike/.bin/run-or-notify;
            ProgramArguments = [ "/Users/mike/.bin/run-or-notify" "restic-snapshot failed!" "/Users/mike/.bin/restic-snapshot" ];
            StartInterval = 21600;
            EnvironmentVariables.PATH = "${pkgs.restic}/bin:/usr/bin";
            StandardErrorPath = "/Users/mike/restic-stderr.txt"; # these lines are how you debug stuff with launchd
            StandardOutPath = "/Users/mike/restic-stdout.txt";

    yt-dlp = {
        enable = true;
        config = {
            Program = /Users/mike/.bin/yt-dlp;
            ProgramArguments = [ "/Users/mike/.bin/yt-dlp" "-U" ];
            StartInterval = 86400;

Everything inside config is standard launchd stuff which is documented in man launchd.plist. StartInterval Just Works if you put your laptop to sleep etc which is nice.

run-or-notify is a script that alerts the program's output if it fails:

#! /bin/sh

output="$("$@" 2>&1)"

if [ "$err" -ne 0 ]; then
        osascript -e "display notification \"Output: $output\" with title \"$title\""
        exit "$err"