{"slug": "show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm", "title": "Show HN: GymCoach – Self-hosted workout tracker where you bring your own LLM", "summary": "GymCoach, a new open-source, self-hosted workout tracker, allows users to log hypertrophy training sessions and receive AI-powered coaching using their own Anthropic or OpenRouter API key. The application, built with Next.js and PostgreSQL, provides features including progress tracking, program generation from natural language, and a streaming AI chat coach, all while keeping user data stored locally in their own database. Developed under an MIT license, GymCoach is designed for self-hosting via Docker and offers a public demo for evaluation.", "body_md": "Open source, self hosted hypertrophy training tracker with a built in AI coach. Log your sessions, track your progress, and get evidence based weekly debriefs and program suggestions from the LLM of your choice (Anthropic Claude or any OpenRouter model).\n\n[ ▶ Try the live demo](https://demo-gymcoach.mesureprivee.com)\n· login\n\n`demo@gymcoach.app`\n\n/ `gymcoachdemo`\n\nWhy GymCoach? It is the only workout tracker you self-host that brings your own LLM. Log your training, see your progress, and get a coach that actually knows your data: weekly debriefs, a streaming chat, and full programs generated from a sentence. Your data stays in your database; the AI runs on your Anthropic or OpenRouter key.\n\nStatus: actively developed. Multi-user, provider-agnostic (Anthropic or OpenRouter), with a unit / integration / E2E test suite and deep AI integration.\n\n- Multi-user accounts: sign up, profiles, per-user data isolation\n- Workout logging with sets, reps, RIR, warmups and drop sets\n- Progress charts and estimated 1RM tracking\n- Bodyweight-aware tonnage (pull-ups, dips, etc.)\n- AI coach: weekly debrief and assisted program adjustments\n- Conversational AI coach: streaming chat grounded in your training data\n- AI program generation from a natural-language goal, editable before saving\n- Pluggable LLM provider: Anthropic SDK or any OpenRouter model\n- Installable PWA with offline session logging\n\n- Frontend: Next.js 14 (App Router), TypeScript strict, Tailwind CSS, Shadcn UI\n- Backend: Next.js API routes, Prisma ORM, PostgreSQL 16\n- AI: pluggable LLM provider (Anthropic SDK or OpenRouter)\n- Infra: Docker and Docker Compose\n\nA few beliefs shaped GymCoach:\n\n- Your training data is yours. It lives in a Postgres database you control, not on someone else's servers. No ads, no tracking, no account you cannot delete.\n- AI should be optional and yours to pay for. The coach runs on your own Anthropic or OpenRouter key, so there is no subscription and no rate-limited \"free tier\". With no key set, the app is a clean, fast tracker.\n- Coaching should be grounded in your numbers, not generic advice. The AI only ever sees a structured summary of your own sessions, program and progress.\n- Evidence over hype. Load progression uses double-progression logic, and the coach is prompted to reason from your data (and cite the usual names: Schoenfeld, Helms, Israetel) rather than invent.\n- Self-hosting should be boring: one Docker Compose file, one database, standard Next.js.\n\nI built it for my own training and open-sourced it under MIT. There is nothing to buy: a [public demo](https://demo-gymcoach.mesureprivee.com) lets you look around, but GymCoach is meant to be self-hosted. Clone it, run it, change it.\n\nThe app:\n\n- Next.js 14 (App Router) serves both the UI and the API routes; data lives in PostgreSQL through Prisma. Auth is a signed JWT in an httpOnly cookie; every record is scoped to a user id and every route checks ownership.\n- The session logger is offline-first: each set is written to IndexedDB (Dexie) first for instant feedback, then synced to the server in the background, so a flaky gym connection never blocks you. A Wake Lock keeps the screen awake during a session.\n- Progress is computed server-side: estimated 1RM (Epley), max load over time, and weekly volume per muscle group, with bodyweight-aware tonnage for movements like pull-ups and dips.\n\nThe AI layer:\n\n- A single provider interface (\n`lib/llm`\n\n) sits in front of either the Anthropic SDK or any OpenRouter model. You pick one with the`LLM_PROVIDER`\n\nenv var; the rest of the app does not care which. - For every AI call the server builds a compact, structured payload (your profile + recent sessions + active program + per-exercise progression) instead of dumping raw rows, then:\n- Weekly debrief and program adjustments: one completion that returns markdown plus an optional structured block of suggested changes, validated with Zod before anything touches your program.\n- Chat coach: the same context plus your conversation, streamed back token by token.\n- Program generation: a plain-language goal becomes a JSON program, validated and previewed so you can edit it before it is saved.\n\n- The stable system prompt is marked for prompt caching, so multi-turn chats reuse it instead of re-sending it every turn.\n\nChat coach |\nWeekly debrief + 1-tap adjustments |\nProgram generation |\n\nThese clips use the built-in\n\n`demo`\n\nprovider (canned responses, no key). Point`LLM_PROVIDER`\n\nat your Anthropic or OpenRouter key for the real thing.\n\n- Node.js 20+\n- Docker and Docker Compose\n- npm\n\nRecommended setup: Postgres in Docker, Next.js running locally for hot reload.\n\n```\n# 1. Environment variables\ncp .env.example .env\n# Edit .env (the example ships with working dev defaults)\n\n# 2. Install dependencies\nnpm install\n\n# 3. Start Postgres\ndocker compose up -d db\n\n# 4. Apply Prisma migrations\nnpm run db:migrate\n\n# 5. Seed demo data (account + exercise catalog + program + sample session)\nnpm run db:seed\n\n# 6. Start the dev server\nnpm run dev\n```\n\nThe app runs on [http://localhost:3030](http://localhost:3030). Postgres is exposed on `localhost:5433`\n\non the host.\n\nThe demo account credentials come from `.env`\n\n(`USER_EMAIL`\n\nand `USER_PASSWORD`\n\n); the seed hashes the password at runtime.\n\nAll configuration is done through environment variables. See `.env.example`\n\nfor the full list (database, JWT secret, demo account, and the AI provider keys).\n\nThree tiers: unit/component (Vitest + jsdom), integration (Vitest against a real Postgres), and end to end (Playwright driving the built app).\n\n```\nnpm run test            # unit and component tests\nnpm run test:coverage   # with coverage report\n\n# Integration + E2E use a dedicated Postgres (docker-compose.test.yml, port 5434):\ndocker compose -f docker-compose.test.yml up -d\nDATABASE_URL=postgresql://gymcoach_test:gymcoach_test@localhost:5434/gymcoach_test \\\n  npx prisma migrate deploy\nnpm run test:integration\nnpm run build && npm run test:e2e\ndocker compose -f docker-compose.test.yml down\n```\n\nCI (`.github/workflows/ci.yml`\n\n) runs lint, typecheck, unit, integration,\nbuild and E2E on every push and pull request.\n\n| Script | Description |\n|---|---|\n`npm run dev` |\nNext.js dev server (port 3030) |\n`npm run build` |\nProduction build |\n`npm run start` |\nRun the production build |\n`npm run lint` |\nESLint |\n`npm run typecheck` |\nTypeScript type checking |\n`npm run test` |\nUnit and component tests |\n`npm run test:e2e` |\nEnd to end tests |\n`npm run format` |\nPrettier |\n`npm run db:migrate` |\nApply migrations (dev) |\n`npm run db:reset` |\nReset the database (drop + migrate + seed) |\n`npm run db:seed` |\nLoad the demo dataset |\n`npm run db:studio` |\nOpen Prisma Studio |\n`npm run db:generate` |\nRegenerate the Prisma client |\n\n```\n.\n├── app/              # Pages and API routes (App Router)\n├── components/       # React components (Shadcn UI in components/ui)\n├── lib/              # Helpers (db, auth, stats, llm, etc.)\n├── prisma/           # Schema, migrations and seed\n├── public/           # Static assets (PWA icons, manifest)\n├── tests/            # Integration (Vitest) and E2E (Playwright) tests\n├── docs/             # Project documentation\n└── docker-compose*.yml\n```\n\nA production stack is provided through `docker-compose.prod.yml`\n\n(app + Postgres). Put it behind a reverse proxy (Nginx, Caddy, Traefik) for HTTPS.\n\n```\ncp .env.example .env\n# Fill in real values (JWT_SECRET, the AI provider key, NEXTAUTH_URL, ...)\ndocker compose -f docker-compose.prod.yml up -d --build\ndocker compose -f docker-compose.prod.yml exec app npx prisma migrate deploy\n```\n\n- Single user MVP (logging, progress, weekly AI debrief, program adjustments)\n- Pluggable LLM provider (Anthropic SDK or OpenRouter, switchable via env)\n- Multi user support (registration, profiles, data isolation)\n- AI program generation from a natural language goal\n- Conversational AI coach (streaming chat with your training context)\n- Test pyramid (unit, integration, E2E) and CI\n- In-session AI suggestions and natural-language set logging\n\nContributions are welcome. See [CONTRIBUTING.md](/Julien-Au/gymcoach/blob/main/CONTRIBUTING.md) for setup,\nconventions and the test commands.\n\nMIT, see [LICENSE](/Julien-Au/gymcoach/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm", "canonical_source": "https://github.com/Julien-Au/gymcoach", "published_at": "2026-06-03 07:26:41+00:00", "updated_at": "2026-06-03 07:46:19.127388+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "large-language-models", "artificial-intelligence", "ai-startups"], "entities": ["GymCoach", "Anthropic", "OpenRouter", "Next.js", "Tailwind CSS", "Shadcn UI", "Claude", "TypeScript"], "alternates": {"html": "https://wpnews.pro/news/show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm", "markdown": "https://wpnews.pro/news/show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm.md", "text": "https://wpnews.pro/news/show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm.txt", "jsonld": "https://wpnews.pro/news/show-hn-gymcoach-self-hosted-workout-tracker-where-you-bring-your-own-llm.jsonld"}}