# AGENTS.md — Proof of Work Self-hosted multi-user workout logger (Next.js app) packaged as a StartOS 0.4 `s9pk`, published to a private Start9 registry. > **Inbox check:** At session start, if `~/Projects/standards/INBOX.md` exists, scan it for > items tagged `(proof-of-work)` and surface them before proposing next steps; triage with `/triage`. ## Stack (versions that matter) - **Next.js 15** (App Router, server components + server actions, SSE streaming) — dynamic request APIs are async (see Conventions) - **React 19**, **TypeScript 5**, **TailwindCSS 3** - **Prisma 5** ORM over **SQLite** (WAL mode; tuned at boot) - **bcrypt** (native — NOT bcryptjs), **zod 3** for validation - **Vitest 4** for tests - **@start9labs/start-sdk** for the 0.4 packaging layer - Node **>= 20** to build ## Layout (two projects in one repo) ``` proof-of-work/ ← the Next.js app (THIS is where you run npm) app/ ← App Router routes; app/api/** = route handlers app/main/ ← authed UI; navigation.tsx = sidebar components/ ← React components (workouts/, ai/, settings/) lib/ai/ ← AI subsystem (see below) lib/ai/providers/ ← claude.ts openai.ts gemini.ts ollama.ts + index.ts (getProvider; openai.ts exports both openai + openai-compatible = 5 registered providers) prisma/schema.prisma ← schema (mirror; real DB migrates via entrypoint ALTERs) prisma/*.seed.json ← curated exercise library + AI templates (reconciled each boot) tests/ ← Vitest specs (ai-*.test.ts, routes-*.test.ts, ...) start9/0.4/ ← StartOS packaging wrapper docker_entrypoint.sh ← boot: first-boot seed, additive ALTERs, library reconcile Makefile / s9pk.mk ← s9pk build (ARCHES := x86) startos/versions/ ← one file per ExVer version + index.ts (the version graph) ~/.proof-of-work/ ← publish.sh + unpublish.sh (NOT in repo; self-hosted registry) ``` `workout-planner/` is scratch (only `logs/`) — ignore. `start9/0.4/*.s9pk` are build artifacts. ## Commands Run app commands **from `proof-of-work/`** (running tsc/vitest/next from repo root fails — wrong cwd): ```bash cd proof-of-work npm run dev # local dev server npm run build # next build (run this to catch route/type errors before shipping) npm run lint # next lint npm test # vitest run (full suite) npx vitest run tests/ai-pricing.test.ts # single file npx vitest run -t "findPrice" # single test by name npx tsc --noEmit # typecheck only npx prisma generate # REQUIRED after editing schema.prisma (else TS can't see new fields) npm run db:seed # seed InstanceSettings singleton (NO users/library — see below) npm run create-admin -- you@example.com pw "Name" # create first admin locally (--force resets existing) ``` Build/sideload the s9pk (from `start9/0.4/`): `make x86` then `make install`. Targets come from `s9pk.mk` (the wrapper `Makefile` just sets `ARCHES := x86`): - `make x86` — build the x86 s9pk. - `make install` — sideload the newest local `.s9pk` to the StartOS box at `host:` in `~/.startos/config.yaml` (via `start-cli package install`). - `make publish` — upload every `.s9pk` to the S3 bucket (`s9pk-s3base:`) and index it on `registry:` from `~/.startos/config.yaml` (via `s3cmd` + `start-cli s9pk publish`). **Distinct from `~/.proof-of-work/publish.sh`** below. - `make clean` — remove build artifacts. Both `install` and `publish` read host/registry config from `~/.startos/config.yaml`, which is **not in the repo** — verify against the live setup, not from a checkout. **Verify on-box state read-only via `start-cli`** (the same host config) instead of punting to the StartOS web UI — used this way to confirm the 1.2.0:4/:5 ALTERs and a persisted set: - `start-cli package installed-version proof-of-work` — what version the box actually runs. - `start-cli package logs proof-of-work --limit N | grep -iE "adding missing column|as nextjs|error"` — confirms boot ALTERs ran (each logs once) and the non-root launch. - `start-cli package attach proof-of-work -- sqlite3 /data/app.db "