BodyCommit
Move while your agent codes.
BodyCommit is a VS Code and Cursor extension for a bit more movement during the workday. Designed sequences fit a Quiet office or a home office, including while an AI agent is working. It waits for a natural pause. There is no score, no streak, and no nudge for skipping.
Your agent commits code. You commit your body.
Features
- Active coding clock. Time counts while the window is focused and a text editor is focused, for a short while after the last keystroke, cursor move, or focus return. Silence pauses the clock. A longer idle resets the session, so a lunch break does not count toward the next reminder.
- Default reminder around 50 active minutes. The interval is a setting.
- Agent-wait heuristic. When the workspace looks like an AI agent, a build, or a long terminal command is busy, that moment is a preferred break slot. It can also offer an earlier nudge. A stricter check, on by default, offers a break when you have not typed for a few seconds and either a known agent CLI or a run of non-user edits has lasted about 35 seconds. It is a best-effort guess.
- Flow respect. A due reminder waits while you are typing. It shows up after a save, when a task or terminal command ends, after about 30 seconds of quiet, or during an agent window. If none of those arrive, it shows after 2 minutes anyway, unless you are mid-keystroke.
- Soft by default. The status bar changes to “break ready” and one notification offers Start a break, Snooze 15m, and Skip. Status-bar-only mode skips the popup. Quiet hours and a rest-of-today do-not-disturb hold reminders. The status bar still shows time since your last break, and clicking it starts one.
- 17 local routines, plus short sequences. Stretching (neck, shoulders, wrists, hips, back, chest), mini workouts with no equipment (including jumping jacks and high knees), and breathing (box breathing, 4-7-8, physiological sigh, an easy even breath). Automatic breaks prefer a 2–4 move sequence that fits your space: a seated neck and shoulder minute, a quiet standing hip and back minute, and a home-office energizer. A 3-minute seated sequence is in the Pro library. Each move has an animated figure. Add routines in
media/routines.json and sequences in media/sequences.json.
- Workspace setup. The first launch asks whether you are in a quiet or small space or a home office, and whether you want seated only, standing, no floor contact, or a smaller range of motion. Quiet mode leaves out loud, large-space moves such as jumping jacks and high knees. Change it later with BodyCommit: Set up your workspace or the
bodycommit.space.* settings.
- Local stats. Breaks finished today, breaks finished this week (Monday through today), minutes moved, and counts per category. Stored in VS Code’s global state on this machine. Skipping a break is not counted and does not change what is offered next.
- End-of-day summary. One notification at 18:00 local, or after an hour of quiet past 16:00, with today's breaks and minutes moved, plus a small tip. See stats opens the panel. Once per day. Quiet hours and do-not-disturb hold it. Turn it off with
bodycommit.daySummary.enabled.
- Free and Pro scaffold. Free includes two routines in each category. Pro unlocks the full library and custom programs. There is no checkout. Pro preview, or the local stub key
BC-PRO-LOCAL, unlocks them on this machine only.
This is not medical advice. Move in a range that feels okay, and stop if something feels off.




