What It Means for openGym to Be Yours
openGym is a self-hosted gym and body-weight tracker, but that description is only the starting point. The more useful question is what “self-hosted” changes in the product itself. This series examines how openGym tries to keep a person’s training record under their control while still offering guided workouts, offline use, device synchronization, progress views, and optional AI assistance. The reader’s practical task is to understand where that control lives, what it enables, and which responsibilities come with it.
Ownership Is a Product Decision
Many applications can be moved onto a private server without becoming meaningfully different products. A user might change the address of the service while the underlying relationship remains the same: the important data is still held by someone else, the application still depends on a remote account, and the user has little visibility into how the service stores or transforms their history. openGym takes a more explicit position. Its documentation describes a system that runs on the user’s own machine, keeps durable data in a folder the operator controls, and does not require a third-party account, subscription, advertising, or telemetry in the default installation.
That promise matters because a training log is not just a collection of recent screen states. It is a record that accumulates value over time: routines express intent, completed workouts record what actually happened, body-weight entries add context, and progress views interpret the history. Losing access to that record can be more damaging than losing access to a single session. Ownership therefore has to cover more than where the web page is served. It has to cover who can recover the files, who can move them to another instance, which device is allowed to edit them, and whether a later calculation can be traced back to the underlying entries.
A useful distinction follows. The person who owns a record is not necessarily the person who owns every computation made from it. openGym can derive a next target, an estimated strength value, or a muscle-recovery display without treating those results as new facts that replace the log. It can also keep media outside the ordinary state document and let an optional provider see only a bounded projection. These choices matter because they preserve a route back to the underlying record. If a calculation is wrong, the user can correct the history or change the rule instead of trying to repair an invisible counter maintained by a remote service.
At the same time, openGym does not present control as a reason to accept a primitive interface. The project aims to behave like a modern application: it can be installed as a progressive web app, work offline, synchronize between a phone and a computer, and use passkeys for sign-in. It includes planning, guided training, progress analysis, import/export, and multi-profile administration. The design problem is consequently not “private storage or convenience.” It is how to make convenience operate on a boundary the user can inspect and manage.
That distinction also keeps the subject precise. This is not a general argument that every application should be self-hosted, nor is it a fitness-programming guide detached from software design. It is an examination of openGym’s particular attempt to connect a user-owned record with a derived, multi-device training experience. The important test is not whether the project uses a familiar stack or exposes a configuration file. It is whether the choices made at each transition—saving, editing, syncing, exporting, authenticating, or sending data to an external provider—leave the user able to understand and recover their own history.
The Small Operating Map
The simplest way to understand openGym is to follow the data rather than list the features. In the server-backed mode, a browser loads the application through a web container. That web layer serves the static interface and proxies API requests to a separate Node-based API. The arrangement keeps the application on one browser origin, which is important because passkeys are bound to a hostname and origin. The API stores account information and each profile’s state as files under the host’s data directory. The durable profile state includes the plan, workouts, body-weight history, and settings; media and certain credentials are kept on separate paths rather than being folded into the ordinary state document.
This division gives each layer a different job. The browser or phone provides the interaction and can hold a live session. The API authenticates the profile, reads and writes the shared state, and coordinates access between devices. The host filesystem is where the operator can back up or restore the durable record. Media is handled as a separate resource because large binary files should not be treated like a small change to a workout document. The point is not that these boundaries are universally superior; it is that they make it possible to ask where a failure occurred and what can be recovered.
The browser is not merely a display for that server copy. It holds the working state needed to run a session, and it may continue to operate when the network is unavailable. A completed workout can remain on the device until it reaches the server. That local behavior is what makes offline use practical, but it also creates the central systems question that the rest of this series will return to: when two copies both contain legitimate work, how can openGym preserve the meaning of both? Keeping a live workout local is useful because a half-finished session is not the same thing as a completed historical record. It also means the application must decide carefully what is safe to replace and what must be carried forward.
The phone app makes the ownership choices more visible because it supports more than one mode. In local mode, the phone is the account. The app does not need a server or a sign-in, and it mirrors its state into a private file so that browser storage inside the mobile shell is not the only durable copy. In connected mode, the same app can pair with a self-hosted server. The phone then keeps a local copy for offline work, but the server becomes the shared home for that profile. Pairing uses a short-lived code from an already signed-in browser because the mobile WebView cannot perform a passkey ceremony at the server’s real hostname.
There is also a guest mode in the browser. It is deliberately different from a signed-in profile: the data stays in that browser and never reaches the backend. That can be useful for trying the application, but it does not provide server backup, cross-device continuity, or an administrator’s view. The distinction is easy to miss if “local” is treated as one category. Local browser storage, local phone storage, and a server-owned profile all keep data away from a conventional hosted account, but they offer different recovery and synchronization properties.
The optional paths are important precisely because they are not the core path. The AI Coach can send selected training information to a provider configured by the operator, while the MCP bridge gives an external local LLM client a read-only view of selected profile information. Neither is needed to log a workout or keep the ordinary application running. Treating them as optional prevents “the application” from becoming an undifferentiated black box: the core can remain within the self-hosted boundary while integrations cross it by an explicit decision.
Control Always Comes With a Boundary
The ownership model creates a useful set of questions. Where is the authoritative copy for this mode? What remains only on a device? Which data is a durable fact, and which value is calculated again from the history? If an optional provider is enabled, what information is allowed to leave the server? Who can read a backup? Who is responsible when a hostname, reverse proxy, disk, or certificate is wrong?
Those questions are not administrative footnotes. They define what the product can safely promise. The application can implement passkey verification, signed sessions, profile-scoped data access, and controls around optional integrations. It cannot make the host filesystem invisible to the person who controls the host. The project’s own security documentation states that the data directory is not encrypted at rest; an operator, backup recipient, or intruder with access to that directory can read the stored profiles. A self-hosted deployment changes who holds that authority, but it does not remove authority from the system.
The same is true of convenience. A server-backed profile can provide continuity across devices, but it requires HTTPS, correct origin settings, backups, updates, and a working reverse proxy. A local phone mode reduces server responsibility, but it gives up server-backed synchronization. A guest session is easy to start, but its data depends on one browser. Each mode is coherent when its boundary is understood; each becomes surprising when the user assumes it offers the recovery or privacy properties of another mode.
There is a second boundary around integrations. An optional AI provider is not simply another screen in the app; it is a new recipient of selected information. A local read-only MCP client is not equivalent to a provider that can propose plan edits; transport, data scope, and write authority all matter. The fact that these capabilities are off or separate by default is part of openGym’s design argument. Users can adopt the core tracker without accepting an external model, and they can judge an integration by what it can actually read or change rather than by its label.
This is the core lens for openGym. Its value is not simply that the source code is available or that the data directory is visible. Its value lies in the attempt to make the important transitions explicit: from device to server, from plan to logged session, from history to derived view, and from local data to an optional provider. The following parts of this series examine those transitions in detail. The first step is to see exactly which components own state, which components transform it, and where the operator—not the project—must take responsibility.