It Can Die in Its Sleep — Self-Healing launchd Jobs with Multi-Slot Firing and a Done-Marker A developer created a self-healing launchd job pattern for macOS that uses multiple scheduled firing slots and done-markers to ensure a daily Obsidian Vault update completes despite failures from sleep, network loss, or API timeouts. The job fires at 4:55, 8:20, 10:45, and 12:15 each day, with each slot checking a date-stamped marker file; if the day's run already succeeded, the slot exits immediately, otherwise it retries from the last completed step. The approach uses half-markers per sub-step to avoid redoing work, so a failure in step2b (Codex logs) only retries that step on the next slot. My previous piece, " Making a launchd Job Unload Itself https://zenn.dev/bokuwalily/articles/self-unload-launchd-job ," built a job that runs exactly once and then unloads itself. This time it's the mirror image: a pattern designed around the assumption that the job will die mid-run — it fires several slots a day and delivers "retry until it succeeds, then quit immediately on success." Every morning I hand Claude Code the task of updating my Obsidian Vault, and it kept dying partway through — killed by macOS sleep, no network on wake, or a claude timeout. Instead of trying to prevent every failure perfectly, I decided "it can die overnight as long as it's done by the time I wake up" was the more realistic goal, and I redesigned around that. There are three ways a launchd job fails to run to completion. caffeinate -s only works on AC power. On battery, the job freezes the instant you close the lid, and gets reaped by timeout after wake. git push and claude's API calls time out.All three can look like "the job started, exit code 0," so you notice late. The fix is simple: stuff multiple StartCalendarInterval entries into the plist, and at the top of the script check "if today's run already succeeded, exit 0 immediately." php < -- com.shun.vault-auto-ingest.plist StartCalendarInterval excerpt --