Your AI works hard, so should you. A Claude Code and Codex hook that blocks your prompt until you work out β push-ups or squats, counted live via webcam.
> /plugin marketplace add BotchetDig/workout-gate> /plugin install workout-gate@workout-gate
Your AI works hard, so should you.
A Claude Code and Codex hook that blocks your prompt until you work out β push-ups or squats, counted live via webcam. When a challenge fires you pick your pain (say 6 push-ups or 9 squats). Random reps, session-persistent debt (no closing the tab to skip), streak stats, and three trigger modes.
Version franΓ§aise : README.fr.md Β· made by @Botchet
bootstrap.sh to run once by hand.git and python3 on your PATH./plugin marketplace add BotchetDig/workout-gate
/plugin install workout-gate@workout-gate
Then start a new session (or run /reload-plugins) β nothing happens
until you do. The plugin works in Claude Code CLI and desktop. Onboarding pops
up in a Terminal window on its own β dependencies install, then a 30-second
wizard (your max, trigger choice, a 2-pushup camera test). Until setup is done,
prompts pass freely. The gate and /workout-gate:workout then work in every
session, and plugin updates never break the install (the runtime lives in
~/.workout-gate/).
The gate uses the same UserPromptSubmit hook in Codex β CLI and desktop.
From Codex, open /plugins, add the BotchetDig/workout-gate marketplace if
needed, then install workout-gate. Codex shows the hook review separately, so
approve the plugin hooks once with /hooks before testing a prompt.
Prefer terminal commands? After setup, wire it into all your Codex sessions:
workout codex on # adds the hook to ~/.codex/hooks.json
workout codex off # remove it
If workout is not on your PATH yet, use the installed launcher directly:
~/.workout-gate/app/workout codex on
Heads-up: workout global on wires both Claude Code and Codex when it sees
~/.codex, because you're gating your AI usage, not one tool. Verified working
across all four surfaces β Claude Code CLI and desktop, Codex CLI and desktop.
Everything is shared across tools: one runtime in ~/.workout-gate/ holds
your debt, prompt counter, stats and streak. Dodge a challenge in Claude Code
and the debt blocks your next Codex prompt. Concurrent prompts from two tools
can't double-trigger (the counter is locked) and never open two webcam windows
at once (a challenge already running elsewhere just lets the other prompt
through). On macOS desktop flows that run hooks without a controlling terminal,
the challenge opens in a Terminal window so the camera prompt attaches to
Terminal β force it either way with WORKOUT_GATE_TERMINAL=1 / 0.
curl -fsSL https://raw.githubusercontent.com/BotchetDig/workout-gate/main/get.sh | bash
Re-running the same line updates the install. Prefer to look around first?
git clone https://github.com/BotchetDig/workout-gate.git && cd workout-gate
./install.sh
The 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.
Re-run the wizard anytime with workout setup. Use ./install.sh --no-setup
for a non-interactive install with defaults (every 15 prompts, 5β10 reps).
Drive it with ! workout from inside Claude Code (the ! prefix runs a shell
command β instant, zero tokens), or just workout from any terminal. Codex
CLI does not have Claude's ! shell shortcut, so use a terminal for settings
commands like workout on, workout off, and workout status.
| Command | Effect |
|---|---|
! workout | open the web dashboard (settings + live stats) in your browser |
! workout tui | the terminal dashboard instead (curses, arrow keys) |
! workout now | force a challenge right now (great for filming) |
! workout stats | per-exercise totals + 7-day chart (arrow keys to switch exercise in a real terminal) |
! workout status | gate state (counter, debt, settings) |
! workout on / off | enable / disable |
! workout stop | close a running challenge window |
! workout preset chill|demo|hardcore | see presets below |
! workout enable|disable squats | turn an exercise on/off |
! workout set reps squats 8 15 | rep range for one exercise |
! workout set mode choice|random | pick the exercise yourself, or at random |
! workout debug on|off | overlay the detected skeleton + live joint angle (handy when adding exercises) |
! workout set freq 15 | one challenge every 15 prompts |
! workout set time 30 | time-based: at most one challenge per 30 min |
! workout set chance 10 | roulette: 10% chance on every prompt |
There's also a
/workout-gate:workoutslash command, but it routes through Claude and costs tokens β prefer! workoutfor everything above.
! workout (or workout in a terminal) opens the web dashboard in your
browser. It's organised in tabs: an Overview tab (all the settings β
preset, trigger, gate on/off β plus combined stats) and one tab per
exercise, each with its own enable toggle, rep range, today/total counters and
7-day chart. Add an exercise (one entry in detector.py) and its tab appears on
its own. A "force a challenge" button is one click away. It's a tiny local-only
server (stdlib, no dependencies, bound to 127.0.0.1) that shuts itself down a
few minutes after you close the tab.
Prefer the terminal? ! workout tui opens the curses settings dashboard
(arrow keys to navigate, left/right to change values), and ! workout stats is
the dedicated stats viewer (β/β cycles through ALL + each exercise: total,
streak, record, 7-day chart). Both pop up in a Terminal window on macOS; the
webcam challenge itself is unchanged everywhere.
UserPromptSubmit hook 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.mode random.~/.workout-gate/: config.json, state.json, stats.json,
gate.log.workout off from any terminal β the universal off switch (works no matter
which tool you're in)./workout ... in Claude Code, or the bare workout ... / wg ... forms
in Codex CLI. They may still cost a model turn in Codex; use a terminal for
zero-token control.WORKOUT_GATE_OFF=1 env var bypasses everything.~/.workout-gate/gate.log. You can never be
locked out of your own tool.By default the gate only fires in this folder. To gate every Claude Code session on your machine (the plugin install does this for you):
./install.sh --global # or: workout global on
workout global off # to remove
This surgically adds one hook entry to ~/.claude/settings.json (a backup of
your original file is kept next to it) and removes exactly that on off.
Takes effect in new sessions.
For Codex CLI without the plugin, use:
workout codex on
workout codex off
Then approve the hook once with /hooks in a new Codex CLI session.
.venv/bin/python -m unittest discover -s tests
Show your reps right in the Claude Code statusline. workout statusline prints
a compact self-colored segment β π 36 π₯4d (today's reps + day streak).
Claude Code runs one statusline command (statusLine in settings.json). If
you already have a statusline script, append the segment to its output:
# near the end of your statusline script, before the final printf
WG="$HOME/.local/bin/workout"
[ -x "$WG" ] && wg=$("$WG" statusline 2>/dev/null)
# ...then add ${wg:+ $wg} to your printf
Or, for a statusline that's only the workout segment, set in
settings.json:
"statusLine": { "type": "command", "command": "workout statusline" }
Everything routes through one registry, detector.EXERCISES. Adding an
exercise is two steps in workout_gate/detector.py and nothing else:
A counter β subclass ExerciseCounter, declare the joint angle to
track and the down/up thresholds (override posture() to reject bad form):
class SitupCounter(ExerciseCounter):
SIDES = ((L_HIP, L_SHOULDER, L_KNEE), (R_HIP, R_SHOULDER, R_KNEE))
DOWN_ANGLE = 55.0 # torso folded
UP_ANGLE = 110.0 # lying back
A registry entry:
"situps": {
"label": "SIT-UPS", "counter": SitupCounter,
"cue": "LIE DOWN - SIDE-ON",
"default_reps": (8, 15), "default_max": 30,
},
Config defaults, presets, the setup wizard, the dashboard, the choice screen
and per-exercise stats all read the registry β they pick it up automatically.
Run the tests (test_factory.py proves a new entry flows end-to-end).
Built by @Botchet. If Workout Gate made you sweat, a follow is appreciated. ποΈ
workout-gate is a Claude Code plugin, indexed on Flowy in the Entertainment category. Install it with the command on its page. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it