Skip to main content
Phase: Phase 3.5 — Personal install + cross-platform parity · Status: closed · Filed 2026-04-16

What 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
Last modified on April 20, 2026