| name | setup-health-cron |
| description | This skill should be used when the user asks to "setup daily health cron", "schedule mac health check", "automate daily report", "cron my mac check", or mentions scheduling the mac-guardian report. Installs a user-level launchd agent (preferred on macOS) that runs daily-health-report at a user-specified time, with cron as an optional fallback. |
setup-health-cron
Schedules the daily-health-report skill to run automatically at a user-specified local time. Prefers launchd on macOS. Falls back to cron only when explicitly requested.
When to invoke
Trigger on phrases like: "setup daily health cron", "schedule mac health check", "automate daily report", "cron my mac check".
Inputs
- Time of day (local). Default
09:00. Accept HH:MM in 24-hour form.
- Mode:
launchd (default) or cron.
Procedure (launchd — default)
-
Confirm with the user before writing anything:
"Ready to install ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist to run daily at HH:MM. Proceed?" Abort on "no".
-
Resolve plugin root: prefer ${CLAUDE_PLUGIN_ROOT}. Otherwise, derive it from the current skill path.
-
Build the plist at ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.dennisonbertram.mac-guardian.daily</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-lc</string>
<string>PLUGIN_ROOT="<ABSOLUTE PATH>"; bash "$PLUGIN_ROOT/scripts/render.sh" && bash "$PLUGIN_ROOT/scripts/open-report.sh"</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key><integer>HH</integer>
<key>Minute</key><integer>MM</integer>
</dict>
<key>StandardOutPath</key><string>/tmp/mac-guardian.daily.out.log</string>
<key>StandardErrorPath</key><string>/tmp/mac-guardian.daily.err.log</string>
<key>RunAtLoad</key><false/>
</dict>
</plist>
Substitute <ABSOLUTE PATH>, HH, MM. Hour is 0–23. Minute is 0–59.
-
Load it:
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist 2>/dev/null || true
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist
launchctl enable gui/$UID/com.dennisonbertram.mac-guardian.daily
-
Verify:
launchctl print gui/$UID/com.dennisonbertram.mac-guardian.daily | head -30
-
Note: the launchd agent runs render.sh and open-report.sh only. It does not re-run the collection skills automatically — collection requires Claude Code. Tell the user explicitly:
"The scheduled job renders and opens a dashboard from whatever JSON has accumulated in ~/.mac-guardian/data. To refresh data, run /mac-health manually."
-
Print the uninstall instructions:
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist
rm ~/Library/LaunchAgents/com.dennisonbertram.mac-guardian.daily.plist
Procedure (cron — only when asked)
- Confirm with the user before editing crontab.
- Show the line that will be appended:
MM HH * * * /bin/bash -lc 'bash "<PLUGIN_ROOT>/scripts/render.sh" && bash "<PLUGIN_ROOT>/scripts/open-report.sh"' >>/tmp/mac-guardian.cron.log 2>&1
- Append via
(crontab -l 2>/dev/null; echo "<line>") | crontab -.
- Print uninstall instructions:
crontab -e and remove the line, or crontab -l | grep -v mac-guardian | crontab -.
Output contract
Write a JSON envelope to ~/.mac-guardian/data/setup-health-cron-<ISOdate>.json:
{
"skill": "setup-health-cron",
"timestamp": "...",
"severity": "ok",
"summary": "Installed launchd agent for 09:00 daily",
"findings": [],
"raw": { "mode": "launchd", "time": "09:00", "plist_path": "/Users/.../com.dennisonbertram.mac-guardian.daily.plist" }
}
Handoff
- On direct invocation, also render a mini HTML via
bash ${CLAUDE_PLUGIN_ROOT}/scripts/render-single.sh setup-health-cron.
Safety
- Must prompt for confirmation before writing a launchd plist or modifying crontab.
- Never use
sudo — the agent is user-level (gui/$UID).
- If the plist already exists, prompt before overwriting.
- On any failure during bootstrap/enable, restore the previous plist (if any) and report the error.