Files
proof-of-work/AGENTS.md
T
Keysat 09eeef249d
CI / proof-of-work (Next.js app) (push) Has been cancelled
CI / start9/0.4 (StartOS package code) (push) Has been cancelled
Update Current state: trailer scrub done, record Gitea remote
The Co-Authored-By scrub (next-step #1) is complete — history was
rewritten and force-pushed, so the old SHAs are stale. Record the
configured origin remote and drop the resolved next-step.
2026-06-12 20:34:03 -05:00

8.0 KiB
Raw Blame History

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.

Stack (versions that matter)

  • Next.js 14 (App Router, server components + server actions, SSE streaming)
  • React 18, 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):

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)

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.

Canonical publish path for this project: ~/.proof-of-work/publish.sh (builds, uploads to FileBrowser, registers) — separate from the generic make publish. Unpublish: ~/.proof-of-work/unpublish.sh.

npm run db:seed (= tsx prisma/seed.ts) seeds the InstanceSettings singleton + curated library; it is live, not dead — invoked at Docker image-build time (start9/0.4/Dockerfile) to bake the library into the image, and also the local-dev first-run path (proof-of-work/README.md). Runtime first-boot/upgrade seeding is handled separately by docker_entrypoint.sh.

Conventions

  • Versioning is ExVer: 1.1.0:4 (note the colon). Every release = a new start9/0.4/startos/versions/vMAJOR.MINOR.PATCH.N.ts file, imported into versions/index.ts and promoted to current (previous current moves into other[]).
  • Bump the version BEFORE building the s9pk — Start9 0.4 won't recognize a rebuild as an update otherwise.
  • Schema changes are additive ALTERs in docker_entrypoint.sh, guarded by PRAGMA table_info checks. Keep schema.prisma in sync as the mirror, but the entrypoint is what migrates live /data. Never write a destructive migration.
  • Commit subject = vX.Y.Z:N — short summary, imperative, body explains the why.
  • Git remote is self-hosted (a private Start9 registry + a FileBrowser artifact host), NOT GitHub. The actual registry/file-host URLs are constants in ~/.proof-of-work/{publish,unpublish}.sh; FileBrowser creds live in ~/.keysat/filebrowser.env (outside the repo, gitignored). Default branch is master.
  • Tests live in proof-of-work/tests/; mock server-action deps with vi.hoisted() + vi.mock.
  • Before editing the AI subsystem (proof-of-work/lib/ai/** or the generate/generations routes), read docs/guides/ai-subsystem.md — provider abstraction, SSE/lenient-JSON, pricing/model menus, and the background-runner architecture live there.

Always

  • Run npx prisma generate after any schema.prisma edit, then npx tsc --noEmit.
  • Run npm test AND npm run build before shipping a version.
  • Add the boot-time ALTER TABLE (with an existence guard) for any new column, in docker_entrypoint.sh.
  • Treat API keys / secrets as plaintext in /data BY DESIGN (threat model: the operator owns /data). Reference env-var names (DATABASE_URL, etc.); never hardcode values.
  • Keep migrations idempotent and additive; data already on a user's server must survive upgrades.
  • Verify the published file actually changed (size / 404 / Last-Modified) after publish.sh.

Never

  • Never add Co-Authored-By / "Generated with" trailers to commits — the user authors commits solo. (This was done wrong in earlier commits; do not repeat.)
  • Never reintroduce nonce-based CSP — it broke first paint. Use the static 'unsafe-inline' CSP in next.config.js.
  • Never run app commands from the repo root — always cd proof-of-work first.
  • Never export non-HTTP-method symbols from a route.ts — Next.js rejects the build (helpers go in lib/, e.g. lib/ai/activateConfig.ts).
  • Never commit app.db, *.bak, or any user data — they're gitignored; double-check git status before git add.
  • Never click Uninstall on a StartOS package during a data cutover — it destroys the volume; use Stop.
  • Never assume GitHub — don't add a GitHub remote or push there.

Current state

Latest version is 1.1.0:7 (built locally, installed on the StartOS server). The registry is currently empty — all versions were unpublished; nothing is downloadable until publish.sh runs again.

Working: workout logging, programs (manual + AI), multi-user, curated library, full AI subsystem (5 providers, multi-config, background generation, history detail, cost/duration, Ollama auto-detect, infinite-scroll exercise history).

In progress: none — repo is at a clean checkpoint.

Decided but not implemented: tiered AI prompt formatting — JSON-Schema enforcement (Ollama format / OpenAI response_format), pipe-separated library, XML-tagged sections, Ollama-only few-shot. Targets local-model output quality; would ship as 1.1.0:8.

Git remote: origin → self-hosted Gitea at ssh://git@immense-voyage.local:59916/grant/proof-of-work.git; master is pushed and tracking. (The ~/.proof-of-work/{publish,unpublish}.sh registry/FileBrowser hosts are separate from this code remote.)

Known issues: publish.sh Step 3 (registry register) silently no-op'd on 1.1.0:6 and :7 — uploaded the file but didn't register; investigate before relying on those versions appearing in the registry. (The Co-Authored-By trailer scrub on 8f149d35b0535f is done — history was rewritten and force-pushed; those SHAs are now stale.)

Next steps:

  1. Re-publish current version once the Step-3 registry-register failure is diagnosed.
  2. Implement the tiered AI prompt formatting (1.1.0:8).