Keysat 7a62690a4a v1.1.0:4 — multi-config AI, background generation, ollama auto-detect, system prompt overhaul
User-feedback-driven release after testing v1.1.0:3. Nine themes:

1. Multi-config persistence
   - New AIConfigProfile table (per-user). Save N configs, toggle one
     active. Switching providers no longer wipes the previous setup.
   - UserPreferences gains activeAIConfigId; legacy single-config
     columns are mirrored from the active profile so existing reads
     keep working without conditional logic.
   - Idempotent boot migration lifts any existing single-config row
     into a default profile.

2. Ollama auto-detect
   - The "Add config" form probes /api/tags on the StartOS internal
     addresses (ollama.startos / ollama.embassy on :11434). If
     reachable: URL pre-fills, model field becomes a dropdown of
     installed models. Fixes the copy-paste UX.

3. Curated model dropdowns for major providers
   - Claude: Opus 4.7, Sonnet 4.6 (1M ctx), Haiku 4.5
   - OpenAI: GPT-5.5, 5.4, 5.4-mini, 5.4-nano
   - Gemini: 3.1-pro-preview, 2.5-pro, 2.5-flash, etc.
   - "Other (type your own)" stays for niche models.
   - Fixes "I tried gemini-3.0-pro and got 404."

4. Background generation
   - lib/ai/generationRunner.ts: detached runner with in-memory
     pub/sub bus. POST /api/ai/generate kicks it off and returns
     immediately. SSE stream attaches by id. The runner survives
     request cancellation; navigating away no longer kills it.
   - New AIGeneration columns: progressText (in-flight stream),
     durationMs (final wall-clock).
   - Generate UI shows a banner explaining background-safety.
   - History detail page polls progress + renders partial JSON
     live for cross-process resume (page refresh, new tab).

5. System prompt overhaul
   - lib/ai/systemPromptBase.ts: structural contract prepended to
     every template. Forces JSON-only output, library-exerciseId
     usage (kills "exerciseId doesn't belong to this user" errors),
     and per-resistance-exercise suggestedWeight (with-history vs
     without-history variants).
   - aiExerciseSchema + ProgramExercise gain suggestedWeight +
     suggestedWeightUnit. Starting a workout from a ProgramDay
     pre-populates SetLog.weight from the suggestion.

6. Test connection improvements
   - Latency in seconds (was ms — confusing for slow Ollama).
   - Stale "✓ Connected" clears on form change.
   - Per-config Test (no need to activate first).
   - Generous maxOutputTokens for thinking models.
   - Gemini surfaces finishReason on empty response (e.g. "blocked
     by safety filter") instead of generic "empty response."
   - Test endpoint accepts a draft body so you can verify before
     saving + before activating.

7. History detail view
   - Click row → full program tree + exact prompts sent. Apply from
     here without re-generating. Pending rows poll for progress.

8. Sidebar sub-navigation
   - AI: Generate / History / Templates
   - Settings: General / Password / Sessions / AI integration /
     Export / Instance (admin) / Danger zone, with anchor scroll.

9. API key UX
   - "Key saved" indicator on saved configs (was confusing to see
     an empty input after a successful save).

Schema migrations (additive, idempotent in entrypoint):
  - AIConfigProfile table created
  - UserPreferences.activeAIConfigId
  - AIGeneration.progressText + durationMs
  - ProgramExercise.suggestedWeight + suggestedWeightUnit

Tests: 16 new (systemPromptBase, modelMenu, generationRunner). 177
total pass.
2026-05-11 08:09:01 -05:00

Proof of Work

Self-hosted multi-user workout planner and logger. Plan training cycles, log daily workouts, search your history, and curate a shared exercise library across everyone on the instance. Distributed as a StartOS 0.4 sideload package.

Repo layout

proof-of-work/    Next.js app (TypeScript, Prisma + SQLite, Tailwind, PWA)
start9/0.4/       StartOS 0.4 package wrapper (manifest, Dockerfile,
                  entrypoint, version graph, change-credentials action)

Everything else is generated at build time.

Local development

cd proof-of-work
npm install
npx prisma generate       # important after schema changes
npx prisma db push        # create the dev DB at prisma/data/app.db
npm run db:seed           # ONLY seeds the InstanceSettings singleton — no admin
npm run dev               # http://localhost:3000

For local dev you'll need to create an admin manually since the StartOS action isn't available — easiest is npx tsx a one-off script, or just open Prisma Studio (npm run db:studio) and add a User row with isAdmin: true + a bcrypt hash you generate with node -e 'require("bcrypt").hash("yourpassword", 10).then(console.log)'.

Multi-user

Fresh installs ship with no admin user on purpose — the operator must run the StartOS Action Set admin credentials (Services → Proof of Work → Actions) before anyone can log in. This eliminates the default-credentials footgun.

Once the admin exists, they can open sign-ups for additional users:

  • In-app: log in as admin -> Settings -> Instance Settings -> Allow new sign-ups.
  • StartOS: Services -> Proof of Work -> Actions -> Set new signups.

Both write to the same InstanceSettings row; either path works.

When sign-ups are open, anyone reaching the URL can create an account at /auth/signup. New users start with no admin privileges and are automatically seeded the full curated exercise library.

Building the StartOS package

See start9/0.4/DEPLOY_040.md for the full deployment / cutover guide. Short version:

cd start9/0.4
npm ci
make clean
make x86                  # produces proof-of-work_x86_64.s9pk
make install              # sideload to the host in ~/.startos/config.yaml

Curated exercise library

proof-of-work/prisma/exercises.seed.json is the canonical library shipped to every install. It seeds fresh installs (via prisma/seed.ts) and is re-applied on every boot to existing installs (via docker_entrypoint.sh + ensureExerciseLibrary.cjs) so updates flow to all users on package upgrade.

Refresh the JSON from the maintainer's live host:

./start9/0.4/refresh_seed.sh <ssh-target>     # pull a fresh /data snapshot
cd proof-of-work && npm run sync-library      # extract Exercise table -> JSON
git diff prisma/exercises.seed.json

The system is additive only — removing an exercise from the JSON does not delete it from existing installs (users may have logged sets against it). Users' own custom exercises (isCustom = true) are never touched.

Privacy

start9/0.4/seed/data/app.db is your live /data snapshot. It contains real workout history and a bcrypt'd password hash. The top-level .gitignore keeps it out of git; do NOT commit it to any public repo.

S
Description
No description provided
Readme 110 MiB
Languages
TypeScript 93.8%
Shell 2.6%
JavaScript 2.4%
Makefile 0.7%
Dockerfile 0.4%