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

LaunchAgent -> runner script -> compute end time -> SelfControl CLI

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

Working pieces

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

Boundary

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

What It Proves

  1. 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.
  2. 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.
  3. 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.