Claude Code in launchd: My Nightly claude -p Job Worked 6 of 14 Nights A developer documented running Claude Code headless via a macOS launchd agent for 14 nights, during which the nightly `claude -p` job produced a usable morning note on only 6 of those nights. The failures traced to launchd's minimal PATH (exit 127 because `claude` and its `node` shebang weren't found), the default working directory of `/` preventing CLAUDE.md from loading, and headless permission prompts being auto-denied while still exiting 0. The fixes were setting PATH and WorkingDirectory in the plist, adding StandardOutPath/StandardErrorPath logging, pre-approving tools with `--allowedTools`, and verifying the output file exists. For two weeks I woke up and checked for a markdown file that should have been written at 3:00 AM. On 8 of 14 mornings it either wasn't there, was empty, or showed up after I'd already finished my coffee. The job was simple. A macOS launchd agent ran Claude Code headless with claude -p every night, read yesterday's commits across four repos, and wrote a one-page morning note. It worked perfectly every single time I ran it from my terminal. That is exactly the trap: running Claude Code in launchd is a different environment from your shell, and launchd doesn't tell you when something goes wrong. Here's the autopsy, night by night, plus the plist that finally worked. PATH=/usr/bin:/bin:/usr/sbin:/sbin .zshrc . claude isn't on that PATH, so you get exit 127. /usr/bin/env node , so node must be on PATH too. Set PATH in the plist's EnvironmentVariables . / . CLAUDE.md never loads. Set WorkingDirectory . claude -p can't answer permission prompts. --allowedTools and verify the output file exists. pmset to wake the machine, or accept late runs. One plist in ~/Library/LaunchAgents , one shell command, one target file. The first version looked like this: