openGym logo

openGym

Self-hosted gym and body-weight tracker with workout planning and muscle recovery tracking

Alternative to: strong, hevy, fitnotes

openGym screenshotopenGym screenshotopenGym screenshot

About Versions (28)

v1.2.7

2026-08-18

The muscle map answers a third question. Balance showed where the volume went and Fatigue what was still recovering; Strength now names the exercises behind a muscle and what each one is worth in estimated 1RM. Fatigue itself got harder to fool — a set counts for more the closer it is to your maximum, and it can no longer creep upward across a rest week. In a session, supersets finally behave: pair them as you go, rest once per round, and drop an exercise you have decided against.

The muscle map, read as strength

  • A per-muscle exercise breakdown behind the muscle card — estimated 1RM per exercise, decay bars, and primary/secondary tags, with a best-weight fallback for holds and carries that have no reps to work from. Contributed by @Space-Hermes in #92, #93 and #94.
  • Fatigue is now intensity-weighted, not volume alone: a set counts for more the closer it is to your estimated maximum. It also reads against a stable historical reference, so fatigue can no longer rise across a rest week, and bodyweight movements no longer register as zero load. A property probe over 108,000 comparisons runs in CI to keep it that way. Contributed by @Space-Hermes in #55.

In a session

  • 🔗 Supersets advance properly. Completing a set moves to the next member of the group, the active exercise scrolls into view, and rest starts once the whole round is done rather than after each set. Contributed by @Space-Hermes in #80.
  • ➖ Remove an exercise from a running session, with a superset-aware picker and a confirmation. Contributed by @Space-Hermes in #83.
  • ⬅️ The Android back button closes the open sheet instead of leaving the screen or the app (#63). Each open sheet gets its own history entry, so stacked sheets unwind one at a time. Contributed by @Space-Hermes in #85.

Self-hosting

  • 🐳 The API service no longer has to be called api (#99). The web image builds its nginx config at startup from BACKEND, PORT and NGINX_PORT, all defaulted to today’s values, so existing compose files are unaffected. Reported and fixed by @GAS85 in #100.
  • …and the shipped docker-compose.yml now actually passes those through. The web service had no environment of its own and published a hardcoded :80, so setting BACKEND or NGINX_PORT in .env did nothing at all on the stock stack — the setting existed, the wiring did not. Both services now read PORT from the same place, so nginx cannot end up proxying to a port the API is not listening on. Defaults are unchanged, so an existing .env behaves exactly as before.
  • 🏷️ Health checks and OCI image labels on both images — source, licence, version, revision and build date, so image tooling can tell what it is holding. Contributed by @GAS85 in #98.
  • Images are published from a release, not from any tag (#87). A tag that gets consolidated away before it becomes a release used to leave its image tags behind in the registry, where dependency bots read them as newer versions.

Fixes

  • Imported warm-up sets were counted as work. The importer marks them with phase, but several places still read the older boolean, so warm-ups from FitNotes/Strong/Hevy history inflated set counts, progression and the fatigue map.