diff --git a/docs/explanations/2026-07-19-explanation-remove-focus-mode-daemon.html b/docs/explanations/2026-07-19-explanation-remove-focus-mode-daemon.html new file mode 100644 index 00000000..f2ca5a70 --- /dev/null +++ b/docs/explanations/2026-07-19-explanation-remove-focus-mode-daemon.html @@ -0,0 +1,738 @@ + + +
Commit 937c597 · digital_wellbeing/ · 2026-07-19
+ digital_wellbeing/ is a folder of small personal-automation
+ daemons and installers that fight the author's own bad habits: a
+ compulsive-app-opening blocker, a LeechBlock installer, a pacman wrapper
+ that adds friction to installing distracting software, and — until this
+ change — a focus-mode daemon.
+
+ The idea behind focus-mode was simple: Steam (gaming) and web browsers
+ compete for the same attention, so let only one of them run at a time.
+ Concretely, focus_mode_daemon.py ran as a
+ systemd user service that polled /proc
+ every 2 seconds, and enforced a rule: whichever category — Steam or
+ browsers — started first "wins", and the daemon pkills the
+ other one the moment it shows up. A companion
+ whitelist subcommand let the author temporarily allow
+ browsers during a gaming session, for things like a two-factor-auth
+ prompt that has to open in a browser.
+
+ This lived across four files: focus_mode_daemon.py (the
+ state machine and CLI), _focus_mode_lib.py (process
+ detection via /proc/*/stat, logging, and the actual
+ pkill calls), install_focus_mode_daemon.sh
+ (installs a systemd --user service), and a bare
+ __init__.py whose only content was a one-line docstring
+ naming the daemon.
+
check_and_enable_services.sh — the
+ script that audits and self-heals all the other daemons on this system —
+ repairs a broken service by running its installer as
+ sudo -u <user> bash install_focus_mode_daemon.sh install.
+ But sudo -u changes the UID without granting a login
+ session: XDG_RUNTIME_DIR and
+ DBUS_SESSION_BUS_ADDRESS stay unset, so every
+ systemctl --user call inside the installer died with
+ "Failed to connect to user scope bus". The installer tried to route
+ around this by deriving those paths from the effective UID — but by the
+ time this change landed, the daemon was confirmed not
+ installed and not running on the live system at all. A feature
+ that silently never actually deployed is exactly what "unusable in its
+ current state" means here.
+ + Before removal, the daemon's core was a three-state machine. Read it as: + "no app category has claimed the screen yet, until one shows up — at + which point the other gets killed on sight." +
+ ++ The one subtlety worth internalizing — because it's easy to misread — + is what happened if both Steam and a browser were already + running the moment the daemon started, with no mode active yet. The + code didn't wait to see which one the user "meant" first: it directly + entered gaming mode and killed the browsers. Steam wins ties. +
+ +
+ This logic is gone from the repo now, but it's small enough to simulate.
+ Toggle which processes are "running", hit Tick to step
+ the daemon's update() once, and watch the mode and log
+ react exactly as the deleted code would have.
+
+ Try it: check both boxes, leave whitelist off, then hit Tick once from a + cold start — gaming mode wins and the log shows a browser kill. Now + reset, enter gaming mode with just Steam, turn on whitelist, + then check the browser box and Tick — no kill this time, + because the whitelist suppresses the enforcement while gaming mode is + already active. +
+ ++ With the daemon deleted, none of this runs anymore. The system-level + picture also gets simpler: +
+ +| Before | After | |
|---|---|---|
check_and_enable_services.sh --status row count |
+ 12 services, incl. focus_mode | +11 services | +
install_core_system.sh secondary modules |
+ 8, incl. Focus-mode daemon | +7 | +
test_security_hardening.sh checks |
+ 27 tests, incl. 3 focus-mode tests | +24 tests | +
+ All four files under digital_wellbeing/ that made up the
+ daemon are gone: the 320-line state machine, the 227-line process/kill
+ library it imported, the 241-line systemd installer, and the
+ one-line package docstring.
+
- focus_mode_daemon.py (320 lines: FocusMode state machine + CLI) +- _focus_mode_lib.py (227 lines: /proc scanning, pkill helpers) +- install_focus_mode_daemon.sh (241 lines: systemd --user unit + install/uninstall/status) +- __init__.py (1 line: package docstring)
+ install_core_system.sh's secondary-module menu drops item
+ 8 outright — it was the last entry, so no renumbering was needed for
+ the remaining seven.
+
-ask_install "Focus-mode daemon" \ +- bash "$LINUX_CONFIG/scripts/periodic_background/digital_wellbeing/install_focus_mode_daemon.sh" install +-
+ check_and_enable_services.sh is the script that checks all
+ 12 (now 11) personal services and repairs anything broken. Its entire
+ check_focus_mode() function — the one whose repair path
+ hit the sudo -u session-bus bug described above — is
+ deleted, along with its variable, its slot in the summary table, and
+ its call site. The remaining services in the printed list shift down
+ by one number so item 8 (Thorium startup) doesn't leave a gap where 6
+ used to be.
+
- 6. Focus mode daemon - Steam/Browser mutual exclusion (user service) +- 7. Compulsive blocker - Limits messaging apps to one launch per hour ++ 6. Compulsive blocker - Limits messaging apps to one launch per hour ++ 7. Thorium startup - Auto-launch Thorium with Fitatu on boot + ... +- for service in ... hosts focus_mode compulsive_blocker ...; do ++ for service in ... hosts compulsive_blocker ...; do + ... +- check_hosts +- check_focus_mode +- check_compulsive_blocker ++ check_hosts ++ check_compulsive_blocker
+ test_security_hardening.sh loses its three focus-mode
+ checks (daemon file exists, installer exists, service is active). The
+ tests that followed — for an unrelated screen-locker component — get
+ their comment numbers shifted down from 23–27 to 20–24, purely so the
+ numbering stays sequential. test_result() tallies
+ pass/fail/skip by counting calls, not by parsing these comments, so
+ this renumbering is cosmetic, not functional.
+
-# Test 20: Focus mode daemon script exists +-if [[ -f "$focus_daemon" ]]; then ... +-# Test 21: Focus mode installer exists +-... +-# Test 22: Focus mode daemon is running (user service) +-... +- +-# Test 23: Screen locker exists ++# Test 20: Screen locker exists
+ CLAUDE.md's directory map and "Key scripts" list both
+ drop their mentions of the daemon.
+
-│ ├── digital_wellbeing/ # Compulsive-opening blocker, focus daemon, LeechBlock ++│ ├── digital_wellbeing/ # Compulsive-opening blocker, LeechBlock + ... +-- `scripts/periodic_background/digital_wellbeing/focus_mode_daemon.py` — Linux digital-wellbeing daemon
+ Left untouched on purpose: phone_focus_mode/ (a completely
+ separate GPS-based Android app-restriction system that just happens to
+ share the word "focus"), and the historical design docs
+ (docs/SECURITY_HARDENING_ANALYSIS.md,
+ docs/superpowers/evidence|contracts) that originally
+ proposed and tracked this daemon — those stay as append-only history of
+ what was tried.
+
Five questions on the reasoning behind this change. Click an option to check it.
+ +