This repo is a chat-first personal trainer app for the Pinata Agents hosting platform.
It gives you:
- a valid
manifest.jsonwith one public hosted route - a Next.js app mounted at
/app - a SQLite-backed trainer dashboard data model using App Router routes
- a workspace-served avatar asset exposed through the API
- a PM2-managed runtime so the hosted app can restart without turning the agent into its own watchdog
- a
workspace/folder with the coaching identity and behavior docs
The product split is intentional:
- the main
/chatsession is the primary interaction surface for onboarding, daily updates, and plan changes /appis a read-only dashboard for progress, current plan, and recent coaching context
manifest.jsondefines the Pinata agent metadata, lifecycle scripts, and/approuteapp/contains the App Router UI plusapp/api/*route handlerslib/trainer.jsmanages the trainer SQLite file atworkspace/data/trainer.dbserver.jsruns a tiny custom Next server and exposes a health endpointecosystem.config.cjstells PM2 how to run the appworkspace/holds the editable coaching identity and behavior docs
GET /app/api/dashboardGET /app/api/avatarGET /app/api/statusPOST /app/api/responsesPOST /app/api/auth/loginPOST /app/api/auth/logoutPOST /app/api/admin/rebuildGET /app/api/admin/rebuild/statusGET /app/api/admin/rebuild/log
profileplan_blocksdaily_snapshotsweekly_summariesactivity_entriesnutrition_trendscoach_notesreminder_preferences
The database seeds a starter state on first run so the dashboard renders immediately.
The dashboard now uses simple password auth backed by an environment variable.
APP_PASSWORD: optional, defaults tochangeme- unauthenticated requests to
/apprender the inline login form - unauthenticated requests to protected API routes return
401
Protected routes:
GET /appGET /app/api/dashboardGET /app/api/statusPOST /app/api/responsesPOST /app/api/admin/rebuildGET /app/api/admin/rebuild/status
This is intentionally lightweight starter auth, not a full user system. Change the default password in any real deployment.
For manual admin calls, protected API routes also accept the direct header:
x-app-password: <APP_PASSWORD>
This is useful for rebuild and status checks when cookie-based auth is unreliable through the hosted proxy.
Pinata does not automatically rebuild the Next app just because files changed in the workspace. PM2 will restart processes, but it will not regenerate the Next production build for you.
The app now includes an authenticated rebuild hook:
POST /app/api/admin/rebuildGET /app/api/admin/rebuild/statusGET /app/api/admin/rebuild/log
What it does:
- runs
npm run build - then runs
pm2 reload ecosystem.config.cjs --update-env - writes status to
workspace/data/rebuild-status.json - writes logs to
workspace/data/rebuild.log
This is better than a cron for normal app edits because rebuilds happen on demand rather than on a fixed schedule. If you still want automation, a Pinata Task can call this route or prompt the agent to trigger it after code changes.
Rebuild debugging:
- rebuild status writes are now atomic to avoid partial JSON reads
GET /app/api/admin/rebuild/logreturns the current rebuild log
Startup behavior:
npm startnow runs a freshnext buildbefore launching PM2/app/healthincludes the current NextBUILD_ID
This makes it easier to confirm whether the hosted app actually booted from a fresh production build.
- replace seeded rows with agent-written records from chat
- add write routes for onboarding updates, daily check-ins, workout logs, and plan refreshes
- write reminder preferences from onboarding and later chat updates into
reminder_preferences - remove or replace the starter avatar asset if you want a trainer-specific brand
- add reminder preferences and message delivery later if you connect Telegram, Discord, email, or SMS
The app includes a server-side proxy at POST /app/api/responses that forwards requests to the protected OpenClaw gateway.
Expected environment variables:
APP_PASSWORD: dashboard password, defaults tochangemeOPENCLAW_GATEWAY_TOKEN: required bearer token for the gatewayOPENCLAW_GATEWAY_URL: optional override, defaults tohttp://127.0.0.1:18789
Example request:
curl -X POST http://localhost:3011/app/api/responses \
-H "Content-Type: application/json" \
-d '{"model":"openclaw","input":"Start a new onboarding session for a personal trainer app."}'The route forwards the JSON body to ${OPENCLAW_GATEWAY_URL}/v1/responses and returns the upstream status and body. Keep the token in environment or Pinata secrets, not in source.
Config checks:
GET /app/api/statusGET /app/health
Both return whether the gateway token is configured, without exposing the token value.
npm install
npm run build
npm startOpen http://localhost:3000/app.
If you do not set APP_PASSWORD, the login password is changeme.
If you need a different local port:
APP_PASSWORD=changeme PORT=3011 npm run build && APP_PASSWORD=changeme PORT=3011 npm startFor local daemon mode:
PORT=3011 npm run start:daemonThe manifest is configured so Pinata can:
- install dependencies and run
next build - run
npm starton agent boot throughpm2-runtime - expose port
3000at/app
If you replace the tutorial with another frontend or API shape, keep the server bound to 0.0.0.0 and make sure it can serve behind the /app path prefix.