Phase: Phase 3.5 — Personal install + cross-platform parity · Status:
closed · Filed 2026-04-16What Worked
- Multi-stage build with model bake — 88MB MiniLM in runtime layer, zero remote fetch on first request
- name: prism-personal in compose — isolated namespace, dev compose unaffected
- Idempotent bootstrap — second boot is no-op, same Prism idiom as other services
- Conditional router mount for personal mode — don’t mount OAuth/invites, 404 is default
- Credentials extraction via docker exec — no path translation, works identically cross-platform
- Cross-platform script parity from same session as .ps1 audit
- Build cache discipline — second rebuild under 1s, only COPY . layer re-executed
What Didn’t
- CRED FILE OVERWRITE INCIDENT — first version wrote bootstrap key into credentials.json, clobbered dev OAuth key
- require() in an ESM file — ReferenceError at runtime, caught only at end-to-end test
- Git Bash MSYS path translation — docker exec paths translated, needed MSYS_NO_PATHCONV=1
- First compose run silently recreated dev container — same project name collision
- Dev API key bypass refused with ENVIRONMENT=personal — expected but momentarily confusing
- Reminder injection didn’t change behavior — noisy system-reminders ignored per instruction
Lessons
- [project] L12 — Always set explicit name: on a non-default compose file. Two compose files in same dir share default project name
- [project] L13 — Credential files are personal data. Path-clash = footgun. Give each mode a distinct filename
- [project] L14 — In ESM modules, never require(). Always top-level imports
- [project] L15 — Don’t ship a .sh you haven’t run
- [global] G7 — Pre-bake heavy ML model artifacts into container images. Eliminates first-request latency and runtime model registry dependency
- [global] G8 — Two-file credential split for multi-mode local tools. Each mode gets its own file

