Go to file
Krzysztof kuhy Rudnicki 186bfcabc4 Run the workout app on Linux, and let it hold the screen lock
The phone is lost, so no workout can be recorded and enforcement has been
disarmed since 2026-08-21. This gives the PC a first-class way to do the
workout, reusing the existing app rather than reimplementing the progression
rules a second time -- two implementations would guarantee the divergence the
"same weights everywhere" requirement forbids.

Storage: sqflite has no Linux plugin, so main() installs sqflite_common_ffi's
factory, which runs the same schema and migrations against the same SQL. It
was already a dev dependency driving the test suite; this only promotes it.

Auth: the account password in ~/.config/crdt-sync no longer authenticates
(verified: HTTP 400 INVALID_LOGIN_CREDENTIALS). The PC fleet has been running
on the cached refresh token all along, so the desktop credential store reads
that same 0600 file -- the Dart and Python credential JSON keys are already
identical -- and passes null instead of the stale password. This also avoids
google_sign_in, which ships no Linux implementation.

Lock mode: --lock-mode makes the window the lock surface. There is no Dart API
for this, so the runner sets override-redirect and takes an exclusive
gdk_seat_grab. Two details cost a debugging cycle each and are commented in
place: override-redirect must be set BEFORE the first map, or the window stays
mapped and never repaints; and gtk_window_fullscreen() only ASKS the window
manager, which cannot see an override-redirect window -- so the geometry is
set from the monitor directly, otherwise a strip of live desktop is left
uncovered at the edge of a larger screen.

The grab is acquired by retry rather than by asking the supervisor to release
first: the Python locker keeps its grab while this window maps on top, so the
screen is covered continuously instead of exposing the desktop for the whole
of Flutter's cold start.

Verified against the live data: pulls all 7 exercises from Firebase (Bench
17.5x12, RDL 27.5x8, Row 25x6, Situp 10x31 -- the real weights, not factory
defaults), leaves the remote progression byte-identical, and mints its own
device id rather than reusing the phone's. A Tk client is refused the grab
while the lock holds it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfJC1Wu1SEgJ6X49k5Jqtg
2026-08-22 11:18:48 +02:00
.github/workflows Finish the Python side: scripts, conftest, and the last test modules 2026-08-15 20:57:29 +02:00
docs Stop the relaxed-day popup from re-firing every 30 minutes after Skip 2026-08-18 21:55:59 +02:00
prompts Stop the relaxed-day popup from re-firing every 30 minutes after Skip 2026-08-18 21:55:59 +02:00
screen_locker Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
scripts Queue behind stronger lockers, single-instance guard, fix budget-crash in fit check 2026-08-21 13:04:54 +02:00
stronglift_replacement Run the workout app on Linux, and let it hold the screen lock 2026-08-22 11:18:48 +02:00
.gitignore Stop the relaxed-day popup from re-firing every 30 minutes after Skip 2026-08-18 21:55:59 +02:00
.mcp.json Add read-only MCP server exposing workout/lock status 2026-07-10 21:28:09 +02:00
.pre-commit-config.yaml Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
arm.sh Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +02:00
CLAUDE.md Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
DESIGN_AUDIT_TODO.md Split DESIGN_AUDIT_TODO.md into one file per audited surface 2026-08-15 21:27:19 +02:00
early-bird-workout-check.timer Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +02:00
install_autostart.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
install_systemd.sh Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +02:00
install.sh Make every lock screen keyboard-operable, and add the missing installer 2026-07-30 16:25:45 +02:00
pyproject.toml Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
README.md Add read-only MCP server exposing workout/lock status 2026-07-10 21:28:09 +02:00
refactor_claude_todo.md Refresh the refactor todo: 41 -> 10 files over the cap 2026-08-15 21:46:16 +02:00
remove_autostart.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
remove_systemd.sh Let the PC see phone workouts again, and stop losing progression on reinstall 2026-08-10 14:39:02 +02:00
requirements.txt Adopt crdt-sync v0.9.0's bundled sync_log signature 2026-08-21 14:28:14 +02:00
run.sh chore: set up as standalone repo 2026-05-28 07:43:06 +02:00
todo_finish_dart_250_prompt.md Add todo_finish_dart_250_prompt.md and the Dart test splitter 2026-08-15 21:49:15 +02:00
todo_fix_pylint_10_prompt.md Add todo_fix_pylint_10_prompt.md: raise pylint to a 10.00 gate 2026-08-15 19:18:39 +02:00
workout-locker.service Drop WorkingDirectory/PYTHONPATH from workout-locker.service 2026-06-22 12:43:58 +02:00
workout-locker.timer Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +02:00
workout-sync.service Re-arm the locker, and make a disarmed enforcer impossible to miss 2026-08-17 16:47:25 +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, sick-day management, and wake-alarm integration. It enforces a workout cadence by locking the screen until a RunnerUp-verified (or explicitly justified) workout is logged.

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.