# Gallery Entry Shapes — Revised Position (after operator's "slightly different case" feedback) > **Status**: DRAFT v2 for operator review (2026-07-22) > **Author**: Mavis > **Replaces**: `/workspace/position-gallery-entry-shapes-recipes-and-code.md` v1 > **Key change**: **Promotion to top-level is earned by reusability.** App-specific modules stay inside the app entry. Cross-app modules get promoted to `gallery/modules/`. The gallery is a *promotion system*, not just a *list system*. --- ## TL;DR The operator is right — vibecoder and freshcloud-mail are different cases: - **VibeCoder's modules are CROSS-APP** (ai-toast, ai-mic, etc. — any FreshVibe app uses them). They live at `gallery/modules/`. VibeCoder itself is just a consumer; it doesn't need a gallery entry. - **freshcloud-mail's modules are APP-SPECIFIC** (mail-engine-smtp, mail-engine-imap — only freshcloud-mail uses them). They live at `gallery/apps/freshcloud-mail/modules/`, not at top-level. freshcloud-mail itself IS a gallery entry because it's a platform-level FreshCloud app. The "slightly different case" is: **where the modules live depends on whether they cross apps, not on whether they're a module or a bundle**. The promotion rule is the same either way. The constitutional rule: - Recipe books **always** in the gallery (non-negotiable) - Code defaults to "in the gallery" but can be external - Location is the discriminator: top-level `modules/` = cross-app; inside `apps//` = app-internal --- ## 1. The "promotion" model The gallery is a **promotion system**. A module is born inside an app. If multiple apps start using it, it gets **promoted** to `gallery/modules/`. If only one app uses it, it stays inside `gallery/apps//modules/`. **Why this matters:** - Cross-app modules get the full gallery treatment: top-level listing, registry index, consumers tracked, facets, dependency graph, swappability - App-specific modules get the app's namespace: bundled under the app entry, recipe book inside the app, code inside the app - The gallery's `modules/` directory is the *honour roll* of reusable components - The gallery's `apps//modules/` is the *private* subdirectory of platform apps **For freshcloud-mail:** - The 17 mail-engine modules are mail-specific - They stay inside `apps/freshcloud-mail/modules/` - They do NOT promote to `gallery/modules/` (because no one else needs an SMTP client) - The `freshcloud-mail-engine-bundle` lives at `apps/freshcloud-mail/bundles/freshcloud-mail-engine-bundle/` **For VibeCoder:** - The ai-bundle modules (ai-toast, ai-mic, etc.) are cross-app - They live at `gallery/modules/` - They are tracked in `registry.json` with consumers: `[vibecoder, freshcards, vibescope, oscar]` - The `ai-bundle` lives at `gallery/bundles/ai-bundle/` - VibeCoder itself is NOT a gallery entry — it's a sovereign consumer --- ## 2. The new structure ``` gallery/ ├── modules/ ← CROSS-APP modules (the "promoted" ones) │ ├── ai-toast/ ✅ extracted │ ├── ai-mic/ ❌ TODO (lives in ai-shell) │ └── ... │ ├── bundles/ ← CROSS-APP bundles │ ├── ai-bundle/ (11 modules, all cross-app chrome/AI) │ └── ... │ └── apps/ ← APP entries (NEW — proposed 2026-07-22) ├── freshcloud-mail/ ← the platform's email app │ ├── module.json (kind: "app", code_location: "external", │ │ source_location: "avidtech6/freshmail-2") │ ├── module-meta.json │ ├── recipe-book/ ← FVW §11 (always in gallery) │ │ ├── recipe.md │ │ ├── codex.md │ │ ├── rules.md │ │ ├── module-meta.json │ │ ├── ingredients.json │ │ ├── diffs/ │ │ ├── trace-atlas/ │ │ ├── dna/ │ │ ├── plan.md │ │ └── coverage-matrix.md │ ├── modules/ ← APP-INTERNAL modules (the 17 mail-engine ones) │ │ ├── mail-engine-smtp/ │ │ │ ├── module.json (kind: "app-internal-module", code_location: ???) │ │ │ ├── recipe-book/ (always) │ │ │ └── src/ (if small enough to vendor) │ │ ├── mail-engine-imap-client/ │ │ └── ... (15 more) │ └── bundles/ ← APP-INTERNAL bundles │ └── freshcloud-mail-engine-bundle/ │ ├── module.json (kind: "bundle", kind_subtype: "app-internal") │ ├── bundle-manifest.json │ └── bundle-features.md │ └── (other platform apps, future: freshcloud-calendar, freshcloud-contacts, etc.) ``` **For sovereign apps that are NOT in the gallery (like vibecoder-standalone, fvs):** They don't appear in the gallery at all. They just consume `gallery/modules/` and `gallery/bundles/`. The fact that they're sovereign consumers doesn't need a gallery entry. But should they have a recipe book in the gallery? Two options: - **Option A: Yes, register them as `apps//` with `code_location: "external"` and recipe book in gallery.** Same shape as freshcloud-mail, but the recipe book is "for reference" not "canonical". - **Option B: No, they're not in the gallery.** Only platform apps (FreshCloud suite) get gallery entries. **My recommendation: Option A.** Every sovereign app should be discoverable in the gallery, with a recipe book (for reference) and a pointer to the source repo. This way: - The gallery is the discovery surface for "what apps exist in the FreshVibe ecosystem" - VibeCoder, freshcards, vibescope, oscar, fvs all show up in the gallery - The gallery has both: cross-app modules (top-level) + apps + their internal modules - The pattern is consistent: recipe book always in gallery, code in gallery or external So the structure becomes: ``` gallery/ ├── modules/ ← cross-app modules ├── bundles/ ← cross-app bundles └── apps/ ├── freshcloud-mail/ ← platform app (FreshCloud) ├── vibecoder-standalone/ ← sovereign consumer (kind: "app", code_location: "external") ├── freshcards-standalone/← sovereign consumer ├── vibescope-standalone/ ← sovereign consumer ├── fvs/ ← sovereign consumer (kind: "app", code_location: "external") └── ... ``` Each `apps//` has: - `module.json` with `kind: "app"`, `code_location: "gallery" | "external"`, `source_location: "..."` (if external) - `recipe-book/` (always) - `modules/` (if app has internal modules) - `src/` (if `code_location: "gallery"`) --- ## 3. The constitutional rule (final) > **Every gallery entry has a recipe book in the gallery.** Always. Non-negotiable. The recipe book is the constitutional shape. > > **Location is the discriminator:** > - `gallery/modules//` → cross-app module (promoted) > - `gallery/bundles//` → cross-app bundle > - `gallery/apps//` → app (sovereign consumer OR platform app) > - `gallery/apps//modules//` → app-internal module (not promoted) > - `gallery/apps//bundles//` → app-internal bundle > > **Code defaults to "in the gallery"** for new modules. Code may be external if the entry is too large or sovereign. The `code_location: "gallery" | "external"` field declares it. > > **Promotion rule**: a module lives at `apps//modules//` until 2+ apps use it, at which point it can be promoted to `modules//`. The operator decides when to promote. --- ## 4. The "tag it differently" rule (operator's insight, refined) The operator said: "if a module has code in it, it needs to be tagged in one way. Well if it's only got recipe books then it means to be typed in another way." **Refined: it's not about code vs no-code, it's about location + code_location:** | Path | What | `kind` | `code_location` | |---|---|---|---| | `gallery/modules/ai-toast/` | cross-app module, code in gallery | `module` | `gallery` | | `gallery/modules//` (hypothetical) | cross-app module, code elsewhere | `module` | `external` | | `gallery/bundles/ai-bundle/` | cross-app bundle | `bundle` | n/a | | `gallery/apps/freshcloud-mail/` | platform app, code in freshmail-2 | `app` | `external` | | `gallery/apps/vibecoder-standalone/` | sovereign app, code in vibecoder-standalone | `app` | `external` | | `gallery/apps//modules/mail-engine-smtp/` | app-internal module | `app-internal-module` | `gallery` or `external` | | `gallery/apps//bundles/freshcloud-mail-engine-bundle/` | app-internal bundle | `app-internal-bundle` | n/a | **The "tag" is the path + the `kind` field together.** No new "code_location" discriminator needed beyond what's already in v1. --- ## 5. The freshcloud-mail migration (revised) Per the v1 plan, freshcloud-mail would be at `gallery/apps/freshcloud-mail/` with `code_location: "external"`. The 17 mail-engine modules would also be at `apps/freshcloud-mail/modules//`, NOT at top-level. **Why this is right:** - The 17 modules are mail-specific. They don't generalize. They don't promote. - Putting them at `gallery/modules/` would inflate the registry with non-reusable entries - The recipe books still live in the gallery (in the right subdirectory) - The 17 modules are discoverable *through* the freshcloud-mail app entry - The freshcloud-mail-engine-bundle is an internal bundle that lists them **One concern**: what if someone in the future wants to use a single mail-engine module in another app? Then it gets *promoted* — moved to `gallery/modules/mail-engine-smtp/`, with a `promoted_from: "apps/freshcloud-mail/modules/mail-engine-smtp"` field in `module-meta.json` for traceability. --- ## 6. What about VibeCoder being a "collection of modules"? The operator said: "apps can sometimes be a collection of modules in the gallery already eg vibecoder has many modules" I now think this means: VibeCoder is a *consumer* of many gallery modules (its 11 chrome/AI modules). It's a "collection of modules" in the sense that it composes them. The modules themselves are at `gallery/modules/`. VibeCoder itself doesn't need to be at `gallery/apps/vibecoder-standalone/` *unless* it has its own internal modules that aren't in the gallery. But per my refined recommendation, sovereign consumers SHOULD be in the gallery as `apps//` with `code_location: "external"`. So VibeCoder would be at `gallery/apps/vibecoder-standalone/` with: - A recipe book (for reference — VibeCoder's constitutional shape) - A `module.json` with `kind: "app"`, `code_location: "external"`, `source_location: "avidtech6/vibecoder-standalone"` - An empty `modules/` (because VibeCoder's modules are all in `gallery/modules/`, not internal) - A note in `module-meta.json`: "consumer of: [ai-toast, ai-mic, ai-stt, ...]" This way VibeCoder is discoverable in the gallery, and you can see "this app uses these gallery modules" by looking at its entry. --- ## 7. Comparison: v1 vs v2 | Question | v1 (wrong) | v2 (revised) | |---|---|---| | Where do freshcloud-mail's 17 modules live? | `gallery/modules/mail-engine-*/` (top-level) | `gallery/apps/freshcloud-mail/modules/mail-engine-*/` (internal) | | What's the "slightly different case" for freshmail? | "It's an app, not a module" | "Its modules are mail-specific, not cross-app" | | Is VibeCoder a gallery entry? | Not addressed | Yes, as `gallery/apps/vibecoder-standalone/` with `code_location: "external"` | | Is there an `apps/` folder? | Yes (new) | Yes (new), with both platform apps and sovereign consumers | | Promotion rule? | Not stated | Stated explicitly: "promoted when 2+ apps use it" | --- ## 8. Open questions (revised) 1. **The promotion threshold** — is "2+ apps" right, or should it be "explicitly promoted by operator"? I'd say operator, since the operator knows the strategic intent. 2. **Sovereign consumer apps** — should all sovereign consumers be in the gallery? Or only those that have internal modules? My recommendation: all, for discoverability. 3. **The freshcloud-mail-engine-bundle** — is it an "app-internal bundle" or just a regular bundle listed at `gallery/bundles/`? My recommendation: internal, because it lists app-internal modules. 4. **The promotion direction** — when a module gets promoted, does its OLD location (inside the app) become a pointer, or does the code get deleted? My recommendation: pointer (for backwards compat), with `promoted_to: "gallery/modules//"`. 5. **The 17 mail-engine modules and `code_location`** — should the small ones (e.g. simple IMAP wrapper) be vendored into the gallery, and the large ones (e.g. SMTP server) stay external? Or all external because freshmail-2 is the source of truth? My recommendation: all external for now, with the recipe book in gallery. Promotion to gallery code can happen later if specific modules are reused. --- ## 9. What to do next (revised) ### Step 1: Operator approval Read this doc, confirm or amend the promotion rule + the apps/ folder scope. ### Step 2: Add FVW v8.2 doctrine Section: "Gallery Entry Shapes (Revised)" — covers the promotion rule, the apps/ folder, the location-based discrimination. Update CHANGELOG (v8.2 minor bump). ### Step 3: Add `apps/` to the gallery - Create `gallery/apps/` folder - Write `apps/README.md` documenting the pattern (both platform apps and sovereign consumers) - Update registry schema to include `kind: "app"`, `kind: "app-internal-module"`, `kind: "app-internal-bundle"` ### Step 4: Migrate freshcloud-mail (the test case) - `gallery/apps/freshcloud-mail/` with the structure from §2 - 17 modules at `apps/freshcloud-mail/modules//` - 1 bundle at `apps/freshcloud-mail/bundles/freshcloud-mail-engine-bundle/` - Recipe book pulled from `avidtech6/freshmail-2/recipes/` - Update `registry.json` ### Step 5: Migrate other apps (sweep) - `gallery/apps/vibecoder-standalone/` (code_location: "external") - `gallery/apps/freshcards-standalone/` - `gallery/apps/vibescope-standalone/` - `gallery/apps/fvs/` (FreshVibeStudio — recipe book is for reference, code is in freshvibestudio) - Each is small: just module.json + recipe-book/ + module-meta.json - This is optional but recommended for discoverability ### Step 6: Sync workflow For entries with `code_location: "external"`, sync the recipe book from `source_location/recipes/` to the gallery copy. Daily cron + webhook. ### Estimated effort - Step 1: 0 (read this doc) - Step 2: 1 hour (FVW v8.2 doctrine) - Step 3: 1 hour (apps/ + registry schema) - Step 4: 3-4 hours (freshcloud-mail migration + 17 modules) - Step 5: 2-3 hours (sweep all 5 apps) - Step 6: 1-2 hours (sync workflow) - Total: ~10 hours, can be spread over a week --- ## 10. The "app gallery" question, again **Was there an app gallery built?** No (confirmed earlier). **Should there be one?** Yes, as `apps/` in the existing `avidtech6/fv-module-gallery`. **What goes in it?** Sovereign consumer apps + platform apps + their internal modules/bundles. **Is this the same as the module gallery?** Yes — one gallery, three top-level folders: `modules/`, `bundles/`, `apps/`. --- ## Related docs - `/workspace/position-gallery-entry-shapes-recipes-and-code.md` (v1, superseded) - `/workspace/gallery-investigation.md` - `/workspace/canonical-home-proposal.md` - `/workspace/facets-in-fvw-v8.md` - `/workspace/recipe-book-shape.md` - `/workspace/audit/freshcloud-mail-recipes/README.md` (recipes merged into freshmail-2 on 2026-07-21) - `avidtech6/fv-module-gallery/gallery-pact/registry-plan.md` (the gallery's design doc)