Go to file
2026-11-10 16:53:37 +01:00
.github/workflows Bump flutter 3.47.9, node 26.13.0, python dev pins, web deps to latest 2026-11-01 17:54:17 +01:00
contracts workout-poke: instant phone credit over LAN (signed POST :8773) and Firebase stream 2026-10-09 19:05:51 +02:00
docs docs: move android_ui TODO to testsAndMisc 2026-11-01 20:52:37 +01:00
screen_locker Merge branch 'worktree-agent-acd53f670745f7d44' 2026-11-10 16:09:14 +01:00
scripts Add todo app git hooks 2026-11-02 14:25:01 +01:00
stronglift_replacement Allow an extra workout after done today 2026-11-10 16:53:37 +01:00
web Bump deps: fln 23, gradle 9.9, astro, jsdom 31 2026-11-07 08:44:45 +01:00
.fvmrc Bump flutter 3.47.9, node 26.13.0, python dev pins, web deps to latest 2026-11-01 17:54:17 +01:00
.gitignore web: migrate status page from React to Astro 2026-11-01 20:12:46 +01:00
.mcp.json Add read-only MCP server exposing workout/lock status 2026-07-10 21:28:09 +02:00
.phone-deploy-flavor Workout screen never moves when a rest starts; a sandbox flavor to prove it on the phone 2026-09-20 18:55:08 +02:00
.pre-commit-config.yaml Pin gatelock v0.12.0 2026-11-07 08:31:14 +01:00
AGENTS.md late credits: a credit at/after tonight's shutdown sets it to min(23:00, its own time + reward); grace floor removed (also on sick days) 2026-10-17 18:14:04 +02:00
arm.sh shutdown bonus: apply the moment a gate writes its ledger (earner-bonus.path) 2026-10-06 20:42:13 +02:00
CLAUDE.md Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
early-bird-workout-check.timer The early-bird window is the wake-alarm carrot, not a clock 2026-09-20 08:39:44 +02:00
earner-bonus.service earner-bonus: add the new modules, unit and tests missed by 7851d59 2026-10-06 20:44:01 +02:00
install_autostart.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
install_systemd.sh Wire runnerup-retire units into installer 2026-11-10 16:01:37 +01:00
install.sh sick days: one shared sickdays pool, 20:00 shutdown floor, one-tap lock button 2026-10-16 13:30:39 +02:00
LICENSE chore: add MIT LICENSE 2026-10-11 18:10:46 +02:00
pyproject.toml Pin gatelock v0.12.0 2026-11-07 08:31:14 +01:00
README.md Wire runnerup-retire units into installer 2026-11-10 16:01:37 +01:00
remove_autostart.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
remove_systemd.sh Wire runnerup-retire units into installer 2026-11-10 16:01:37 +01:00
requirements.txt Pin gatelock v0.12.0 2026-11-07 08:31:14 +01:00
run.sh Reconcile the venv on launch, so a pin bump cannot sit unnoticed 2026-08-23 06:56:26 +02:00
runnerup-retire.service Wire runnerup-retire units into installer 2026-11-10 16:01:37 +01:00
runnerup-retire.timer Wire runnerup-retire units into installer 2026-11-10 16:01:37 +01:00
runnerup-watch.service runnerup-watch: credit a RunnerUp run the moment its TCX upload finishes; lock the workout-log write 2026-10-07 20:36:38 +02:00
screen-locker-web.service Serve the lock decision, its history and its health at 127.0.0.1:8770 2026-08-29 22:50:19 +02:00
workout-locker.service Close the four gaps that let a decided lock never reach the screen 2026-08-30 15:24:45 +02:00
workout-locker.timer Close the four gaps that let a decided lock never reach the screen 2026-08-30 15:24:45 +02:00
workout-poke.service workout poke moves to tcp/8774: 8773 is book-guard's desktop wrapper, whose window the poke server had been answering since 2026-10-09 (phone app rebuilt, selftest default, contract doc) 2026-10-10 09:38:21 +02:00
workout-sync.service Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
workout-sync.timer Let the PC see phone workouts again, and stop losing progression on reinstall 2026-08-10 14:39:02 +02:00

