diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md
new file mode 100644
index 0000000..10c4fba
--- /dev/null
+++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-CONTEXT.md
@@ -0,0 +1,142 @@
+# Phase 14.2.1: Translate plugin - Context
+
+**Gathered:** 2026-10-06
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+`Golem15.Translate` is ported to Go as `sm-translate-plugin` so Journal (Phase 15) and later blogs can keep translatable fields. This phase ships the lean core Journal needs: the Locale model and its admin screen, the TranslatableModel behavior, cabana ML field types, and PHP's request-locale resolution.
+
+The proof host is `sm-grzybyfunkcjonalne-app`, booted with `sm-user-plugin` + `sm-translate-plugin` (Journal mounts in Phase 15). Proof: the app boots, Locales admin works, and a fixture model can save and read `en`+`pl` through ML fields and `WithLocale`.
+
+`summercms.go` is touched for the ML field types (`mltext`, `mlmarkdown`) and any Translator/request-locale seam the plugin cannot own alone.
+
+Out of scope: the Messages catalogue and `manage_messages` admin, locale-picker / hreflang / suggestion-banner CMS components, AI and theme console commands, message import/export, and any edit to `wn-translate-plugin`. Those wait for a later translate follow-up if a site needs them.
+
+
+
+
+## Implementation Decisions
+
+### PHP source of truth
+- **D-01:** The port contract is `github.com/golem15com/wn-translate-plugin` at git SHA `725d547` (2026-08-26), the pin currently checked out in Płytarium. That tree is newer than grzybyfunkcjonalne.pl (`6e0c146`). — **Reversibility:** costly — Locale tables, attribute storage and Translator behaviour are copied from this tree.
+- **D-02:** Freeze at `725d547`. Planner and researcher must not silently pick a newer `master`. — **Reversibility:** reversible — a later discussion can re-pin.
+- **D-03:** Downstream agents read the frozen source from `/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate` (already at that SHA). Do not clone a second copy unless that path is missing or the SHA does not match.
+- **D-04:** This phase does not edit or PR `wn-translate-plugin`. An urgent PHP upgrade on a live Winter site before that site migrates is allowed as operations. If it lands before plan or execute, re-pin the SHA rather than mixing trees.
+
+### What ships this phase
+- **D-05:** Lean only: Locale model + Locales admin (`golem15.translate.manage_locales`), and a TranslatableModel behavior Journal can implement. Messages catalogue, locale-picker components, AI/theme commands and message import/export are deferred. — **Reversibility:** reversible — later plans can add the rest without rewriting Locale.
+- **D-06:** Cabana gains ML field types (`mltext`, `mlmarkdown`) matching PHP's `ml*` widgets, so a Journal form stays one screen with a locale switch. Phase 15's markdown field (15 D-11) and these ML types must compose (`mlmarkdown` is markdown plus locale). — **Reversibility:** costly — new field types in the typed admin schema and generated TS types.
+- **D-07:** Port PHP `Translator` locale resolution: URL prefix / session / cookie / default. Do not reduce this phase to `Accept-Language` or a query param only. — **Reversibility:** costly — public blog URLs and the Journal API will depend on this order.
+- **D-08:** The plugin seeds English and Polish locales, matching Journal 15 D-06.
+
+### Model API
+- **D-09:** A Go model declares translatable attributes with a `Translatable() []string` (or equivalent tagged list) the way PHP uses `$translatable`. Journal copies the PHP Post/Category lists. — **Reversibility:** costly — every translatable model in shared plugins will call this.
+- **D-10:** Storage uses the same tables and columns as this PHP pin (`golem15_translate_*` attributes/indexes/locales — researcher confirms exact names from the frozen updates). No JSON-column alternative. — **Reversibility:** one-way — Winter import and Journal cutover expect those tables.
+- **D-11:** A missing translation falls back to the default locale, as PHP does.
+- **D-12:** The exported API other plugins call this phase is the minimum: `WithLocale` on queries, get/set an attribute in a locale, and current locale from Translator. Do not 1:1 every PHP `TranslatableModel` / `Translator` method name unless research shows Journal needs it.
+
+### Where it boots
+- **D-13:** The host is `sm-grzybyfunkcjonalne-app` (same as Phase 15 D-18). This phase mounts `sm-user-plugin` + `sm-translate-plugin`; Journal is added in Phase 15. — **Reversibility:** one-way — submodule layout lands in that app.
+- **D-14:** Local app checkout: `/media/nvme/dev/golem15/summercms.io/summercms/sm-grzybyfunkcjonalne-app/` (sibling of `summercms.go`).
+- **D-15:** The user creates the public Gitea remote `git@git.golem15.com:golem15/sm-translate-plugin.git` as a manual plan step (it does not exist yet). Module path `git.golem15.com/golem15/sm-translate-plugin`, package `translate`, plugin ID `golem15.translate`.
+- **D-16:** Local plugin checkout: `/media/nvme/dev/golem15/summercms.io/summercms/sm-translate-plugin/` (sibling of `summercms.go`). The host mounts it as a submodule at `plugins/golem15/translate` with a `go.work` replace.
+- **D-17:** Phase proof: the app boots with user+translate; Locales admin works; a fixture model can save and read `en`+`pl` through ML fields and `WithLocale`.
+
+### Claude's Discretion
+- Exact `golem15_translate_*` table/column names and migration IDs, taken from the frozen PHP updates (D-10), not invented.
+- ML field YAML type names and SPA locale-switcher chrome, provided they follow cabana fail-loud rules and update the module README, `docs/`, admin OpenAPI, generated TS types and committed `dist/` in the same change.
+- How `mlmarkdown` shares implementation with Phase 15's markdown field (land the shared primitive here if Journal is otherwise blocked).
+- Plan count and split, subject to the plan-count checkpoint and "unit tests are the last plan".
+- Run the security-review agent: locale switching on public requests and admin ML writes are authorization-adjacent.
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Roadmap and prior decisions
+- `.planning/ROADMAP.md` § Phase 14.2.1 — stub goal; this file is the real scope
+- `.planning/ROADMAP.md` § Phase 15 — Journal depends on this plugin
+- `.planning/phases/15-journal-plugin/15-CONTEXT.md` — D-09/D-10 (Journal requires translate; translatable title/slug/content), D-06 (`en`+`pl`), D-11 (markdown field), D-18–D-21 (grzyby host)
+- `.planning/notes/core-plugins-own-repos.md` — `sm--plugin` layout, module path, submodule mount
+- `.planning/phases/12.1-user-plugin-admin-screens/12.1-CONTEXT.md` — YAML admin screens, framework-first field types
+- `.planning/phases/04-cli-scaffolding-i18n-and-mail/04-CONTEXT.md` — phrasebook; this plugin is model-level translation, not UI strings
+- `.planning/phases/09-backend-admin-authentication-and-schema-pipeline/09-CONTEXT.md` — typed schema, fail-loud YAML
+
+### PHP contract (read-only) — `/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate` at SHA `725d547`
+- `Plugin.php` — permissions (`manage_locales`, `manage_messages`), navigation, components (components are out of scope)
+- `models/Locale.php`, `models/Attribute.php`, `models/Message.php` (Message is out of scope except as a table that must not be broken)
+- `behaviors/` — TranslatableModel (or equivalent) and how `$translatable` is applied
+- `classes/Translator.php` — URL prefix / session / cookie / default (D-07)
+- `controllers/Locales.php` and YAML under `controllers/locales/`, `models/locale/`
+- `formwidgets/` — PHP `ml*` widgets that D-06 replaces
+- `updates/` — Locale / attributes / indexes table names and migration IDs (D-10)
+- `README.md`, `UPGRADE.md`
+- `tests/` — use as landmines; lean scope means not every PHP test maps 1:1
+
+### Go references
+- `../fonoteka.go/plugins/golem15/user/` — mount pattern for the sibling plugin
+- `modules/cabana/` — field registry; `mltext` / `mlmarkdown` land here
+- `modules/phrasebook/` — UI strings; do not conflate with model translations
+- `docs/backend/forms.md`, `docs/backend/admin-controllers.md`
+
+### Remotes
+- `git@git.golem15.com:golem15/sm-translate-plugin.git` — **does not exist yet**; user creates it, public
+- `git@git.golem15.com:golem15/sm-grzybyfunkcjonalne-app.git` — empty proof host, already created
+- `git@git.golem15.com:golem15/sm-journal-plugin.git` — public, empty; mounted in Phase 15
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `sm-user-plugin` mount pattern: `summer.yaml`, submodule at `plugins/golem15/user`, `go.work` replace, `pact.HasAdminControllers`.
+- cabana field registry (Phase 12.1 `permissioneditor`, Phase 12.2 `fileupload` / `datepicker`): the pattern for `mltext` / `mlmarkdown`.
+- phrasebook `en`/`pl` for plugin UI strings — separate from Locale rows and attribute translations.
+- `sm-grzybyfunkcjonalne-app` remote already exists; local directory may not.
+
+### Established Patterns
+- Shared plugins: module `git.golem15.com/golem15/sm--plugin`, package plain (`translate`), plugin ID `golem15.translate`.
+- Unknown YAML keys fail boot. Framework field types update README, `docs/`, OpenAPI, TS types and `boardwalk` `dist/` in the same change.
+- PHP originals are not changed. Migrations are append-only. Unit tests are the last plan.
+
+### Integration Points
+- New repo `sm-translate-plugin`: Locale model, updates, Locales admin, Translatable behavior, Translator.
+- `summercms.go` cabana + admin SPA: `mltext`, `mlmarkdown`, locale switcher on forms.
+- `sm-grzybyfunkcjonalne-app`: first mount of user + translate.
+- Phase 15 Journal: `Requires` translate; Post/Category `Translatable()` lists; `mltext`/`mlmarkdown` on YAML forms.
+
+
+
+
+## Specific Ideas
+
+- Same freeze/read-only/re-pin rules as Journal, applied to Translate.
+- "Start fast" on `sm-grzybyfunkcjonalne-app` still holds; this phase boots that app without Journal.
+- Messages, CMS locale components and AI/theme commands were explicitly left out so Journal is not blocked.
+
+
+
+
+## Deferred Ideas
+
+- Messages catalogue and `golem15.translate.manage_messages` admin.
+- Locale picker, alternate hreflang, and locale-suggestion-banner CMS components (Phase 16 views may need a successor).
+- AI/theme console commands and message import/export.
+- Remaining PHP locales beyond the `en`+`pl` seed (D-08 is seed rows, not phrasebook files).
+- Phase 15 should list **Depends on: Phase 14.2.1** in ROADMAP (`$gsd-phase --edit 15`); not done in this discussion.
+
+### Reviewed Todos (not folded)
+- `sitemap-plugin-port.md`, `mailblocker-with-mailing.md`, and the other keyword matches from `todo.match-phase 14.2.1`: unrelated housekeeping.
+
+
+
+---
+
+*Phase: 14.2.1-translate-plugin*
+*Context gathered: 2026-10-06*
diff --git a/.planning/phases/14.2.1-translate-plugin/14.2.1-DISCUSSION-LOG.md b/.planning/phases/14.2.1-translate-plugin/14.2.1-DISCUSSION-LOG.md
new file mode 100644
index 0000000..f8c2f18
--- /dev/null
+++ b/.planning/phases/14.2.1-translate-plugin/14.2.1-DISCUSSION-LOG.md
@@ -0,0 +1,78 @@
+# Phase 14.2.1: Translate 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-06
+**Phase:** 14.2.1-translate-plugin
+**Areas discussed:** PHP source of truth, what ships, model API, where it boots
+
+---
+
+## PHP source of truth
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Fonoteka pin `725d547` | Newest Płytarium checkout | ✓ |
+| grzyby pin `6e0c146` | Older ancestor | |
+| GitHub master at plan time | Moving target | |
+
+**User's choice:** Freeze at `725d547`, read from the Fonoteka path. Read-only with the same urgent-upgrade re-pin rule as Journal.
+
+---
+
+## What ships
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Lean: Locale + TranslatableModel | Unblocks Journal | ✓ |
+| Lean plus Messages catalogue | Extra admin | |
+| Full PHP surface | Picker, AI/theme, import/export | |
+
+**User's choice:** Lean. Cabana `mltext`/`mlmarkdown`. PHP Translator resolution (URL prefix / session / cookie / default). Seed `en`+`pl`.
+
+---
+
+## Model API
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| `Translatable() []string` like PHP `$translatable` | Journal copies the PHP list | ✓ |
+| YAML-only; models unaware | | |
+| Same Winter attribute tables | Cutover-compatible | ✓ |
+| JSON column per field | Breaks Winter import | |
+| Fallback to default locale | PHP behaviour | ✓ |
+| Minimum API (`WithLocale`, get/set, Translator) | Enough for Journal | ✓ |
+| 1:1 every PHP method | | |
+
+**User's choice:** PHP-like declaration, same tables, PHP fallback, minimum exported API.
+
+---
+
+## Where it boots
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Same `sm-grzybyfunkcjonalne-app` | Matches Phase 15 D-21 | ✓ |
+| In-module testhost | | |
+| User creates `sm-translate-plugin` remote | Does not exist yet | ✓ |
+| Sibling checkout | `summercms/sm-translate-plugin/` | ✓ |
+| Proof: Locales admin + fixture en+pl | | ✓ |
+| Plugin tests only | | |
+
+**User's choice:** Grzyby host with user+translate. User creates the public remote. Proof is boot + Locales admin + fixture model.
+
+---
+
+## Claude's Discretion
+
+- Exact table/column names from frozen PHP updates
+- ML field identifiers and docs/OpenAPI/`dist/` bundling
+- How `mlmarkdown` shares work with Phase 15 markdown
+- Plan count and split
+- Security-review agent
+
+## Deferred Ideas
+
+- Messages admin, CMS locale components, AI/theme commands
+- ROADMAP Phase 15 depends_on should include 14.2.1 (`$gsd-phase --edit 15`)