{"slug": "claude-workout-gate", "title": "Claude Workout Gate", "summary": "A new Claude Code plugin called 'Workout Gate' blocks AI prompts until users complete physical exercises like push-ups or squats, counted live via webcam. The tool, created by developer BotchetDig, aims to encourage fitness by requiring users to work out before their AI assistant responds, with features like session-persistent debt and streak tracking.", "body_md": "Your AI works hard, so should you.\n\nA Claude Code hook that blocks your prompt until you work out — push-ups or\nsquats, counted live via webcam. When a challenge fires you pick your pain\n(say 6 push-ups *or* 9 squats). Random reps, session-persistent debt (no\nclosing the tab to skip), streak stats, and three trigger modes.\n\n*Version française : README.fr.md*\n\n**Python 3.9–3.13**— including the macOS system Python 3.9, so there's no newer Python to install.- A\n**webcam**+ an internet connection (first run downloads MediaPipe/OpenCV and a ~9 MB pose model). **macOS** for the zero-config plugin onboarding — it pops the setup in a Terminal and triggers the camera-permission dialog. Linux/Windows work too; Claude just points you at`bootstrap.sh`\n\nto run once by hand.`git`\n\nand`python3`\n\non your PATH.\n\n```\n/plugin marketplace add BotchetDig/workout-gate\n/plugin install workout-gate@workout-gate\n```\n\nThen **start a new session** (or run `/reload-plugins`\n\n) — nothing happens\nuntil you do. Onboarding pops up in a Terminal window on its own —\ndependencies install, then a 30-second wizard (your max, trigger choice, a\n2-pushup camera test). Until setup is done, prompts pass freely. The gate and\n`/workout-gate:workout`\n\nthen work in every session, and plugin updates never\nbreak the install (the runtime lives in `~/.workout-gate/`\n\n).\n\n```\ncurl -fsSL https://raw.githubusercontent.com/BotchetDig/workout-gate/main/get.sh | bash\n```\n\nRe-running the same line updates the install. Prefer to look around first?\n\n```\ngit clone https://github.com/BotchetDig/workout-gate.git && cd workout-gate\n./install.sh\n```\n\nThe installer sets everything up (venv, dependencies, pose model) then walks you through a 30-second wizard: it asks your one-set max to size the challenges to you (25–50% of it), lets you pick a trigger, offers the global install, and runs a 2-pushup camera test so the macOS permission dialog happens now — not in the middle of your first gated prompt.\n\nRe-run the wizard anytime with `workout setup`\n\n. Use `./install.sh --no-setup`\n\nfor a non-interactive install with defaults (every 15 prompts, 5–10 reps).\n\nDrive it with `! workout`\n\nfrom inside Claude Code (the `!`\n\nprefix runs a shell\ncommand — instant, **zero tokens**), or just `workout`\n\nfrom any terminal.\n\n| Command | Effect |\n|---|---|\n`! workout` |\nopen the web dashboard (settings + live stats) in your browser |\n`! workout tui` |\nthe terminal dashboard instead (curses, arrow keys) |\n`! workout now` |\nforce a challenge right now (great for filming) |\n`! workout stats` |\nper-exercise totals + 7-day chart (arrow keys to switch exercise in a real terminal) |\n`! workout status` |\ngate state (counter, debt, settings) |\n`! workout on` / `off` |\nenable / disable |\n`! workout stop` |\nclose a running challenge window |\n`! workout preset chill|demo|hardcore` |\nsee presets below |\n`! workout enable|disable squats` |\nturn an exercise on/off |\n`! workout set reps squats 8 15` |\nrep range for one exercise |\n`! workout set mode choice|random` |\npick the exercise yourself, or at random |\n`! workout debug on|off` |\noverlay the detected skeleton + live joint angle (handy when adding exercises) |\n`! workout set freq 15` |\none challenge every 15 prompts |\n`! workout set time 30` |\ntime-based: at most one challenge per 30 min |\n`! workout set chance 10` |\nroulette: 10% chance on every prompt |\n\nThere's also a\n\n`/workout-gate:workout`\n\nslash command, but it routes through Claude and costs tokens — prefer`! workout`\n\nfor everything above.\n\n`! workout`\n\n(or `workout`\n\nin a terminal) opens the **web dashboard** in your\nbrowser. It's organised in **tabs**: an **Overview** tab (all the settings —\npreset, trigger, gate on/off — plus combined stats) and **one tab per\nexercise**, each with its own enable toggle, rep range, today/total counters and\n7-day chart. Add an exercise (one entry in `detector.py`\n\n) and its tab appears on\nits own. A \"force a challenge\" button is one click away. It's a tiny local-only\nserver (stdlib, no dependencies, bound to `127.0.0.1`\n\n) that shuts itself down a\nfew minutes after you close the tab.\n\nPrefer the terminal? `! workout tui`\n\nopens the curses **settings** dashboard\n(arrow keys to navigate, left/right to change values), and `! workout stats`\n\nis\nthe dedicated **stats** viewer (←/→ cycles through ALL + each exercise: total,\nstreak, record, 7-day chart). Both pop up in a Terminal window on macOS; the\nwebcam challenge itself is unchanged everywhere.\n\n**chill**— every 25 prompts, 3–6 reps. Everyday use.** demo**— every single prompt, 5–8 reps. Filming mode.** hardcore**— every 5 prompts, 15–25 reps. You asked for it.\n\n- A\n`UserPromptSubmit`\n\nhook counts your prompts. When a challenge is due, it draws a random rep count,**persists the debt to disk first**, opens the webcam window and freezes your prompt until you're done. Then the prompt sends itself. - Detection: MediaPipe Pose. Push-ups from the elbow angle (\n**profile view, on the floor**, body horizontal); squats from the knee angle (** stand in full view, side-on**, body upright). One rep = full descent then full extension, with smoothing and a posture guard so you can't cheat. - When more than one exercise is enabled, the challenge offers a choice\n(\"pick your pain\") — or picks at random in\n`mode random`\n\n. - Every rep is written to disk the moment it happens (atomic writes): quit at 4/8 and you keep 4 in the stats, with 4 still owed next session.\n- Data lives in\n`~/.workout-gate/`\n\n:`config.json`\n\n,`state.json`\n\n,`stats.json`\n\n,`gate.log`\n\n.\n\n`! workout off`\n\nfrom inside Claude Code — prompts starting with`!`\n\nor`/workout`\n\nare never gated, so you can always reach this.`workout off`\n\nfrom any terminal.`WORKOUT_GATE_OFF=1`\n\nenv var bypasses everything.**Fail-open**: no webcam, broken dependency, any crash → your prompt goes through and the error lands in`~/.workout-gate/gate.log`\n\n. You can never be locked out of your own tool.\n\nBy default the gate only fires in this folder. To gate **every** Claude Code\nsession on your machine (the plugin install does this for you):\n\n```\n./install.sh --global        # or: workout global on\nworkout global off           # to remove\n```\n\nThis surgically adds one hook entry to `~/.claude/settings.json`\n\n(a backup of\nyour original file is kept next to it) and removes exactly that on `off`\n\n.\nTakes effect in new sessions.\n\n```\n.venv/bin/python -m unittest discover -s tests\n```\n\nShow your reps right in the Claude Code statusline. `workout statusline`\n\nprints\na compact self-colored segment — `🏋 36 🔥4d`\n\n(today's reps + day streak).\n\nClaude Code runs one statusline command (`statusLine`\n\nin `settings.json`\n\n). If\nyou already have a statusline script, append the segment to its output:\n\n```\n# near the end of your statusline script, before the final printf\nWG=\"$HOME/.local/bin/workout\"\n[ -x \"$WG\" ] && wg=$(\"$WG\" statusline 2>/dev/null)\n# ...then add  ${wg:+ $wg}  to your printf\n```\n\nOr, for a statusline that's *only* the workout segment, set in\n`settings.json`\n\n:\n\n```\n\"statusLine\": { \"type\": \"command\", \"command\": \"workout statusline\" }\n```\n\nEverything routes through one registry, `detector.EXERCISES`\n\n. Adding an\nexercise is two steps in `workout_gate/detector.py`\n\nand nothing else:\n\n-\n**A counter**— subclass`ExerciseCounter`\n\n, declare the joint angle to track and the down/up thresholds (override`posture()`\n\nto reject bad form):\n\n```\nclass SitupCounter(ExerciseCounter):\n    SIDES = ((L_HIP, L_SHOULDER, L_KNEE), (R_HIP, R_SHOULDER, R_KNEE))\n    DOWN_ANGLE = 55.0   # torso folded\n    UP_ANGLE = 110.0    # lying back\n```\n\n-\n**A registry entry**:\n\n```\n\"situps\": {\n    \"label\": \"SIT-UPS\", \"counter\": SitupCounter,\n    \"cue\": \"LIE DOWN - SIDE-ON\",\n    \"default_reps\": (8, 15), \"default_max\": 30,\n},\n```\n\nConfig defaults, presets, the setup wizard, the dashboard, the choice screen\nand per-exercise stats all read the registry — they pick it up automatically.\nRun the tests (`test_factory.py`\n\nproves a new entry flows end-to-end).", "url": "https://wpnews.pro/news/claude-workout-gate", "canonical_source": "https://github.com/BotchetDig/workout-gate", "published_at": "2026-06-16 17:42:41+00:00", "updated_at": "2026-06-16 17:49:22.636059+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "computer-vision", "machine-learning"], "entities": ["Claude Code", "BotchetDig", "MediaPipe", "OpenCV", "macOS", "Linux", "Windows", "Python"], "alternates": {"html": "https://wpnews.pro/news/claude-workout-gate", "markdown": "https://wpnews.pro/news/claude-workout-gate.md", "text": "https://wpnews.pro/news/claude-workout-gate.txt", "jsonld": "https://wpnews.pro/news/claude-workout-gate.jsonld"}}