screen-locker

Tkinter/systemd screen locker with workout tracking, shared sick days, and wake-alarm integration. It enforces a workout cadence by locking the screen until a verified (RunnerUp, StrongLifts) or budgeted manual workout is logged.

Sick days

A sick day is a date in the fleet-wide sickdays pool, nothing else: no budget, countdown, justification or debt. The lock screen's I'm sick button (retry screen, no-phone screen and the Tue-Thu prompt) marks today with one tap and unlocks; sickdays add or the phone do the same. On a sick day the workout lock stands down, wake-alarm's workday penalty is void, and shutdown is 20:00 plus the gaming pay of everything credited that day, capped at 23:00 (earned_time.sick_shutdown_from). A day marked after its daily reset is raised to it by the next live pass (_sick_floor), and every later credit that day raises it again.

A credit landing at or after tonight's shutdown is never lost: tonight becomes min(23:00, the credit's own time + its reward) (_late_credit). install.sh migrates the old sick_history.json dates into the pool once (scripts/migrate_sick_history.py).

A sick day may keep lockers (sickdays add --keep workout). A kept workout lock behaves exactly as on a normal day (lock, quota, relaxed-day penalty on that date); only the 20:00 shutdown floor still applies, since it belongs to the day, not to a locker. The one-tap button keeps nothing. The missed-alarm penalty is void on its ring day only if alarm is off, and on its penalty day only if workout is off. All of it goes through _sick.stands_down_workout.

Shutdown time

Every day starts at 19:00 from 2026-10-01, 20:00 before it (base_minutes() in screen_locker/_shutdown_base.py) and bonuses push it later, capped at 23:00: the first counted workout +2h, each further one +1h, an accepted LeetCode submission that day +1h (flat, read from leetcode-guard's ledger, once per day), and a credited paper-book reading session of 20+ pages / 20+ minutes +1h (flat, read from book-guard's ledger, once per day, keyed on when the reading ended). The config is re-derived from those sources on each new day, so nothing has to be "remembered" across reboots.

A RunnerUp run is credited from its TCX export, found in the WebDAV drop directory RunnerUp uploads to on this machine (~/data/cloud/RunnerUp/, plus processed/ once endurain-import has taken it) or, when a phone is adb-visible, in /sdcard/Documents/RunnerUp/. The 15-minute workout-sync.timer scans both, so a run finished after 20:00 pushes the hour later without the phone being plugged in; the per-minute shutdown check then lifts the night lockdown on its own once the hour is past "now" (digital-wellbeing's check script).

Retiring RunnerUp. A week after the PC first credits a run recorded by the workout app (TCX author kuhy workout_app), runnerup-retire.timer (daily, retries until the phone is attached) backs /sdcard/Documents/RunnerUp up to ~/data/cloud/RunnerUp/runnerup_phone_backup_<date>/ and uninstalls org.runnerup.free, once the app's .workout_app_import.json matches processed/; no app run, no uninstall. python3 -m screen_locker.runnerup_retire --status / --dry-run change nothing.

MCP server (Claude Code integration)

screen-locker exposes a read-only MCP server (screen_locker._mcp) so Claude Code and its subagents can query workout compliance and the lock-decision state through typed tools — without shelling out to the screen-locker-status CLI or opening the Tk window.

  • Read-only tools: get_status (full status snapshot), get_summary (one-line i3blocks summary + ok/warn/lock state word), explain_lock (why the screen is / isn't locked right now), get_flags (the individual boolean lock-decision predicates for today).
  • There are no write/action tools, by design. Nothing here logs a workout or mutates state — workouts are logged only from RunnerUp-verified TCX data, never from a caller's claim. No tool exposes the sync token or any HMAC key.

The mcp SDK is an optional dependency (pip install -e '.[mcp]'), kept out of the CLI/systemd system-python path. One-time setup of the dedicated venv that Claude Code spawns:

./scripts/setup_mcp.sh

Registration lives in the checked-in .mcp.json (project scope). Restart Claude Code in this repo and approve the project MCP-server prompt for it to load. Verify with claude mcp list.