Docs
/
what you can do

Gym

<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->

<!-- GENERATED by ops/tools/skill-sync — do not edit by hand. Run pnpm skills:sync. -->

Gym — what you can do

/admin/d/gym · pillar apps

Run a self-hosted gym — 1,324 exercises, weekly plans, guided sessions, 4 progression systems, AI coach.

Fetch this, never remember it

These change per install and per release. Call for them - a list written here would be a future lie.

WhatCallWhy
this gym's exercise library, including its own custom exercisesGET /api/gym/exercisesthe 1,324 shipped rows are the same everywhere, but a gym's custom exercises are not — and the facets tell you which filter combinations would return anything at all
whether a session is already runningGET /api/gym/overviewrunning is what makes Today resume rather than restart; starting a second session without force silently returns the first
what to lift next for one exercise, and whyGET /api/gym/next/:exerciseIdthe prescription is DERIVED from the log every time it is asked for — never stored — so it is always current and there is no counter to go stale
whether this install can show exercise animations at allGET /api/gym/settingsmediaConfigured is false by default and that is not a fault: the media belongs to Gym visual and Leumas ships none of it

How to actually do things here

Written by hand, because the order and the traps are the part no file can derive.

Give somebody a program to start on

  1. GET /api/gym/starters for the three shipped programs and what each would cost this catalog.
  2. POST /api/gym/routines with starterId to build it, or POST /api/gym/ai/program to have one written.
  3. Check unfilled (starter) or warnings (AI) before telling anyone it is ready.

Trap: A non-empty unfilled means the catalog could not supply those slots — the routine EXISTS and is missing exercises. Say so. The AI lane refuses the whole document rather than dropping an exercise it invented, so a 422 there means nothing was saved, not that something partial was.

Run a workout

  1. POST /api/gym/sessions with { routineId, day } — it returns the sets already prescribed and stamped.
  2. PATCH /api/gym/sessions/:id/sets/:setId with { reps, weight, completed: true } per set as it happens.
  3. POST /api/gym/sessions/:id/finish to close it and get the records it set.

Trap: An unticked set is a MISS, not an absence — that is what stops a session that fell apart from advancing the load next time. Finishing DELETES the unticked rows, so tick as you go rather than at the end. Sending completed: false un-ticks and changes the judgement.

Work out why a weight went down

  1. GET /api/gym/next/:exerciseId and read prescription.reason.text — it names the rule and the count.
  2. GET /api/gym/stats/exercise/:exerciseId for the curve and the records behind it.

Trap: A deload is the policy working, not a bug. Greyskull resets after ONE failure by design where linear gives three attempts. A field the policy has no opinion on comes back undefined, not 0 — reading it as 0 prescribes an empty bar.

Bring history over from another tracker

  1. POST /api/gym/import with the file text and NO commit — this previews and returns unresolved.
  2. Map each unresolved name to an exerciseId and re-post with mapping and commit: true.

Trap: A commit with unresolved names is REFUSED (409) unless you pass ignoreUnresolved, which DROPS those rows. Inventing an exercise is the one irreversible mistake an importer can make, so it will not guess. Weights convert per row, not per file.

Show exercise animations

  1. Obtain a licence from Gym visual, or host a copy you are entitled to.
  2. PATCH /api/gym/settings with mediaBase set to that absolute https origin.

Trap: Leumas ships NO exercise media — it belongs to Gym visual and is excluded from the dataset's MIT grant. There is deliberately no default base, a relative path is refused, and the attribution must render wherever the media does. An empty mediaBase is the correct state, not a broken install.

Tabs

Every one is a real URL. A tab with its own section below carries a real job.

TabPathGroupWhat it is for
desk/admin/gym--
today/admin/gym/today--
plan/admin/gym/plan--
classes/admin/gym/classes--
library/admin/gym/library--
history/admin/gym/history--
stats/admin/gym/stats--
members/admin/gym/members--
settings/admin/gym/settings--

API

Mounted prefixes that serve this domain: /api/gym

The full route table is leumas-capabilities/reference/api-routes.md.

Source .claude/skills/leumas-studio/reference/domains/gym.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt