Go to file
Krzysztof kuhy Rudnicki 8450644a56 Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock
Next to the one-tap "I'm sick" (unchanged: keeps nothing, unlocks), a small
secondary link lays sickdays 0.3.0's embeddable KeepPanel over every
surface, in-process so it gets input under the lock's grab. Closing the
overlay reveals the untouched screen underneath, so no countdown or phone
check is restarted or skipped.

After the panel's own write + sync: sick with the workout lock standing
down -> sick floor, decision, close (shared with the one-tap path, no second
mark or push); sick with the workout kept -> sick floor and a note, lock
stays; cleared / unchanged / cancel -> the panel just closes.

Tests stub KeepPanel and redirect resolve_paths and sync_quietly in every
sickdays.* module, sickdays.gui._panel included. The fit check measures the
panel on a throwaway pool. Pins bumped to sickdays-v0.3.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-17 14:06:22 +02:00
.github/workflows deps: newest stable (freshness gate); migrate web/ npm -> pnpm 2026-10-16 14:16:56 +02:00
contracts workout-poke: instant phone credit over LAN (signed POST :8773) and Firebase stream 2026-10-09 19:05:51 +02:00
docs 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
prompts drop the weekly shutdown bonus entirely; every bonus stops at the shutdown ceiling 2026-10-10 08:59:50 +02:00
screen_locker Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock 2026-10-17 14:06:22 +02:00
scripts Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock 2026-10-17 14:06:22 +02:00
stronglift_replacement workout_app: log manual workouts for future dates, planned list + delete 2026-10-16 15:36:27 +02:00
web deps: newest stable (freshness gate); migrate web/ npm -> pnpm 2026-10-16 14:16:56 +02:00
.fvmrc deps: Flutter 3.47.7 (fixes red freshness CI) 2026-10-09 10:53:10 +02:00
.gitignore Shutdown: walks as workout, rest days, grace floor, workout ledger (earned-time 0.4.0) 2026-10-09 10:43:45 +02: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 Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock 2026-10-17 14:06:22 +02:00
AGENTS.md Sick days: per-locker keep (sickdays 0.2.0) for the workout lock 2026-10-16 15:18:49 +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 Sync: Firebase only — drop the GitHub transport (kuhyx/syncs stays a frozen archive) 2026-10-09 19:18:56 +02: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 Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock 2026-10-17 14:06:22 +02:00
README.md Sick days: per-locker keep (sickdays 0.2.0) for the workout lock 2026-10-16 15:18:49 +02:00
remove_autostart.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
remove_systemd.sh workout-poke: instant phone credit over LAN (signed POST :8773) and Firebase stream 2026-10-09 19:05:51 +02:00
requirements.txt Lock screen: "choose lockers…" opens sickdays' KeepPanel in the lock 2026-10-17 14:06:22 +02:00
run.sh Reconcile the venv on launch, so a pin bump cannot sit unnoticed 2026-08-23 06:56:26 +02: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
TODO-cap-bonus-at-day-ceiling.md TODO: cap live shutdown bonuses at the day's earned_time ceiling (from the tutor-cutover handoff) 2026-10-10 09:17:58 +02:00
TODO-file-length-250.md Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
TODO-finish-dart-250.md Re-point paths for the ~ reorganisation (home-tidy) 2026-09-11 18:46:28 +02:00
TODO-pylint-to-ten.md Add the removal marker to every TODO file 2026-08-24 15:56:24 +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 and the grace floor stand down, wake-alarm's workday penalty is void, and shutdown is max(20:00, the normal ladder) capped at 23:00 (earned_time.resolve(..., sick=True)). A day marked after its daily reset is lifted to 20:00 by the next 5-minute pass (_sick_floor); a workout that day still earns normally and is paid out of that lift first, so it lands on the ladder value (e.g. 20:40), never 20:00 plus its whole reward. 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).

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.