Project / failure writeup
When launchd Was Not Enough
I tried to automate weekday SelfControl blocks with a small `launchd` scheduler. The schedule worked; the unattended block did not, because the real boundary was macOS authorization.
Goal
I wanted a weekday 9-to-5 website block to start automatically. The point was not to build a large productivity system. It was to make focus the default instead of relying on daily willpower.
Monday-Friday at 9:00 am -> start SelfControl block -> end at 5:00 pm First Attempt
The installer writes user-owned LaunchAgent and runner files; SelfControl owns the privileged block helper.
The installer accepted a start time, end time, and cadence, then installed a user LaunchAgent and runner script. A typical experimental install looked like this:
./install-selfcontrol-automation.sh 09:00 17:00 weekdays What Worked
The schedule fired, the runner could compute the target end time, the block could be started manually, and the repo became a small auditable shell project with install, uninstall, dry-run, logs, and CI shell checks.
What Failed
SelfControl's CLI goes through macOS Authorization Services. Its privileged helper path expects an interactive user session, including the little approval prompt where an administrator password may be entered.
If I was at the computer, I could approve the prompt and start the session. If I was not, the scheduled job could fire and still fail to cross the authorization boundary. That was not a scheduler bug. It was the security model working as designed.
Fork In The Road
At that point, the choices were to patch SelfControl, fork it, find another blocking mechanism, use a different product, or accept manual activation. I also looked at Hammer Control, whose maintainer had effectively moved on because Raycast Focus existed.
Practical Decision
I stopped treating the issue as a scripting problem. The hard part was not cron syntax, `launchd`, or time arithmetic. The hard part was trying to get unattended privileged behavior from a tool whose helper model is intentionally interactive.
The public repo now points people toward Raycast Focus if they just want scheduled focus blocks. This project is better read as a reference artifact and a small lesson in respecting platform boundaries.
What It Proves
- Automation taste Small tools should be auditable. The project stayed understandable: install a LaunchAgent, run a script, log what happened, and provide an uninstall path.
- Systems judgment A failed automation can still be a successful investigation. The useful conclusion was identifying the authorization boundary, not forcing a brittle workaround through it.
- Environment design Focus is easier when the environment carries some of the load. The original instinct was still right: make the desired behavior the default. The mechanism was the part that needed to change.