diff --git a/.planning/phases/20-demo-instance-with-every-shared-plugin/20-CONTEXT.md b/.planning/phases/20-demo-instance-with-every-shared-plugin/20-CONTEXT.md
new file mode 100644
index 00000000..0a079cbb
--- /dev/null
+++ b/.planning/phases/20-demo-instance-with-every-shared-plugin/20-CONTEXT.md
@@ -0,0 +1,140 @@
+# Phase 20: Demo instance with every shared plugin - Context
+
+**Gathered:** 2026-10-28
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Phase 19.4.1 put `sm-demo-app` live on demo.summercms.io with the plugins of that time. This phase adds the chat family to that live instance and shows it working on the public Nuxt site: `chat`, `chatchannels`, `chatvideo`, `chatbots`, `forum`, `herald` and `userfriends` are mounted at tagged versions, seeded by `demo:seed`, deployed on rome, and given site UI through new shared Nuxt layers. Everything decided in 19.4.1 still holds (hosting on rome, own Centrifugo, `/backend` refused by nginx with the contact call to action, open registration behind Turnstile, the reset job, the demo banner, EN/PL, the summercms.io look). This phase does not repeat it.
+
+New shared repos created by this phase: `vue-chat-layer`, `vue-chatvideo-layer`, `vue-forum-layer`, `vue-userfriends-layer`, `sm-moderation-plugin`.
+
+
+
+
+## Implementation Decisions
+
+### Chat frontend
+- **D-01:** The chat UI is ported from `sm-bm-app`'s Vite SPA (`frontend/src/components/chat/`, `stores/chat.ts`, `api/chat.ts`, `lib/chat*.ts`, about 4.6k lines) into a new shared Nuxt layer, **`vue-chat-layer`**, consumed by `vue-demo-app` like the journal, menu, FAQ and paymentgateway layers. The layer is Golem15 code with no bm (JZ) specifics: BM link embeds, Terminarz deadline pins and other bm-only pieces are stripped or turned into slots or extension points. The layer names no application. — **Reversibility:** costly. A public layer with tagged releases; later sites pin it by tag.
+- **D-02:** The full bm feature set: channels, DMs, threads, mentions, reactions, typing, unread counts, attachments, member picker, delete dialog, embeds (generic link embeds only).
+- **D-03:** Chat appears as a full `/chat` page (channel sidebar, message pane) **and** a floating panel (DM list and unread badge) on every page for logged-in users. The homepage tour (19.4.1 D-11) gets a "Chat" card.
+- **D-04:** Anonymous visitors on `/chat` see a description and a "register to chat" prompt, the same pattern as quizzes (19.4.1 D-18). There is no read-only preview, and the floating panel is hidden for them.
+- **D-05:** Chatbots has no UI of its own. Its slash commands appear as a command picker in the `vue-chat-layer` composer. There is no `vue-chatbots-layer`.
+
+### Chat context and access
+- **D-06:** One demo community: a single chat context (in the spirit of bm's `bm/1`, `plugins/jz/bm/classes/chat_context.go`, e.g. `demo/1`) implemented in `golem15.demo` as the host `contracts.Context` and the chatchannels `ChannelAccessResolver`. Every registered user is a member automatically.
+- **D-07:** Channels are **seeded only** (for example #general, #announcements, a Polish channel). Users join seeded channels and cannot create channels of any kind.
+- **D-08:** Any community member can DM any other member, as in bm. userfriends does not gate DMs.
+- **D-09:** `demo:seed` creates a handful of persona users with message history, threads, reactions and pins in EN and PL channels. The reset job (19.4.1 D-09) wipes and reseeds them along with everything else. There is no live bot persona.
+
+### Video calls
+- **D-10:** LiveKit is self-hosted on rome under supervisor, next to the demo's Centrifugo (19.4.1 D-17), with its own keys in `.env`. The media ports (UDP range, TCP fallback, TURN/TLS through nginx stream or LiveKit's embedded TURN) are opened on rome and documented in `sm-demo-app/DEPLOY.md`. — **Reversibility:** reversible. Moving to LiveKit Cloud later only changes `golem15.chatvideo.livekit_*` config.
+- **D-11:** Calls start from DMs only. chat has DMs plus one context-wide group conversation (`GetGroupChat`) and no ad-hoc group DMs, and with D-07 there are no private channels, so in practice that means 1:1 calls. The researcher confirms this against the plugin. Calls are never started in seeded public channels.
+- **D-12:** Caps for a public demo: `max_duration` about 15 minutes, about 4 participants per room, the plugin's existing rate limits, and the `chatvideo:reconcile-sessions` job ending idle rooms.
+- **D-13:** The video UI is a **minimal call page** (own camera, remote tiles, mute, camera toggle, leave) built on `livekit-client` and released as the first version of a new shared **`vue-chatvideo-layer`**. bm has no video UI to port.
+
+### Forum, friends, push
+- **D-14:** **`vue-forum-layer`** is a new shared layer with a `/forum` page: categories, threads and Markdown posts, seeded in EN and PL by `demo:seed`.
+- **D-15:** **`vue-userfriends-layer`** is a new shared layer: friends list, requests and friend groups. It is linked from the chat sidebar and the profile.
+- **D-16:** herald (Web Push) is mounted and configured (VAPID keys in `.env`) but has **no subscribe UI** in this phase.
+
+### Moderation
+- **D-17:** A new shared plugin, **`sm-moderation-plugin`**, filters banned words and links in chat messages and forum posts. The banned-word and link lists are editable in its admin settings. On top of it: the plugins' rate limits, Turnstile on register (19.4.1 D-07), admins deleting messages and banning users from the backend, and the reset job.
+- **D-18:** chat and forum fire their festival events after the save (`events.MessageCreated` etc.), so the filter needs a **new, generic, additive pre-save seam** in `sm-chat-plugin` and `sm-forum-plugin`: a host- or plugin-registered validator that can reject a message or post before it is persisted. The change is additive and ships as patch tags. It must not change the existing PHP-parity API or payloads (these plugins are WavePath's port target, Phase 31), and the seam names no application. — **Reversibility:** costly. A public plugin contract other consumers can start using.
+
+### Plan shape (suggestion; confirmed at plan time per the lean-planning rule)
+- **D-19:** Backend first, then layers. The suggested split from the discussion, before the forum and userfriends layers and the moderation plugin were added: 01 mount and tag the chat family, demo context, seed, LiveKit and the rome deploy (with the folded todo); 02 the `vue-chat-layer` port; 03 `vue-chatvideo-layer` plus herald config; 04 forum and friends layers, slash-command picker, tour cards; 05 unit tests and live verification. The planner fits in `sm-moderation-plugin`, the pre-save seams and the two extra layers, and presents the final count for confirmation.
+
+### Claude's Discretion
+- Seeded channel names and persona users, and how much EN/PL history to seed.
+- How LiveKit's media and TURN ports are exposed on rome (embedded TURN vs nginx stream), as long as calls work from typical NAT'd browsers.
+- The exact shape of the pre-save validator seam in chat and forum (interface name, registration through `pact` or the service registry), within D-18's constraints.
+- Which chatbots commands are registered for the demo (`/help`, `/demo`, …) and what they answer.
+- How `vue-chat-layer` exposes extension points for app-specific embeds.
+
+### Folded Todos
+- **Commit sm-demo-app's leftover journal and oauthserver submodule moves** (`.planning/todos/pending/2026-10-26-sm-demo-app-journal-oauthserver-pointers.md`, g15office `ssuyq2os`): sm-demo-app still shows `M plugins/golem15/oauthserver`. This phase bumps submodule pointers and go.mod requires anyway, so the first plan moves each checkout to the tag go.mod requires and makes one `chore: bump to ` commit per plugin before mounting the chat family. `TestGoModRequiresTags` and `scripts/check-pins.sh` must pass.
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Prior demo decisions
+- `.planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/19.4.1-CONTEXT.md` — hosting, accounts, reset job, banner, tour, EN/PL, look, Centrifugo, tagged-module go.mod (D-01..D-23)
+- `../sm-demo-app/DEPLOY.md` — rome layout, ports in use, supervisor programs, Centrifugo, release and rollback
+- `../sm-demo-app/README.md` — local run, `demo:seed`, credentials handling
+- `../sm-demo-app/summer.yaml`, `../sm-demo-app/go.mod` — the current plugin set and tagged requires
+
+### Chat UI source (port)
+- `../sm-bm-app/frontend/src/components/chat/` — ChatPanel, MessageList, ChatMessage, ChatComposer, ChatHeader, DmList, MemberPicker, MentionPopup, ReactionBar, EmbedCard, EmbedPicker, StagingChips, DeleteDialog, Avatar
+- `../sm-bm-app/frontend/src/stores/chat.ts`, `../sm-bm-app/frontend/src/api/chat.ts`, `../sm-bm-app/frontend/src/lib/chat{Events,Format,Text,Unread}.ts` (with their tests)
+- `../sm-bm-app/plugins/jz/bm/classes/chat_context.go`, `../sm-bm-app/plugins/jz/bm/chat.go` — host context and access wiring to mirror in `golem15.demo`
+- `.planning/phases/19.4.1-early-public-demo-on-demo-summercms-io/` plans for the presentations port (precedent for porting a bm Vite view into Nuxt)
+
+### Plugins
+- `../sm-chat-plugin/README.md` — Context contract, Service, events, generic API, channel authorizer
+- `../sm-chatchannels-plugin/README.md` — channels, access resolver
+- `../sm-chatvideo-plugin/README.md` — LiveKit config keys, API, reconcile job, limits
+- `../sm-chatbots-plugin/README.md` — command catalog, dispatch, bot-auth seam
+- `../sm-forum-plugin/README.md`, `../sm-herald-plugin/README.md`, `../sm-userfriends-plugin/README.md`
+- `.planning/phases/19-chat-and-chatchannels/19-CONTEXT.md` — chat port contract (PHP parity, D-07 generic API mirrors WavePath, which must not drift)
+- `.planning/phases/19.1-chat-satellites/19.1-CONTEXT.md` — satellites decisions
+- `.planning/notes/core-plugins-own-repos.md` — new shared plugin and layer repos, submodule mounting, commit order
+
+### Existing layers (pattern)
+- `../vue-journal-layer`, `../vue-faq-layer`, `../vue-menu-layer`, `../vue-paymentgateway-layer`, `../vue-oauth-layer` — layer structure, tags, how `vue-demo-app` consumes them
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- bm chat SPA (about 4.6k lines with tests): the store, the API client and the event handling port almost directly; components need Nuxt/SSR guards (client-only realtime).
+- The demo's Centrifugo and `lighthouse` wiring from 19.4.1 plan 04 (speaker/remote sync) carries chat realtime too; chat authorizes `chat:conversation:{id}` and chatvideo `video:session:{id}`.
+- `golem15.demo` plugin and `demo:seed`, with the EN/PL seeding through translate (19.4.1 D-13).
+- The `realtime_test.go`, `seed_test.go`, `reset_test.go` and `go_mod_test.go` patterns in sm-demo-app for the new plugins.
+
+### Established Patterns
+- Shared plugin and layer repos are their own git.golem15.com repos, mounted as submodules. Plugins are pushed and tagged first, then the pointer bump in the app goes in a separate commit.
+- `go.mod` requires tagged versions (19.4.1 D-03); `scripts/check-pins.sh` and `TestGoModRequiresTags` enforce checkouts at the tag.
+- chat/chatchannels APIs and events are PHP-parity contracts for WavePath (Phase 19 D-07, Phase 31). Changes are additive only.
+
+### Integration Points
+- `golem15.demo`: chat `contracts.Context`, chatchannels `ChannelAccessResolver`, seed, moderation word lists, chatbots command registrations.
+- `vue-demo-app/nuxt.config.ts` `extends`: four new layers.
+- rome: new supervisor program for LiveKit, firewall and nginx changes, `.env` keys (LiveKit, VAPID).
+
+
+
+
+## Specific Ideas
+
+- "There is a simple chat view in sm-bm-app": port it rather than build chat UI from scratch.
+- The video UI starts small but as a reusable layer ("make it as initial vue-chatvideo-layer"), so later sites and the WavePath work can grow it.
+- The user prefers reusable shared pieces over demo-only code: a layer for each satellite with UI, and a shared moderation plugin rather than a filter inside `golem15.demo`.
+
+
+
+
+## Deferred Ideas
+
+- Web Push subscribe UI (opt-in notifications for DMs and mentions, sharing the PWA service worker): herald is mounted without UI here.
+- User-created channels (public or private) and ad-hoc group DMs with group calls.
+- A live bot persona answering in channels.
+- A read-only `/chat` preview for anonymous visitors.
+
+### Reviewed Todos (not folded)
+- "Prompt open admin and site tabs to reload when a new version is deployed": its site half was folded into 19.4.1 (D-22); the admin half is framework work, not this phase.
+- "Translate Messages as a Nuxt i18n JSON editor", "Port the menu plugin as sm-menu-plugin…", and the user/mfa/cabana/build todos that matched on keywords only: they are unrelated to the chat family on the demo.
+
+
+
+---
+
+*Phase: 20-demo-instance-with-every-shared-plugin*
+*Context gathered: 2026-10-28*
diff --git a/.planning/phases/20-demo-instance-with-every-shared-plugin/20-DISCUSSION-LOG.md b/.planning/phases/20-demo-instance-with-every-shared-plugin/20-DISCUSSION-LOG.md
new file mode 100644
index 00000000..22209eed
--- /dev/null
+++ b/.planning/phases/20-demo-instance-with-every-shared-plugin/20-DISCUSSION-LOG.md
@@ -0,0 +1,137 @@
+# Phase 20: Demo instance with every shared plugin - Discussion Log
+
+> **Audit trail only.** Do not use as input to planning, research, or execution agents.
+> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
+
+**Date:** 2026-10-28
+**Phase:** 20-demo-instance-with-every-shared-plugin
+**Areas discussed:** Chat frontend source, Chat context & access, Video calls hosting, Abuse & satellites scope
+
+The user corrected the opening premise: "There is simple chat view in sm-bm-app". bm's Vite SPA chat (about 4.6k lines) became the port source.
+
+Folded todo: "Commit sm-demo-app's leftover journal and oauthserver submodule moves" (Fold it in).
+
+---
+
+## Chat frontend source
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| New vue-chat-layer | Shared Nuxt layer; bm-specific bits stripped or slots | ✓ |
+| Demo-only pages | Port into vue-demo-app as 19.4.1 did for presentations | |
+| Layer, but later | Demo-only now, extraction as backlog todo | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Full bm feature set | Channels, DMs, threads, mentions, reactions, typing, unread, attachments | ✓ |
+| Core only | Channels and DMs with realtime, unread, typing | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Dedicated /chat page | Full-page chat plus tour card | |
+| Page + floating panel | /chat plus floating DM/unread widget | ✓ |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Read-only #general preview | Live read-only seeded channel | |
+| Login prompt only | As quizzes D-18 | ✓ |
+
+---
+
+## Chat context & access
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| One demo community | Single context like bm/1 | ✓ |
+| Per-user workspaces | Users create contexts | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Seeded public + user private | Users create private channels | |
+| Anyone, any channel | | |
+| Seeded only | Join seeded channels, DM each other | ✓ |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Seeded users + history, EN/PL | Persona users with history | ✓ |
+| Plus a live bot | Bot answers slash commands | |
+| Empty channels | | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Any member of the community | userfriends does not gate DMs | ✓ |
+| Friends only | | |
+
+---
+
+## Video calls hosting
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Self-host on rome | LiveKit under supervisor, own keys | ✓ |
+| LiveKit Cloud free tier | | |
+| Decide in research | | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| DMs and private groups | No calls in public channels | ✓ |
+| Any conversation | | |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| LiveKit components in the chat layer | Call view on livekit-client | |
+| Minimal call page | Bare-bones join page | ✓ (as the initial vue-chatvideo-layer) |
+
+**Notes:** "make it as initial vue-chatvideo-layer". Since channels are seeded only and chat has no ad-hoc group DMs, calls are effectively 1:1 DMs.
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Short calls, few people | ~15 min, ~4 participants | ✓ |
+| Plugin defaults | | |
+
+---
+
+## Abuse & satellites scope
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Rate limits + report + reset | No content filter | |
+| Plus a word filter | Banned words/link filter | ✓ |
+| Posting needs approval | | |
+
+Follow-up, filter home: Hook in plugins + list in demo / Demo plugin only / **New shared plugin** ✓
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Forum page + friends in chat + /commands | Built in demo or chat layer | |
+| A layer for each | vue-forum-layer, vue-userfriends-layer | ✓ |
+| Forum only | | |
+
+Follow-up, which layers: **forum + userfriends; commands in chat layer** ✓ / Also a vue-chatbots-layer
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Push for DMs and mentions | Opt-in notifications | |
+| Mounted, no UI | | ✓ |
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Backend first, then layers | 5-plan split | ✓ |
+| You decide at plan time | | |
+
+---
+
+## Claude's Discretion
+
+- Seeded channel names, personas, history volume
+- LiveKit port/TURN exposure on rome
+- Shape of the pre-save validator seam in chat and forum
+- Demo chatbots commands
+- vue-chat-layer extension points for embeds
+
+## Deferred Ideas
+
+- Web Push subscribe UI
+- User-created channels and ad-hoc group DMs/group calls
+- Live bot persona
+- Anonymous read-only chat preview