- ui_switcher.py: add explicit guard that forces pref=streamlit when
DEMO_MODE=true, before the tier-downgrade check. Demo Vue SPA (#46)
is not yet implemented, so navigating there produced a blank screen.
- app.py: call sync_ui_cookie inside wizard gate block before st.stop()
so that cloud users with ui_preference=vue are redirected correctly
even when the first-run wizard is still active. Previous behaviour
called sync_ui_cookie after pg.run() which was never reached.
- demo/config/user.yaml: reset ui_preference to streamlit (belt-and-
suspenders alongside the code guard).
Closes: demo blank-screen regression reported 2026-03-24.
docs/reference/tier-system.md:
- Rewritten tier table: free tier now described as "AI unlocks with BYOK"
- New BYOK section explaining the policy and rationale
- Feature gate table gains BYOK-unlocks? column
- API reference updated: can_use, tier_label, has_configured_llm with examples
- "Adding a new feature gate" guide updated to cover BYOK_UNLOCKABLE
demo/config/user.yaml:
- Reformatted by YAML linter; added dismissed_banners for demo UX
Adds a fully neutered public demo for menagerie.circuitforge.tech/peregrine
that shows the Peregrine UI without exposing any personal data or real LLM inference.
scripts/llm_router.py:
- Block all inference when DEMO_MODE env var is set (1/true/yes)
- Raises RuntimeError with a user-friendly "public demo" message
app/app.py:
- IS_DEMO constant from DEMO_MODE env var
- Wizard gate bypassed in demo mode (demo/config/user.yaml pre-seeds a fake profile)
- Demo banner in sidebar: explains read-only status + links to circuitforge.tech
compose.menagerie.yml (new):
- Separate Docker Compose project (peregrine-demo) on host port 8504
- Mounts demo/config/ and demo/data/ — isolated from personal instance
- DEMO_MODE=true, no API keys, no /docs mount
- Project name: peregrine-demo (run alongside personal instance)
demo/config/user.yaml:
- Generic "Demo User" profile, wizard_complete=true, no real personal info
demo/config/llm.yaml:
- All backends disabled (belt-and-suspenders alongside DEMO_MODE block)
demo/data/.gitkeep:
- staging.db is auto-created on first run, gitignored via demo/data/*.db
.gitignore: add demo/data/*.db
Caddy routes menagerie.circuitforge.tech/peregrine* → 8504 (demo instance).
Personal Peregrine remains on 8502, unchanged.