diff --git a/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-CONTEXT.md b/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-CONTEXT.md
new file mode 100644
index 0000000..575d098
--- /dev/null
+++ b/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-CONTEXT.md
@@ -0,0 +1,148 @@
+# Phase 16.2: Plugin-provided field types and the Blog Editor formwidget - Context
+
+**Gathered:** 2026-10-09
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Two deliverables, framework first:
+
+1. **Plugin-registered, value-bearing cabana field types** (summercms.go: `modules/pact`, `modules/cabana`, admin SPA). A plugin registers its own form field type, the WinterCMS `registerFormWidgets()` successor. Unlike the Phase 10.1 `type: widget`, which is valueless and uses action/fill, the field owns a column value.
+2. **The Journal Blog Editor** (sm-journal-plugin). It is built on that API: a WYSIWYG HTML editor with a source toggle for post `content`. It edits the imported HTML posts (61 of 63 published grzybyfunkcjonalne.pl posts) without losing anything, and it also replaces the textarea for category content.
+
+The phase also includes the frontend half of embeds. The reusable Nuxt blog views layer (`vue-journal-layer`) expands the editor's embed placeholders.
+
+Out of scope: a core cabana `richeditor` type, a media library browser, and HTML input on the public write API (see Deferred).
+
+
+
+## Implementation Decisions
+
+### Blog Editor: what it is
+- **D-01:** The Blog Editor is a **WYSIWYG HTML editor with a source (raw HTML) toggle**, built on ProseMirror through TipTap. It is not a block editor and not a markdown editor.
+- **D-02:** **An admin save stores HTML in both columns.** `content` holds the edited HTML and `content_html` holds the same HTML after it passes `classes.CheckHTML`. The API response shape is unchanged; `content` is simply HTML, as the PHP export already carries for imported posts. — **Reversibility:** costly — every post saved from the admin becomes HTML-content. A later move back to markdown would need an HTML-to-markdown migration across live posts.
+- **D-03:** **Byte-preserving unless edited.** If the post body is not touched in the editor, the save writes back exactly the stored HTML; the editor must not re-serialize an untouched document. Once the body is edited in WYSIWYG, markup the schema doesn't know (custom classes, divs, attributes) is kept as far as possible through generic node and attribute preservation. The source tab always edits the exact HTML.
+- **D-04:** v1 features: basic text (headings, bold/italic, lists, links, blockquote), **images**, **tables**, and **embeds plus a raw HTML block**. The raw HTML block is still subject to `CheckHTML`.
+- **D-05:** **Embeds are an allowlisted placeholder node**, for example ``, that passes `CheckHTML` unchanged. **The XSS gate is not relaxed to allow iframes.** The frontend expands the placeholder into the real iframe (D-17). — **Reversibility:** costly — the placeholder markup becomes stored content in live posts, and the layer's renderer depends on it.
+- **D-06:** The editor is **translatable like today's `mlmarkdown`**: a locale switcher over a locale → HTML map, stored through the translate overlay.
+
+### Markdown vs HTML posts
+- **D-07:** **A markdown post opens with its `content_html`**, and the next admin save stores HTML (D-02). This is a one-way migration on first edit, with **no per-post format flag** and no new column.
+- **D-08:** **The Blog Editor replaces `mlmarkdown` for Journal post `content`** in `models/post/fields.yaml`. `markdown` and `mlmarkdown` stay cabana core types for other plugins. The `excerpt` field is unchanged.
+- **D-09:** **The public write API is unchanged.** `POST`/`PUT /_journal/api/v1/posts` keep the PHP contract: `content` is markdown and the server renders `content_html` with `FormatHTML`. Only the admin form path stores HTML.
+- **D-10:** **Admin save gate: `CheckHTML` refuses, nothing is sanitized.** Unsafe HTML returns a 422 with a field error, as category content does today, and nothing is silently rewritten. No sanitizer dependency is added. `CheckHTML` must run on every admin write path for both the default and the non-default locale values. The admin save path must stop running `FormatHTML`/goldmark over HTML content, which is the current data-loss bug (todo `journal-imported-html-admin-resave.md`).
+
+### Field type contract (framework)
+- **D-11:** **Plugins register field types under a short global alias**, for example `type: blogeditor`. Boot fails loudly if two plugins, or a plugin and a cabana core type, claim the same alias. This is closer to Winter's `registerFormWidgets` aliases than to a namespaced key. — **Reversibility:** costly — aliases end up in plugin `fields.yaml` files across repos; renaming means editing every consumer.
+- **D-12:** The capability is a new `pact` interface (for example `HasFormFieldTypes`). Its Go side owns four things:
+ 1. **Option validation at boot**: the type's own YAML keys, fail-loud like the built-ins.
+ 2. **Value decode and validation on save**: any JSON shape, with field errors returned as 422.
+ 3. **Load and format for the form**: turns the stored column value into what the element receives. For the Blog Editor, a markdown post is served as its `content_html` (D-07).
+ 4. **List column formatting**: for example, strip tags and truncate.
+
+ — **Reversibility:** one-way — a published plugin API in `pact`; later plugins (payment and others, per todo `cabana-plugin-registered-field-types.md`) build on it.
+- **D-13:** **The client-side element loads globally on admin boot.** A plugin declares its field-type assets once, and the SPA loads them on every admin page, so the type works in any controller's form, including other plugins' forms. The element binds a value through a documented contract instead of the widget action/fill round-trip. The todo's starting point for that contract is a `value` property plus a `summer-change` event; the planner finalizes it. The element reads only the public `--c-*` CSS variables.
+- **D-14:** **Translatable variants are registered by the plugin itself**: the plugin registers both `blogeditor` and `mlblogeditor`, mirroring the `markdown`/`mlmarkdown` pair. The planner decides how a plugin ML type plugs into cabana's existing lift/hydrate path (`field_ml.go`) and the translate adapter, so locale storage is not reimplemented per plugin.
+- **D-15:** The form schema and the generated TS types carry plugin types as a generic shape, so the SPA build does not need to know them (per the todo). The cabana README, `docs/`, the admin OpenAPI, the generated TS types and the committed `dist/` are updated in the same change (CLAUDE.md documentation rules).
+
+### Libraries, media, category content
+- **D-16:** **The editor library is TipTap (ProseMirror, MIT).** It is wrapped in a plain custom element and bundled in **sm-journal-plugin's own JS build** (`assets/src` → `assets/dist`), with the bundle committed and embedded, like the admin SPA `dist/`. The host app needs no npm. The admin SPA itself gains no editor dependency.
+- **D-17:** **Embeds render in the `vue-journal-layer` blog views.** The layer expands allowlisted embed placeholders into privacy-friendly iframes (for example `youtube-nocookie.com`), so grzybyfunkcjonalne.pl shows them. A new layer tag is pinned in `vue-grzybyfunkcjonalne-app`.
+- **D-18:** **Images are uploaded through the existing backend-authenticated Journal media upload route**, by drag-and-drop or file picker. The editor inserts `` with alt text and an optional caption (`figure`/`figcaption`). There is no media library browser.
+- **D-19:** **Journal category content uses the Blog Editor** (`blogeditor`, or `mlblogeditor` if the category content attribute is translatable in the PHP tree) instead of the textarea. **No core cabana `richeditor` type** is added. This closes todo `cabana-richeditor-field-type.md` inside Journal. The existing `CheckHTML` gate in the Categories controller's `FormBeforeCreate`/`FormBeforeUpdate` stays.
+
+### Claude's Discretion
+- The exact `pact` interface name and method set, Go identifiers, the element value/event contract details, and the asset declaration shape, all within D-11 to D-15.
+- How "untouched" is detected for D-03: client-side dirty tracking versus server-side comparison with the loaded value. Either is acceptable as long as an untouched save is byte-identical.
+- The ProseMirror schema strategy for preserving unknown markup (generic passthrough nodes and marks, a global attribute preservation extension).
+- The exact embed placeholder markup and the provider allowlist (YouTube at minimum).
+- Whether a summercms tag release, the host bump and a UAT redeploy belong in this phase, following the 16.1 D-04 pattern. Recommended, because the goal is to edit imported posts on UAT.
+- Plan count and split, subject to the plan-count checkpoint and "unit tests are the last plan". Framework work comes before the Journal work.
+- Run the security-review agent: the phase adds a plugin API to `pact`, changes HTML write paths and adds an upload path into the editor.
+
+### Folded Todos
+- **`cabana-plugin-registered-field-types.md`**: the framework half of this phase (D-11 to D-15).
+- **`cabana-richeditor-field-type.md`**: resolved by reusing the Blog Editor for category content (D-19) instead of a core type.
+- **`journal-imported-html-admin-resave.md`**: the data-loss part is fixed by D-02, D-07 and D-10. Its required test applies: re-save an imported HTML post and assert `content` and `content_html` are unchanged. If 16.1 already shipped a stopgap, this phase replaces it.
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Todos folded into this phase
+- `.planning/todos/pending/cabana-plugin-registered-field-types.md`: the framework design sketch (pact interface, element contract, generic schema shape)
+- `.planning/todos/pending/cabana-richeditor-field-type.md`: category content requirement and the `CheckHTML` gate
+- `.planning/todos/pending/journal-imported-html-admin-resave.md`: the data-loss bug and its required test
+
+### Prior phase context
+- `.planning/phases/16.1-journal-admin-urgent-fixes-relation-search-list-state-post-f/16.1-CONTEXT.md`: D-03 (content/excerpt display, data-loss stopgap); 16.2 depends on 16.1
+- `.planning/phases/15-journal-plugin/15-CONTEXT.md`: D-01 to D-04 (frozen PHP tree is binding), D-11 (markdown field origin), D-14 (`/_journal/api/v1` contract)
+- `.planning/phases/16-grzybyfunkcjonalne-pl-on-reusable-blog-views/16-CONTEXT.md`: D-02 to D-05 (the `vue-journal-layer` structure and distribution, for D-17)
+- `.planning/phases/16-grzybyfunkcjonalne-pl-on-reusable-blog-views/16-RESEARCH.md`: Pitfall 2 (goldmark wipes raw HTML)
+- Phase 10.1 (`.planning/phases/10.1-runtime-admin-extension-point/`): the `type: widget` custom-element mechanism, asset serving, `--c-*` CSS variable rule
+
+### Framework code
+- `modules/pact/capabilities.go`: capability interfaces, `AdminClientAssets`
+- `modules/cabana/form_schema.go`: closed `formFieldTypes` set, fail-loud key validation
+- `modules/cabana/crud.go` (~line 1227): scalar type switch on save
+- `modules/cabana/field_ml.go`: ML lift/hydrate for `ml*` types
+- `modules/cabana/extension.go`: widget tag validation, plugin asset hashing and serving
+- `admin/src/components/form/registry.ts`, `admin/src/components/form/fields/MarkdownField.vue`, `MLMarkdownField.vue`: SPA renderer registry and the ML wrapper
+- `modules/cabana/README.md` and `docs/`: must be updated with the API
+
+### Journal plugin (`../sm-journal-plugin`)
+- `classes/format_html.go`: `FormatHTML` (goldmark, API path) and `CheckHTML` (gate)
+- `models/post/fields.yaml`, `models/category/fields.yaml`: fields switched to the Blog Editor
+- The Posts and Categories controllers' form hooks: where the admin save path runs `FormatHTML`/`CheckHTML`
+- Frozen PHP reference: `/media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/formwidgets/` (`JournalMarkdown.php`, `MLJournalMarkdown.php`) and `API.md`
+
+### Frontend layer
+- `../vue-journal-layer`: post body rendering, where embed placeholder expansion goes (D-17)
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- The Phase 10.1 widget machinery (`extension.go`) already validates custom-element tags, embeds and hashes plugin assets, and serves them with ETag and `?v=` cache busting. Global field-type assets should reuse this rather than add a second asset pipeline.
+- `field_ml.go`'s lift/hydrate and the translate adapter already store locale maps for `mlmarkdown`. `mlblogeditor` should go through the same path.
+- `classes.CheckHTML` is the existing three-pattern XSS gate, already used for category content.
+- The Journal media upload route (backend Bearer guard, Phase 15 D-15) is the upload target for D-18.
+
+### Established Patterns
+- Field types fail loudly at boot: an unknown type or key is a boot error. Plugin types must meet the same bar.
+- "Framework first": cabana changes land in their own commits and may get a summercms tag before the plugin work (Phase 12.1 and 15 D-11 precedent).
+- Another session may be working in `modules/` concurrently (16.1 D-02). Stage files explicitly by path and check for in-flight edits to shared cabana files.
+- Committed `dist/` for built JS (admin SPA). The plugin bundle follows the same pattern.
+
+### Integration Points
+- `formFieldTypes` and the crud type switch must consult the plugin type registry.
+- The SPA `registry.ts` needs a fallback route from an unknown or plugin type to a generic plugin-element renderer, instead of `UnsupportedField`.
+- The list column renderer must call the plugin's list formatter.
+- The `vue-journal-layer` post body renderer gets embed expansion, followed by a new layer tag and a bump in `vue-grzybyfunkcjonalne-app`.
+
+
+
+## Specific Ideas
+
+- The user explicitly wants an editor "beyond the current markdown field or a plain rich editor" that edits imported HTML losslessly. Lossless round-trip is the acceptance bar, and it has a test: re-save an untouched imported post and get byte-identical `content`/`content_html`.
+- Embeds must keep the XSS gate strict: placeholder in storage, iframe only in the frontend.
+
+
+
+## Deferred Ideas
+
+- **Core cabana `richeditor`/`mlricheditor` type** for plugins without their own editor. Not needed now; any plugin can register its own type or reuse one.
+- **Media library browser** for picking previously uploaded images.
+- **HTML input on the public write API** (`/_journal/api/v1/posts`). This would extend the PHP contract; the API stays markdown-in for now.
+- **Bulk HTML conversion command** (`journal:content-to-html`). Rejected in favour of convert-on-first-edit (D-07); revisit if a uniform format is ever needed.
+- **Allowlisting iframe hosts in `CheckHTML`**. Rejected in favour of placeholders (D-05).
+
+
+---
+
+*Phase: 16.2-plugin-provided-field-types-and-the-blog-editor-formwidget*
+*Context gathered: 2026-10-09*
diff --git a/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-DISCUSSION-LOG.md b/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-DISCUSSION-LOG.md
new file mode 100644
index 0000000..345cbbd
--- /dev/null
+++ b/.planning/phases/16.2-plugin-provided-field-types-and-the-blog-editor-formwidget/16.2-DISCUSSION-LOG.md
@@ -0,0 +1,142 @@
+# Phase 16.2: Plugin-provided field types and the Blog Editor formwidget - 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-09
+**Phase:** 16.2-plugin-provided-field-types-and-the-blog-editor-formwidget
+**Areas discussed:** Blog Editor: what it is, Markdown vs HTML posts, Field type contract, Libraries/media/richeditor
+
+---
+
+## Blog Editor: what it is
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| WYSIWYG + source toggle | ProseMirror/TipTap-style rich editing of HTML plus a raw HTML source tab | ✓ |
+| Block editor | Editor.js/Gutenberg blocks stored as JSON; imported HTML must be parsed into blocks | |
+| Dual mode: markdown or HTML | Source editor with preview, switching between markdown and HTML per post | |
+
+| Storage after admin save | Selected |
+|--------|----------|
+| HTML in both columns (content = HTML, content_html = HTML after CheckHTML) | ✓ |
+| Markdown in content (WYSIWYG HTML converted to markdown) | |
+| Keep source format (needs a per-post format flag) | |
+
+| Round-trip strictness | Selected |
+|--------|----------|
+| Byte-preserving unless edited; preserve unknown markup where possible; exact source tab | ✓ |
+| Normalize through the editor | |
+| Source-only for unknown markup | |
+
+**v1 features (multi):** Basic text ✓, Images ✓, Tables ✓, Embeds / raw HTML block ✓
+
+| Embeds vs the iframe gate | Selected |
+|--------|----------|
+| Allowlisted embed placeholder node; the frontend renders the iframe | ✓ |
+| Allowlist iframe hosts in CheckHTML | |
+| Raw HTML block only, gate unchanged | |
+
+| Locales | Selected |
+|--------|----------|
+| ML like today (locale switcher, locale → HTML map) | ✓ |
+| Single locale only | |
+
+---
+
+## Markdown vs HTML posts
+
+| Markdown post opened in the Blog Editor | Selected |
+|--------|----------|
+| Load content_html, save as HTML (one-way on first edit) | ✓ |
+| Bulk-convert at deploy | |
+| Per-post format flag | |
+
+| Keep mlmarkdown for Journal posts? | Selected |
+|--------|----------|
+| Blog Editor replaces it | ✓ |
+| Configurable per site | |
+
+| Public write API | Selected |
+|--------|----------|
+| Unchanged, PHP contract (markdown in, FormatHTML) | ✓ |
+| Accept HTML too | |
+
+| Admin save gate | Selected |
+|--------|----------|
+| CheckHTML refuses with 422 | ✓ |
+| Sanitize, then save (bluemonday) | |
+
+---
+
+## Field type contract
+
+| Naming | Selected |
+|--------|----------|
+| Namespaced vendor.plugin::name | |
+| Short alias, registered globally (boot fails on clash) | ✓ |
+| Custom-element tag | |
+
+| Client element loading | Selected |
+|--------|----------|
+| Globally on admin boot | ✓ |
+| Per controller, like AdminClientAssets | |
+
+**Go side owns (multi):** Option validation at boot ✓, Value decode and validate on save ✓, Load/format for form ✓, List column formatting ✓
+
+| ML types | Selected |
+|--------|----------|
+| Framework wraps any type with a translatable flag | |
+| Plugin registers an ml variant | ✓ |
+
+---
+
+## Libraries, media, richeditor
+
+| Editor library | Selected |
+|--------|----------|
+| TipTap (ProseMirror) | ✓ |
+| Bare ProseMirror | |
+| Lexical | |
+| You decide | |
+
+| Images | Selected |
+|--------|----------|
+| Upload via the Journal media route | ✓ |
+| URL only | |
+| Media library picker | |
+
+| Core richeditor todo | Selected |
+|--------|----------|
+| Reuse the Blog Editor for category content | ✓ |
+| Core cabana richeditor too | |
+| Defer category content | |
+
+| Bundle build | Selected |
+|--------|----------|
+| In sm-journal-plugin, dist committed | ✓ |
+| You decide | |
+
+| Embed rendering on the frontend | Selected |
+|--------|----------|
+| Yes, in the Phase 16 blog views layer | ✓ |
+| Admin side only | |
+
+---
+
+## Claude's Discretion
+
+- pact interface naming, element value/event contract, asset declaration shape
+- How "untouched" is detected for byte-preserving saves
+- ProseMirror schema strategy for unknown-markup preservation
+- Embed placeholder markup and provider allowlist
+- Whether release, host bump and UAT redeploy are in scope (recommended)
+- Plan count and split
+
+## Deferred Ideas
+
+- Core cabana richeditor type
+- Media library browser
+- HTML input on the public write API
+- Bulk HTML conversion command
+- Allowlisting iframe hosts in CheckHTML