Build Fitbod

KINDAreplaces $15.99/mosaves $191.88/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A training planner whose interesting logic is progression under uncertainty: deciding what to lift next from what was actually lifted, tracking which muscle groups have recovered, and doing both inside caps that make a bug an inconvenience rather than an injury.

estimated effort multi-daythe files for this build are in the project pack

RuntimeTypeScript with a local application and SQLiteProgressionRules over recent performance with hard caps on rate of increaseRecoveryPer muscle group from volume and elapsed timeEquipmentA declared inventory constraining every suggestionSafetyPain and failure handling evaluated before any progression

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the local application.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. decidefree

    Why Both are enforced as constants before any progression runs, and deciding them after the logic exists means fitting them to the logic rather than to safety.

    Get it Write down the maximum weekly load increase, the deload trigger, and which movements you will not program without stated coaching.

    Verify All three are written down and appear as constants in the safety module

  3. have readyfree

    Why Every generated plan is constrained by it, and the smallest available weight increment determines whether progression is even possible for a given lift.

    Get it List what you have including the real weight increments, which for dumbbells is often much coarser than for a barbell.

    Verify The inventory includes the smallest increment per equipment type

  4. have readyfree, and it takes eight weeks

    Why Progression behaviour, recovery estimates and the failure and deload paths only become observable across weeks of real sessions with real missed reps.

    Get it Log honestly, including the sessions that went badly, since those are the ones the logic is being tested on.

    Verify Eight weeks exist including at least three failed sessions

  5. decidefree

    Why The build stops and says to see someone qualified, and a message with nothing behind it is not much better than a suggested substitution.

    Get it Write the message and decide what it points at, whether that is a professional body's directory or a specific instruction.

    Verify A written message exists and names a concrete next step

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- exercises(id, name, primary_muscles_json, secondary_muscles_json, equipment_required, technical_risk, requires_coaching)
- equipment(id, kind, available, weight_increments_json) · what you actually have, including the smallest increment
- sessions(id, planned_for, completed_at, perceived_effort, notes)
- sets(id, session_id, exercise_id, ordinal, weight, reps, completed_reps, rpe, failed, pain_reported)
- progressions(exercise_id, current_working_weight, last_increase_at, consecutive_successes, capped_by)
- recovery(muscle, last_volume_at, volume_units, estimated_ready_at)
- blocks(exercise_id, reason, from_at, cleared_at) · a movement stopped by pain, cleared only deliberately
- A set records both prescribed and completed repetitions, because the difference between them is the entire input to progression.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
DB_PATHrequired~/.local/share/training/log.dbTraining and pain reports. Health data, so treat backups accordingly.
MAX_WEEKLY_INCREASE_PERCENTrequired5A hard cap in the progression path. Not raisable at runtime.
DELOAD_AFTER_FAILURESrequired2Consecutive failures before load is reduced rather than held.
PAIN_BLOCK_MIN_DAYSrequired14Minimum before a pain block can be cleared, and only deliberately.
SUGGEST_SUBSTITUTES_ON_PAINrequiredneverPresent as a constant. Substitution requires knowing what is wrong.
SESSION_TIME_BUDGET_MINUTESrequired50Plans are generated to fit it, checked against real durations.

The build, in order

  1. Logging a session faster than resting between sets

    Recording a set takes a couple of seconds while you are training.

    1. Most sets go as planned. One action for the common case.

      Files src/logging.ts

    2. Their difference is the whole input to progression.

      Files src/sets.ts

    3. Never read an abandoned session as failure.

      Files src/sessions.ts

    done when · tick each as it passes
    watch out
    • A logging flow requiring several taps per set gets abandoned mid-session, and a partially logged session is worse than an unlogged one because progression will read it as a failure and reduce the next prescription. Default to prescribed values, make completion one action, and mark abandoned sessions rather than treating them as data.
  2. Progression with a ceiling on how fast

    Load increases when earned and never faster than the cap.

    1. Consecutive, recorded, in real increments your equipment has.

      Files src/progression.ts

    2. So a logic error is an inconvenience rather than an injury.

      Files src/caps.tssrc/caps.test.ts

    3. Holding at a weight that keeps failing is not a plan.

      Files src/progression.ts

    done when · tick each as it passes
    watch out
    • Progression rules derived from repetition performance can compound quickly and prescribe a weight the person has never approached, and by the time it is obviously wrong they are already under the bar. Cap the weekly increase as a hard constant so a logic error produces a slightly wrong prescription rather than a dangerous one.
  3. Pain stops the movement, not the plan

    A reported pain removes that movement and does not get worked around.

    1. Not reduce it, not substitute it. Block it.

      Files src/blocks.ts

    2. Substitution requires knowing what is wrong, which the tool does not.

      Files src/blocks.ts

    3. Before any other rule, so nothing can route around them.

      Files src/progression.tstests/pain-blocks.test.ts

    done when · tick each as it passes
    watch out
    • Offering a substitute exercise for a painful movement looks helpful and is the tool diagnosing something it cannot see, since the substitution depends entirely on what is actually wrong. Block the movement, say why, and suggest seeing someone rather than suggesting an alternative loaded exercise.
  4. Knowing what is recovered

    Today's plan avoids what you trained hard two days ago.

    1. Simple, explicable, and honest about being an estimate.

      Files src/recovery.ts

    2. A percentage with no basis reads as a measurement.

      Files src/recovery-view.ts

    3. They know about their sleep and their week. The model does not.

      Files src/recovery.ts

    done when · tick each as it passes
    watch out
    • Presenting a recovery percentage as though it were measured implies a precision that does not exist, since actual recovery depends on sleep, stress, nutrition and things the application cannot see. Show the estimate with what it was computed from, and let the user override it, since they know things the model does not.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more wellness.