lift-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev f9f4e37d6945
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 23e397d8a5d5bf7756362640
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Lift

Lift is a free workout log for the gym, and a free alternative to Strong Pro and Hevy Pro. It is an OpenApp in the OpenApps free apps store (https://openapps.free/), owned by the OpenApps team.

## What it promises

- Free, with no limit on routines, exercises or history, no ads, no third-party trackers and no paid tier, and nothing is sold. The hosting counts visits (page views, a random visitor id, speed and errors). Never add a cap, an upsell or a tracker.
- No sign-up to start. Every visitor is a guest account created in the browser; the log is kept on the device and in that account.
- "Keep my log on all devices" signs in with Bounded hosted email login, and the guest's log merges into the account.
- A person's log is private: only they can read or write it. Routines are shared as links that carry the routine itself (no weights, no history), so sharing never opens anyone's data.
- No API for workout data, on purpose: the log is personal. `public/openapi.json` only describes the public guides and the link formats (`/r`, `/plates`); keep it in step with `llms.txt`. `public/llms.txt` explains the app, the routine link format (`/r?name=...&e=...`), the template links, the plate calculator link and every exercise id. Keep that file true. The build fails if its exercise list drifts from the library.
- Honest about limits: no import from other apps yet, no watch app, the beep may stop on a locked iPhone, and iPhones cannot vibrate from a web page. Lift is a log, not a coach, and says it is not medical or training advice.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read. The quick start mounts into `#start`; the app's tabs mount into `#app-nav` on wide screens. Keep its copy, template list, comparison (figures from `docs/research/wave4-pricing.md` in the store repo, marked as reported in 2026), FAQ and JSON-LD in step with what the app does. `public/index.md` is the same page as plain markdown for AI agents; keep it in step too.
- `src/main.tsx` keeps `/` as the landing; `/workout`, `/routines/<id>`, `/r`, `/history`, `/history/<id>`, `/exercises`, `/exercises/<id>`, `/profile` and `/plates` hide it and show the app (`src/Shell.tsx`).
- `src/lib/library.ts` is the exercise library (166 exercises; ids are stable because links and history use them). Each exercise has a kind: `w` weight and reps, `b` reps with optional added weight, `t` time, `c` distance and time.
- `src/lib/model.ts` holds the data shapes and all the counting: units (weights stored in kg, distances in km, times in seconds), records (heaviest, best estimated 1RM by Epley, most reps, longest time, farthest), last session's sets for the "Previous" column, chart values, the routine link format (`routineQuery`, `parseRoutine`), CSV. `src/lib/templates.ts` holds the ready-made routines as routine links.
- `src/lib/store.ts` keeps two stores in localStorage: the log (`lift:v1`: settings, your exercises, body weight, routines, finished workouts) and the workout in progress with its rest timer (`lift:active`, device only, so typing a set stays fast and survives reloads and dead signal).
- `src/lib/sync.ts` syncs the log with Bounded: it reads the account's copy, merges by each item's `at` timestamp (body weight by day), then writes only what changed, and reads again when the app comes back to the front (at most every 30 seconds). Routine and workout docs carry the server time they were written (`at`, from `serverTimestamp()`); after the first sync a device reads only docs written since the newest one it has seen (minus five minutes), and remembers which version of each doc the account holds (`state.sync`, saved with the log), so a long history is not downloaded or uploaded again. It never writes before the first successful read. Deleted routines, workouts and exercises stay as markers.
- `src/lib/timer.ts` schedules the end-of-rest beeps on the audio clock when rest starts (so they play with the tab in the background), vibrates on Android, and keeps the screen on during a workout (wake lock).
- `src/Logger.tsx` is the set-by-set log, used live for the workout in progress and as an editor for a finished workout. `src/Workout.tsx` is the Workout tab and the rest bar; `src/Routines.tsx` the routine editor and the read-only routine page; `src/History.tsx`, `src/Exercises.tsx`, `src/Profile.tsx`, `src/Plates.tsx` and `src/Chart.tsx` the rest.
- `policy.json`:
  - `lifters/<userId>`: settings, your exercises and body weight as JSON. Owner only, no deletes.
  - `lifters/<userId>/routines/<routineId>`: one routine as JSON, plus the server time it was written. Owner only, no deletes.
  - `lifters/<userId>/workouts/<workoutId>`: one finished workout as JSON, plus the server time it was written. Owner only, no deletes.
  - A routine or workout `at` later than the server's now is refused: other devices read only docs newer than the newest `at` they have seen, so one future `at` would hide every later change from them. Always write it with `serverTimestamp()`.
  - Size caps are constants (`PROFILE_MAX`, `ROUTINE_MAX`, `WORKOUT_MAX`); `policy-tests/` covers every access rule with the caps shrunk: run `bounded tests run`.
- `src/sw.js` becomes `/sw.js` at build (`vite.config.ts` fills in the file list) and keeps the app on the device, so it opens offline. `public/manifest.webmanifest` and `public/icons/` (crops of the card art) make it installable.

## Working on it

`npm install && npm run build` typechecks and builds `dist/`. `npm run dev` serves it on port 4350. Ship changes through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly.

Check a change by starting a template, logging sets with the check (last time's numbers fill in), marking a warm-up and a drop set, making a superset, letting the rest timer run out, reloading mid-workout, finishing, and then looking at History, the exercise's records and chart, and Profile. Open a routine's share link in a second browser and save it.

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens, and say plainly what Lift does not do. No fitness hype, no promises about results.

Change history

Point OpenApps store links to openapps.free
f9f4e37d69 · 17 hours ago
Add favicon.ico, local share image and openapi.json for links and guides
2796c0063c · 18 hours ago
Bind agent address in policy constants
cf80a3ca66 · 19 hours ago
Add OpenApp contribution strip and OpenApps source links
5e4cc2b9f3 · 19 hours ago
Bounded source sync
ca4a3d3631 · 1 day ago
Bounded source sync
7351063f4d · 1 day ago
Bounded source sync
0ce3238c46 · 1 day ago