diff --git a/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-CONTEXT.md b/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-CONTEXT.md
new file mode 100644
index 0000000..96fc3b9
--- /dev/null
+++ b/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-CONTEXT.md
@@ -0,0 +1,141 @@
+# Phase 4: CLI scaffolding, i18n and mail - Context
+
+**Gathered:** 2026-09-18
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Framework repo (`summercms.go`) only. Three deliverables:
+
+1. **Scaffolding** (CLI-02): `summer make:plugin`, `make:model`, `make:migration`, `make:command`, `make:job`, `make:admin-controller` generate stubs that compile and pass `go vet`, laid out in the WinterCMS directory shape and auto-wired through a generated per-plugin registry.
+2. **i18n** (`phrasebook`, I18N-01): namespaced keys `vendor.plugin::group.key` loaded from per-plugin per-locale YAML, `:name` parameter substitution, CLDR plurals for pl and en (go-i18n for category selection), locale fallback chain.
+3. **Mail** (`postcard`, I18N-03): plugins register mail templates and layouts by dotted name with the WinterCMS per-locale suffix convention; templates are WinterCMS-shaped files (INI header, `==`, Markdown body) rendered through `html/template` plus a Markdown renderer, sent through a driver interface (smtp via go-mail, log, memory).
+
+Not in this phase: per-request locale resolution (Phase 7, I18N-02), translated validation messages (`lifeguard`), queued mail and River (Phase 11), the admin schema pipeline (Phase 9), restructuring the Phase 3 `fonoteka.go` plugins (Phase 5), any writes to `fonoteka.go`.
+
+
+
+
+## Implementation Decisions
+
+### Lang files and plurals (phrasebook)
+- **D-01:** Lang files are `lang//.yaml` inside the plugin module, embedded through the `HasLang` capability; keys are `vendor.plugin::group.dot.path`, group = filename. Nested YAML maps flatten to dot paths, as the summer-phrasebook design did for HOCON.
+- **D-02:** Two plural syntaxes are both accepted. A YAML **map** under a key is a CLDR category map (`one`, `few`, `many`, `other`, plus `zero`/`two` where a locale has them) and is selected through go-i18n's plural rules. A **string containing `|`** is parsed Laravel-style: pipe-separated forms in CLDR category order, with optional explicit `{0}` / `[2,*]` conditions, as in the summer-phrasebook design. Fonoteka's PHP lang files contain no pipe plurals, so the map form is the primary target; the pipe form exists for line-by-line ports of other WinterCMS plugins.
+- **D-03:** Parameters use `:name` placeholders with the `:Name` (ucfirst) and `:NAME` (upper) case variants. phrasebook performs substitution itself; go-i18n is used only for CLDR plural category selection, not for message templating. PHP lang values copy over unchanged.
+- **D-04:** Missing keys walk the fallback chain (requested `pl-PL` → parent `pl` → configured fallback) and then return the raw key string, as WinterCMS does. In non-production environments a missing key is logged once per key.
+- **D-05:** Default and fallback locale come from config: `app.locale` and `app.fallback_locale`, framework default `en` for both. Płytarium sets `app.locale: pl` in its own config; the framework ships no Polish default.
+
+### Mail template format (postcard)
+- **D-06:** Template files keep the WinterCMS shape exactly: an INI-style header (`subject = "..."`, `description = "..."`, `layout = "..."`), a `==` separator line, then the body. Files live at `views/mail/.htm` inside the plugin, embedded through `HasMailTemplates`, and are registered by dotted name (`golem15.fonoteka::mail.collection_invitation`). The subject line is itself a template so `{{ .CollectionName }}` works there. postcard ships a small header parser; no INI library.
+- **D-07:** Bodies are Markdown. Rendering order: `html/template` for variable substitution on the Markdown source, then Markdown → HTML for the HTML part; the substituted Markdown source is the plain-text part, as WinterCMS does. This adds one dependency to name in research (goldmark is the expected pick; research confirms version and HTML-escaping behavior of substituted values).
+- **D-08:** Per-locale templates are the PHP convention with no framework magic: the unsuffixed name is the app-default-locale version, `-en` (etc.) suffixed names are explicit siblings, and **the caller picks the full name**. postcard does no locale lookup or fallback at send time.
+- **D-09:** Layouts are registered by short name (`plytarium` → `golem15.fonoteka::mail.layouts.plytarium`), mirroring `registerMailLayouts()`. A layout file has the same INI + `==` shape with a text wrapper section and an HTML wrapper section, each rendering `{{ .Content }}`; shared variables (`css`, brand css) come from config or the registering plugin. The framework ships one neutral `default` layout.
+
+### Scaffolding (make:*)
+- **D-10:** Generated plugins follow the WinterCMS directory layout as Go subpackages, decided in `/gsd-explore` and recorded in `.planning/notes/plugin-layout-winter-directories.md`: `models/`, `classes/`, `controllers/`, `console/`, `jobs/`, `middleware/`, `updates/` are packages; `lang/`, `views/mail/`, `config/` are embedded asset directories; `plugin.go` and `routes.go` sit in the root package and import the leaves. Chosen because agents converting golem15, jz and pxpx plugins lean on the PHP directory: `models/Album.php` → `models/album.go` must be a mechanical move.
+- **D-11:** `models/` is a leaf package: it never imports a sibling package of its own plugin. Casts move into `models/` (or `lagoon` when generic); lifecycle hooks that call services become GORM callbacks registered on the model from `classes/` or `plugin.go` — the same callback-registry mechanism Phase 5 uses for cross-plugin extension. Phase 4 ships the enforcement: `summer build` (or a framework `go test` over the workspace) fails naming the plugin and the offending import when a `models/` package imports a sibling.
+- **D-12:** Auto-wiring through a generated per-plugin `registry.gen.go` in the root package: each `make:*` appends the new artifact to the generated slices (migrations, commands, jobs, admin controllers, models) that the scaffolded `plugin.go`'s capability methods return. Hand-written `plugin.go` is never rewritten. Existing hand-written plugins opt in by calling the same generated accessors (`append(handWritten, generatedMigrations()...)`); running `make:*` on a plugin without a registry creates it and prints the one-time line to add. The Phase 3 `fonoteka.go` plugins are not touched in this phase.
+- **D-13:** `make:model ` generates the model struct in `models/` (table `vendor_plugin_names`, timestamps) **and** a create-table migration appended to the plugin's gormigrate set in `updates/`; `--no-migration` skips the migration. `make:migration` appends a migration alone.
+- **D-14:** `make:admin-controller` generates a stub satisfying a minimal `pact` admin-controller interface defined in this phase (ID, model name, config directory) plus `fields.yaml` and `columns.yaml` placeholders in the WinterCMS shape Fonoteka already uses (`controllers//fields.yaml`). Phase 9 grows the interface and the template; the stub only has to compile and vet now.
+- **D-15:** `make:job` generates a stub satisfying a framework job interface modeled on River's worker (a `Kind() string` on an args struct, `Work(ctx, args) error`) **without importing River**. Phase 11 adapts that interface onto River; jobs are unit-testable now by calling `Work` directly.
+- **D-16:** Stub templates are embedded `text/template` files under `internal/build/stubs/*.tmpl`, rendered and passed through `go/format`. `make:plugin`'s existing Go string builders migrate to the same mechanism. A framework test generates every stub type into a temporary plugin inside `examples/hello` and runs `go build` and `go vet` on it: that test is success criterion 1.
+- **D-17:** Argument shape is `make: `. When run inside a plugin directory the plugin ID may be omitted and is read from `plugin.go` (`pluginIDFromGo` in `internal/build/scaffold.go` already does this).
+
+### Mail drivers and test send
+- **D-18:** Three drivers ship behind the `postcard` driver interface: `smtp` (go-mail), `log` (writes the rendered headers and text part to the app logger, for dev), `memory` (keeps sent messages in a slice for tests). Driver and connection settings come from a `mail.*` config section (`config/mail.yaml`, `SUMMER_MAIL__…` overrides per Phase 1 D-08).
+- **D-19:** Success criterion 3 is proven twice: a unit test renders a registered template + layout through the `memory` driver and asserts subject, HTML part and text part; an integration test, gated the same way as the testcontainers Postgres tests (fails when Docker is unavailable, skipped under `-short`), starts a Mailpit container and asserts through its API that the message arrived over SMTP via go-mail.
+- **D-20:** Sending is a `postcard.Mailer` service published on the `backpack` container: `Send(ctx, postcard.Message{Template, To, Cc, Bcc, ReplyTo, Vars}) error`. This is the port shape for `Mail::send('vendor.plugin::mail.x', $vars, fn)`: the PHP closure's recipient/subject calls become struct fields. No per-template Go types.
+- **D-21:** `Send` returns the driver error to the caller; no swallowing, no retries (retries belong to Phase 11's queue). Registering a template whose file is missing, or a template naming an unregistered layout, fails `Boot` with the plugin ID and the name, consistent with Phase 1 D-10.
+
+### Claude's Discretion
+- Exact `phrasebook` API surface (`Get`, `Choice`, locale on context via an unexported key with exported accessors per ARCHITECTURE.md), namespace aliases and runtime overrides from the phrasebook design if cheap; the request-context seam for Phase 7.
+- Which Markdown renderer (research names it; goldmark expected) and how substituted values are escaped before Markdown rendering.
+- Registry file name and the exact accessor names in `registry.gen.go`; how `summer build` locates each plugin's `models/` package for the leaf check.
+- What `make:plugin` scaffolds beyond Phase 1's minimum now that the directory layout is fixed (empty `lang/en/lang.yaml`, `views/mail/`, `updates/` package with an empty set are reasonable).
+- Whether `make:command` stubs land in `console/` with a colon-style name derived from the plugin ID (`fonoteka:`), following Phase 1 D-15.
+- Mailpit image and API client (a few `net/http` calls; no SDK).
+- Plan count and split, subject to the plan-count checkpoint and "unit tests are the last plan" rules.
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Plugin layout (binding for all make:* output)
+- `.planning/notes/plugin-layout-winter-directories.md` — the directory-as-subpackage layout, the `models`-is-a-leaf rule, the Fonoteka dependency evidence and the accepted trade-off
+- `.planning/todos/pending/verify-models-leaf-rule.md` — follow-up validation on other plugins (not Phase 4 work)
+
+### Design carry-overs
+- `../modules/summer-phrasebook/README.md` — key format, `:name` case variants, pipe-string plural syntax with `{n}`/`[a,b]` conditions, CLDR form ordering, fallback chain, aliases and overrides
+- `.planning/phases/01-framework-kernel-foundation/01-CONTEXT.md` — D-03 (examples/hello as testbed and template source), D-06–D-09 (config layout, `SUMMER_` env mapping), D-10 (fail boot naming plugin + missing thing), D-14–D-17 (bonfire output, colon command names, `bonfire.Command`)
+- `.planning/phases/03-first-vertical-slice-genres-end-to-end/03-CONTEXT.md` — D-16–D-19 (squashed, never-edited per-plugin gormigrate sets; `HasMigrations` capability) which `make:migration` appends to
+
+### Research
+- `.planning/research/ARCHITECTURE.md` — Pattern 1 capability interfaces (`HasLang`, `HasMailTemplates` as `fs.FS`), package table (`phrasebook`, `postcard`), Anti-Pattern on context keys
+- `.planning/research/STACK.md` — go-i18n/v2 v2.6.1 (CLDR v48), goccy/go-yaml, testcontainers-go; go-mail is named in ARCHITECTURE.md's package table
+- `.planning/research/FEATURES.md` §Console / i18n — mail-template-per-locale-by-suffix convention, `registerMailTemplates` pairs
+- `.planning/research/PITFALLS.md` §dev loop (line ~309) — scaffolding quality is what makes the compiled-plugin loop viable for agents
+
+### PHP reference (file shapes to mirror, read-only)
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/views/mail/collection_invitation-en.htm` — INI header + `==` + Markdown body
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/views/mail/layouts/plytarium.htm` — three-section layout (name header, text wrapper, HTML wrapper with `css`/`brandCss`)
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/Plugin.php` lines 333–351 — `registerMailTemplates()` / `registerMailLayouts()`
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/lang/{pl,en}/lang.php` — key structure to mirror in YAML (no plural pipes present)
+- `/media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/` directory tree — the layout D-10 mirrors
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `internal/build/scaffold.go`: `MakePlugin`, `AddPlugin`, `pluginIDFromGo`, go.mod/go.work editing, toolchain pinning — `make:*` commands build on these; the Go-string source builders migrate to embedded `.tmpl` files (D-16)
+- `cmd/summer/main.go`: `make:plugin`, `dev`, `plugin:add` as `bonfire.Command` values — new `make:*` commands register the same way
+- `pact/capabilities.go`: `HasLang` and `HasMailTemplates` are reserved names in the comment block; both were sketched as `fs.FS` returners in ARCHITECTURE.md
+- `examples/hello` (plugins `base`, `greeter`, `optional`): permanent testbed; the stub-compile test (D-16) and a lang + mail smoke can live here
+- `bonfire` output widgets and non-TTY degradation for `make:*` feedback
+- `compass` typed section loading for `app.locale` / `mail.*`
+
+### Established Patterns
+- Capability discovery by type assertion at a fixed kernel point (`HasConfig` before Register, `HasMigrations` in lagoon migrate, `HasRoutes` in surf assemble) — `HasLang` and `HasMailTemplates` get their own assertion points in phrasebook/postcard boot
+- Fail-boot-with-names for missing dependencies, middleware and now templates/layouts
+- Per-plugin ordered slices (migrations) composed at boot in `Requires()` order — lang namespaces and mail template registries compose the same way
+- testcontainers gating: fail when Docker is unavailable, skip under `-short` (Phase 2/3) — reused for Mailpit
+- Colon-style command names; `bonfire.Command` with injected `Output`
+
+### Integration Points
+- `pact`: new minimal interfaces for admin controllers (D-14) and jobs (D-15), plus `HasLang` / `HasMailTemplates`
+- `backpack`: `postcard.Mailer` and the phrasebook translator published as services
+- `summer build` / `internal/build`: the `models`-leaf check (D-11) and `registry.gen.go` generation (D-12)
+- `surf` locale middleware (Phase 3 D-12 reads `Accept-Language` into context): phrasebook exposes the context accessor it will use; Phase 7 fills in user-preferred locale
+
+
+
+
+## Specific Ideas
+
+- The user consistently chose the WinterCMS-literal option over the "Go-native" one when the two diverged (INI + `==` mail files, caller-picked `-en` names, both plural syntaxes, directory-as-subpackage layout). Downstream: when a WinterCMS shape and a Go-idiomatic shape compete and neither is decided here, prefer the WinterCMS shape unless it fights the compiler.
+- The conversion audience is agents porting many plugins (golem15, jz, pxpx projects), so rules must be mechanical and tool-enforced (D-11's build check), not documented conventions.
+- Fonoteka mail bodies use `**bold**` and `[link](url)` Markdown with Twig variables; the Go port keeps them recognisably the same file with `{{ .Var }}` instead of `{{ var }}`.
+
+
+
+
+## Deferred Ideas
+
+- Restructuring the flat Phase 3 `fonoteka.go` plugins into the D-10 layout — Phase 5, when they are widened anyway.
+- Validating the `models`-leaf rule on keios.eu / jz / pxpx plugins — todo `verify-models-leaf-rule`, before Phase 5's bulk port.
+- Per-request locale from `preferred_locale` — Phase 7 (I18N-02).
+- Queued sends, retries, River adapter for the Phase 4 job interface — Phase 11.
+- `summer mail:test` CLI command for production smoke sends — not needed for the criterion; capture if a later phase wants it.
+- Attachments on `postcard.Message` — not required by any Fonoteka template; add when a port needs it.
+
+
+
+---
+
+*Phase: 04-cli-scaffolding-i18n-and-mail*
+*Context gathered: 2026-09-18*
diff --git a/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-DISCUSSION-LOG.md b/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-DISCUSSION-LOG.md
new file mode 100644
index 0000000..c5ded10
--- /dev/null
+++ b/.planning/phases/04-cli-scaffolding-i18n-and-mail/04-DISCUSSION-LOG.md
@@ -0,0 +1,207 @@
+# Phase 4: CLI scaffolding, i18n and mail - 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-09-17 / 2026-09-18
+**Phase:** 04-cli-scaffolding-i18n-and-mail
+**Areas discussed:** Lang file & plural syntax, Mail template format, Scaffold stub behavior, Mail drivers & test send
+
+---
+
+## Lang file & plural syntax
+
+### Plural message form
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| CLDR category map | `{one, few, many, other}` YAML map; 1:1 onto go-i18n; covers Polish's 4th category | |
+| Laravel pipe strings | `":count wpis\|:count wpisy\|:count wpisów"` plus `{0}`/`[2,*]` ranges, per summer-phrasebook | |
+| Both accepted | Map = CLDR categories; string with `\|` = Laravel-style | ✓ |
+
+**Notes:** Fonoteka PHP lang files contain no pipe plurals; the pipe form is for line-by-line ports of other WinterCMS plugins.
+
+### Parameter placeholders
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| `:name` | WinterCMS/Laravel style with `:Name`/`:NAME` variants; phrasebook substitutes, go-i18n only selects plural category | ✓ |
+| `{{.Name}}` go-i18n native | Every ported string rewritten | |
+| You decide | | |
+
+### Missing key
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Fallback chain, then raw key | requested → parent → fallback → key string; logged once in dev/test | ✓ |
+| Fallback chain, then error | `(string, error)` or panic in dev | |
+| You decide | | |
+
+### Default locale
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Config-driven, en default | `app.locale` / `app.fallback_locale`, framework default `en` | ✓ |
+| Config-driven, pl default | | |
+| You decide | | |
+
+---
+
+## Mail template format
+
+### File shape
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| YAML front matter + body | `---` header parsed with goccy/go-yaml | |
+| Keep WinterCMS INI + `==` | Exactly the PHP file shape; small hand-written header parser | ✓ |
+| Go registration + body-only files | Subject/layout declared in Go | |
+
+### Body format
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Markdown, add a renderer | html/template for vars, then Markdown → HTML; raw Markdown is the text part; one new dependency (goldmark expected) | ✓ |
+| Plain HTML only | Zero new deps; six templates hand-converted; no text part | |
+| HTML now, Markdown later | Body-renderer seam, decide at Phase 12/13 | |
+
+### Per-locale suffix
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Suffix lookup with fallback | postcard tries `name-` then `name` | |
+| Caller picks the full name | Exactly like PHP; no locale logic in postcard | ✓ |
+| You decide | | |
+
+### Layouts
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Registered by short name, HTML + text | Mirrors `registerMailLayouts` and the three-section PHP layout; framework ships `default` | ✓ |
+| HTML wrapper only | Drops the text section | |
+| You decide | | |
+
+---
+
+## Scaffold stub behavior
+
+### Wiring
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Auto-wire via generated registry file | Per-plugin `registry.gen.go`; plugin.go never rewritten | ✓ |
+| Edit plugin.go in place | go/ast insertion | |
+| Write file, print the line to add | | |
+
+### make:model output
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Model + migration, flag to skip | `--no-migration` | ✓ |
+| Model only | | |
+| Model + migration + fields.yaml/columns.yaml | No consumer until Phase 9 | |
+
+### make:admin-controller before Phase 9
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Minimal interface + placeholder YAML | Tiny pact interface, WinterCMS-shaped YAML placeholders | ✓ |
+| Go stub only, no YAML | | |
+| You decide | | |
+
+### Stub templates
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Embedded text/template .tmpl files | `internal/build/stubs`, go/format, compile test in examples/hello | ✓ |
+| Keep Go string builders | | |
+| You decide | | |
+
+### make:job before River
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Framework job interface, River-shaped | `Kind()` on args, `Work(ctx, args) error`; no River import | ✓ |
+| Import River now | River enters go.mod six phases early | |
+| You decide | | |
+
+### File layout inside a plugin
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Flat, one package, name suffixes | fonoteka.go Phase 3 style; no intra-plugin imports | |
+| WinterCMS-style subpackages | models/, controllers/, console/, jobs/, updates/ as packages | ✓ (via /gsd-explore) |
+| Flat Go, WinterCMS dirs for non-Go assets | | |
+
+**User's choice:** Deferred to `/gsd-explore` ("This is a difficult one"), then decided: WinterCMS-style subpackages because agents converting golem15/jz/pxpx plugins lean on the PHP **directory**, not the class graph. Added rule: `models/` is a leaf package (user agreed "first option seems the best"), casts move in, service-calling hooks become callbacks from `classes/`/`plugin.go`, enforced by `summer build`. Evidence: Fonoteka has 40 `classes→models` edges and exactly 1 `models→classes` edge (a cast and a hook in `Album.php`). Recorded in `.planning/notes/plugin-layout-winter-directories.md`.
+
+### Coexistence with hand-written plugins
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Opt-in, merged by plugin.go | Hand-written plugins call generated accessors; fonoteka.go untouched | ✓ |
+| Migrate existing plugins in this phase | Touches fonoteka.go, out of phase scope | |
+| You decide | | |
+
+### Argument shape
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| `make:model ` | Plugin ID inferred from plugin.go when inside a plugin dir | ✓ |
+| Always explicit, no inference | | |
+| You decide | | |
+
+---
+
+## Mail drivers & test send
+
+### Drivers
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| smtp + log + memory | go-mail, logger, in-memory slice | ✓ |
+| smtp + memory only | | |
+| smtp only | | |
+
+### Test send
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Unit test + SMTP integration test | memory driver unit test plus Mailpit container test gated like testcontainers Postgres | ✓ |
+| Unit test with memory driver only | | |
+| `summer mail:test` command | Manual verification | |
+
+### Send API
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Mailer service on the container | `postcard.Mailer.Send(ctx, Message{Template, To, Vars})` | ✓ |
+| Typed message per template | | |
+| You decide | | |
+
+### Failures
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Error returned, unknown template fails at boot | Consistent with Phase 1 D-10 | ✓ |
+| Error returned, lazy template check | | |
+| You decide | | |
+
+---
+
+## Claude's Discretion
+
+- phrasebook API surface, aliases/overrides, request-context seam for Phase 7
+- Markdown renderer pick (research) and escaping of substituted values
+- registry.gen.go naming and accessor names; how the models-leaf check locates packages
+- What make:plugin scaffolds beyond Phase 1's minimum in the new layout
+- make:command naming under the plugin's colon prefix
+- Mailpit image and API access
+- Plan count and split
+
+## Deferred Ideas
+
+- Restructure Phase 3 fonoteka.go plugins into the directory layout — Phase 5
+- Validate the models-leaf rule on keios.eu / jz / pxpx plugins — todo `verify-models-leaf-rule`
+- `summer mail:test` production smoke command
+- Attachments on `postcard.Message`