Install and try it
The package is a normal VSIX, so it installs in VS Code, Cursor, and any editor that accepts Open VSX packages. It uses the public VS Code API only (engines.vscode ^1.93.0) and runs as a UI extension, so prompts stay on your machine when you are attached to a remote workspace.
From a terminal, after npm run package:
code --install-extension bodycommit-0.3.2.vsix
cursor --install-extension bodycommit-0.3.2.vsix
Or use Extensions: Install from VSIX… in the command palette.
Then:
- Look for BodyCommit in the status bar (
ready, then a time since your last break).
- Run BodyCommit: Start a break or click the status item. The break panel shows one or two short lines, a large timer, and the figure. Steps and keyboard hints sit in a small disclosure. Space pauses. Right arrow advances.
- Run BodyCommit: Show stats for today's breaks, this week, and minutes moved.
- To see a reminder without waiting 50 minutes, set BodyCommit: Interval Minutes to
1. Keep typing and it will wait. Save a file, let a task finish, or sit still for about 30 seconds. With no pause at all, the notification appears after about 2 minutes as long as you are not typing.
- To try the full library, run BodyCommit: Enable Pro preview or set
bodycommit.licenseKey to BC-PRO-LOCAL.
Develop against the extension host with Run BodyCommit in the debugger (F5). That compiles first.
How agent detection works
Nothing here talks to an agent, and nothing is inferred from prompt text. The extension only watches editor and workspace events already available to any VS Code extension, keeps a few seconds of them in memory, and throws them away. Turn the whole thing off with BodyCommit › Agent Detection: Enabled.
A signal is active when any one of these is true. Two at once raises confidence. Thresholds are settings.
- External edit burst. In the burst window (default 8 seconds), document edits that are not keystrokes outnumber edits that are. A keystroke is a small insertion (default 8 characters or fewer) in the focused editor while the window is focused. Edits in other files, edits while the window is unfocused, and larger insertions count as external. One paste is not enough. Ordinary typing is not enough.
- Files changing on disk while you are idle. At least 3 create, change, or delete events across at least 2 files, during the lookback (default 20 seconds), and only if you have been idle at least 20 seconds. A single save does not count.
node_modules, .git, dist, out, build, .next, coverage, and vendor are ignored.
- Long-running task or terminal command. A VS Code task, or an integrated terminal command reported by shell integration, that is still running after 20 seconds. When it ends, that ending is also one of the natural pauses above, even if the command was short.
If a break is already due, an active signal is the preferred moment to show it, including the wording (“Your agent is busy writing code…” versus a plain long-session note). If Early Prompt Minutes is above 0 (default 25), an active signal can offer a break before the full interval. Set it to 0 to keep reminders on the interval only. Early prompts still wait until you are not typing.
This will sometimes be wrong. Formatters, watch scripts, and multi-file refactors can look like an agent. A terminal command only shows up when shell integration is enabled. The cost of a miss is a later reminder, not a popup on top of your typing. If the nudges feel early, turn detection off or raise the thresholds.
bodycommit.agentWait.enabled (default on) is a separate, stricter offer. It fires only when you have not typed for 8 seconds and a known agent CLI (claude, codex, aider, gemini, cursor-agent, goose, opencode, copilot) has been running in the integrated terminal for at least 35 seconds, or non-user edits have spanned at least 35 seconds with one still fresh. It still waits out the reminder interval or 15 minutes, whichever is shorter, and quiet hours, snooze, and do-not-disturb still win. A long npm test does not count. Copilot agent mode and Cursor Composer have no public “agent is running” event, so those are inferred from edits only, and a silent thinking stretch is invisible.
Agent-wait decisions are written to the BodyCommit output channel whenever they change. The older burst heuristic is logged there only when bodycommit.debug is on. The log stays on your machine.
Settings
| Setting |
Default |
What it does |
bodycommit.intervalMinutes |
50 |
Active minutes between reminders. |
bodycommit.notificationStyle |
soft |
soft is the status bar plus one notification. statusBar never pops up. |
bodycommit.snoozeMinutes |
15 |
How long Snooze holds the next reminder. |
bodycommit.categories |
all on |
Stretching, workout, and breathing can each be disabled. |
bodycommit.quietHours.enabled |
false |
Hold reminders between start and end. Overnight ranges work. |
bodycommit.quietHours.start / end |
22:00 / 08:00 |
Local 24-hour HH:MM. |
bodycommit.agentWait.enabled |
true |
Offer a break during a longer agent wait (known CLI or sustained non-user edits, and you are not typing). |
bodycommit.space.environment |
home |
quiet or home. Quiet drops loud and large-space moves. |
bodycommit.space.seatedOnly |
false |
Seated moves only. |
bodycommit.space.standingOk |
true |
Allow standing moves. Off keeps suggestions seated. |
bodycommit.space.noFloor |
false |
Skip moves that use the floor. |
bodycommit.space.limitedMobility |
false |
Skip full-mobility moves. |
bodycommit.breakLength |
auto |
60, 180, or auto (60 seconds, or about 3 minutes after a 3-minute agent wait). |
bodycommit.agentDetection.enabled |
true |
Master switch for the shorter burst heuristic. |
bodycommit.agentDetection.earlyPromptMinutes |
25 |
Early offer during an agent window. 0 disables it. |
bodycommit.agentDetection.burstWindowSeconds |
8 |
Width of an edit burst. |
bodycommit.agentDetection.minExternalChanges |
4 |
External edits required in that window. |
bodycommit.agentDetection.userKeystrokeMaxChars |
8 |
Insertions this size or smaller count as yours. |
bodycommit.agentDetection.diskIdleSeconds |
20 |
How long you must be idle before disk changes count. |
bodycommit.agentDetection.minDiskChanges |
3 |
Disk events required, across at least two files. |
bodycommit.agentDetection.minTaskSeconds |
20 |
How long a task or terminal command must run. |
bodycommit.agentDetection.lookbackSeconds |
20 |
How far back disk events are considered. |
bodycommit.idlePauseSeconds |
90 |
Stop adding active time after this much silence. The total is kept. |
bodycommit.idleResetMinutes |
10 |
Silence past this zeroes the session. Must be longer than the pause. |
bodycommit.typingLockSeconds |
2 |
No reminder within this many seconds of a keystroke. |
bodycommit.naturalPauseSeconds |
30 |
Idle this long counts as a pause. |
bodycommit.saveGraceSeconds |
20 |
A save this fresh counts as a pause. |
bodycommit.taskEndGraceSeconds |
20 |
A finished task or command this fresh counts as a pause. |
bodycommit.maxDeferralSeconds |
120 |
Show a due reminder after this long even with no detected pause. 0 disables it. Typing still holds it. |
bodycommit.proPreview |
false |
Local Pro unlock. No network. |
bodycommit.licenseKey |
empty |
BC-PRO-LOCAL also unlocks Pro locally. It is never sent anywhere. |
bodycommit.daySummary.enabled |
true |
One end-of-day notification. Off skips it. |
bodycommit.daySummary.time |
18:00 |
Local HH:MM for that summary. An hour of quiet after 16:00 can show it sooner. |
bodycommit.debug |
false |
Log heuristic signals to the output channel. |
Skip asks again only after another full interval of active time, or after the session resets. Snooze asks again at the next natural pause once the timer is up. Finishing a break starts the active clock over. Closing a break before 10 seconds does not count it.
How a routine is chosen
Starting a break prefers a sequence that fits your environment, constraints, and the target length (60 seconds, or about 3 minutes when breakLength is 180 or an agent wait has already lasted 3 minutes). A sequence tagged for your environment is preferred over one that fits anywhere. If none fit, it falls back to a single routine. The closest match is used. Equal matches stay in id order, and random only picks among that tie, so the same inputs always return the same routine when the roll is fixed. Skipping or finishing a break does not change the next one.
| Signal |
Effect |
| Recent id |
−50. The last eight started routines are remembered. |
| Same category as last time |
−20, so categories rotate when nothing else is going on. |
| Active session longer than 45 minutes |
+24 for a workout, and another +8 when its intensity is high. |
| Heavy typing |
+36 for a stretch that uses the wrist or shoulder poses. Heavy means 40 or more keystrokes in the last 10 minutes. |
| Local time at or after 20:00, or a session longer than 3 hours |
+22 for breathing, +14 for low intensity, −16 for high intensity. |
| Agent-wait window |
Up to +30 for a short routine, falling as the routine gets longer. A 45-second routine is preferred over a 90-second one. |
Nothing here is uploaded.
Routines
Edit media/routines.json and media/sequences.json. The shape is checked by media/routines.schema.json (associated in .vscode/settings.json). Each item needs an id, title, category (stretching, workout, or breathing), tier (free or pro), intensity (low, medium, or high), a one-line summary, and steps. A step has a title, plain instructions, a whole-second duration, and a pose the panel knows how to draw. Space tags are noise (quiet or loud), space (small or large), posture (seated, standing, or either), floor (boolean), mobility (limited or full), and optional place (any, quiet, or home). Set sequence to true for a 2–4 step flow.
Keep the instructions literal. The reminder copy can carry one light git joke. The steps should not. Write them as movement during the workday, not as care for a back or neck condition. The unit tests fail if cure, heal, therapy, or RSI show up in the library, the sequences, or the panels.
Privacy
- Stats, snooze, do-not-disturb, custom programs, and the license stub live in local extension state. Recent routine ids are remembered only so the next break can vary. Skipping is not stored as a score.
- Document edits and file events used by the heuristic are held in memory for a few seconds and are not written out.
- There is no telemetry, no account, and no network call. Fonts are bundled. The webview does not load remote assets.
- Pro preview and
BC-PRO-LOCAL are local flags so the paid surface can be built later. They are not a purchase.
Development
npm install
npm test
npm run lint
npm run compile
npm run package # writes bodycommit-0.3.2.vsix
npm test covers the activity clock, the agent heuristic, the flow gate, local stats, the license stub, and the shipped routine file. It does not launch VS Code.
The UI fonts are Space Grotesk, Inter, and JetBrains Mono, shipped as WOFF2 under media/fonts/ with their SIL Open Font License texts. If a font fails to load, the panels fall back to the system UI fonts.
License
MIT.
| |