# Gallery Entry Shapes — Recipes vs Code (Position) > **Status**: DRAFT for operator review (2026-07-22) > **Author**: Mavis > **Scope**: How should gallery entries (modules, bundles, apps) be shaped? Should the gallery hold all the code, or just the constitutional metadata? Where do recipe books live? > **Trigger**: Operator's 2026-07-22 thread re: freshcloud-mail being "more than a module, more than a bundle, an app" — and Plan B's "metadata + source_location pointer" being too thin. --- ## TL;DR The operator's instinct is right. The Plan B version is too thin (just metadata + pointer), but the opposite extreme (all code in gallery) is wrong. The right answer is the **middle path** with **typed entries**: - **Every gallery entry has a constitutional core in the gallery** (recipe book + meta + identity) - **Some entries also have their code in the gallery** (the source code lives there too) - **Some entries are external** (the code lives in another repo, the gallery entry is a pointer + recipe book) - **The `kind` field** in `module.json` tells you which one it is - **Recipe books always live in the gallery** — that's non-negotiable. They are the constitutional shape. freshcloud-mail is the test case that proves the pattern. It's an app, so it gets an `apps/` folder in the gallery (new tier), and its `kind: "app"` entry has the recipe book + a `source_location` pointer to `avidtech6/freshmail-2/`. --- ## 1. Restating the operator's thinking (so I get it right) The operator is wrestling with three tensions: 1. **Tension 1: Where does the code live?** - "Do we want all the code literally inside the gallery?" - "But if the code is [in the gallery], at least we still want to have the recipe books." - "I guess 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 tagged in another way." 2. **Tension 2: How thin is too thin?** - "This is saying the gallery entry is just the constitutional metadata + a source_location pointer. But I think this is too minimal." - "I think [it's] fine to have [a] point to another location, another repo. But I think we should still expose that the shape of it is in the gallery and modules. At least just the recipes are in the gallery." 3. **Tension 3: Constitutionality** - "Make this constitutional, whatever. This is thinking is this a good idea of how it should work because it's right and not always." - The operator wants this to be a **rule**, not a one-off. The pattern should be derived and stable. The key insight from the operator: **recipe books must always be in the gallery. Code can be in or out. The "in or out" decision is the only thing that varies.** --- ## 2. The current state (honest) | Repo / location | What it has | Gallery entry? | |---|---|---| | `avidtech6/ai-shell` | Chrome source code (Toast, Mic, STT, etc.) | Some modules proposed (`ai-bundle`), only `ai-toast` extracted | | `avidtech6/oscar-platform` | Engine source (assistant, orchestrator) | Some modules proposed, none extracted | | `avidtech6/freshmail-2` | Full PHP app (IMAP, SMTP, etc.) + recipe books merged in (`recipes/engine/`) | **NOT in gallery yet** — Plan B proposed but unbuilt | | `avidtech6/freshcloud-mail` | PHP bridge (stub) | **NOT in gallery yet** — sibling of freshmail-2 | | `avidtech6/freshvibestudio` (fvs) | The Studio source + the FVW canon | FVW v8 is now mirrored to gallery (per D-2026-07-22) but fvs itself is not gallery-registered | | `avidtech6/smartpantry-app` | App source + per-module recipe books | NOT in gallery | | `avidtech6/oscar-web` | App source | NOT in gallery | **The pattern is unclear.** Some apps (like fvs) are sovereign and have their own pact. Some apps (like smartpantry, freshcloud-mail) are downstream consumers. Some are FVW canon. The gallery doesn't have a consistent "is this thing in me or not?" rule. --- ## 3. The three (and a half) shapes a gallery entry can take Here's the model I'd propose. The `kind` field in `module.json` (or a new top-level `kind` discriminator) tells you which shape: ### Shape 1: `kind: "module-code"` — code + recipes in the gallery The most common shape. Module IS in the gallery, code IS in the gallery. **Example**: `ai-toast` (already done — the only one that exists today) ``` modules/ai-toast/ ├── module.json # kind: "module-code", tier, tags ├── module-meta.json # versioned metadata ├── facets.json # visibility slices ├── package.json # npm package ├── recipe-book/ # FVW §11 (3+5+2 = 10 items) ├── src/ # the actual code │ ├── default/ # public facet exports │ └── .private/ # private internals └── test-cases/ ``` **Use when**: Module is generic enough that the gallery should be its home. Code is small enough to vendor. ### Shape 2: `kind: "module-recipe-only"` — recipes in gallery, code in another repo The pointer pattern. The recipe book lives in the gallery; the actual code lives in the source repo. **Example**: (hypothetical) `oscar-card-primitive` — the recipe is in the gallery, but the code lives at `avidtech6/oscar-platform/src/card-primitive/` ``` modules/oscar-card-primitive/ ├── module.json # kind: "module-recipe-only", source_location: "..." ├── module-meta.json # versioned metadata, source_location ├── facets.json # (optional — visibility slices for the recipe) ├── recipe-book/ # FVW §11 (3+5+2 = 10 items) — IN THE GALLERY │ ├── recipe.md │ ├── codex.md │ ├── rules.md │ ├── module-meta.json │ ├── ingredients.json │ ├── diffs/ │ ├── trace-atlas/ │ ├── dna/ │ ├── plan.md │ └── coverage-matrix.md └── NO src/ # code is elsewhere ``` **Use when**: The code lives in a sovereign app (like fvs) and we don't want to fork it into the gallery. But the recipe book is still constitutional and should be discoverable. ### Shape 3: `kind: "app"` — full app, recipes + code in the gallery The freshcloud-mail case. The app is a first-class gallery citizen, with the same recipe-book structure but at the app level, and the code lives alongside. **Example**: (proposed) `freshcloud-mail` in `apps/freshcloud-mail/` ``` apps/freshcloud-mail/ ├── module.json # kind: "app", tier, tags (incl. "app") ├── module-meta.json # versioned metadata ├── facets.json # (optional — proprietary bits) ├── package.json # (composer.json for PHP, package.json for Node) ├── recipe-book/ # FVW §11 (3+5+2 = 10 items) — IN THE GALLERY │ ├── recipe.md # describes the app │ ├── codex.md # app-level behaviour │ ├── rules.md # app-level workflow │ ├── module-meta.json │ ├── ingredients.json │ ├── diffs/ │ ├── trace-atlas/ │ ├── dna/ │ ├── plan.md │ └── coverage-matrix.md ├── src/ # the actual app code — IN THE GALLERY │ ├── Mail/ # (FreshCloud\Mail\*) │ └── ... ├── tests/ # PHPUnit / Jest / etc └── api/ # (the bridge endpoints) ``` **Use when**: The app is small enough / clean enough to be vendored in the gallery. OR the app is generic enough that someone else might want to use it as a reference. **Important**: This is the case where Plan B's "metadata + source_location pointer" is **wrong**. Plan B said "PHP code lives in `avidtech6/freshmail-2/`, but the gallery entry is just the constitutional metadata + a source_location pointer." That's Shape 2 thinking, applied to an app. It doesn't fit because: - The app is not a sub-thing. It's sovereign. - Its recipe book is not a reference for reconstruction. It IS the source of truth. - The pointer-only entry would mean the gallery has no way to render the app, validate the recipes, or run tests. So the app case is **Shape 3** (full app, code + recipes in gallery), and the gallery needs an `apps/` folder, parallel to `modules/` and `bundles/`. ### Shape 3.5: `kind: "app-recipe-only"` — full app, recipes in gallery, code in another repo The case where the app is large / has proprietary code / is sovereign, and the gallery just has the recipe book + a pointer. **Example**: (hypothetical) `fvs` (the Studio) — the recipe book lives in the gallery as a reference, the code lives at `avidtech6/freshvibestudio/` ``` apps/fvs/ ├── module.json # kind: "app-recipe-only", source_location: "..." ├── module-meta.json ├── recipe-book/ # IN THE GALLERY (3+5+2 = 10 items) └── NO src/ # code lives in freshvibestudio/ ``` **Use when**: The app is large and sovereign. We want the gallery to be able to discover and reference it, but the code is too big or too proprietary to vendor. This is the case where the operator's "metadata + source_location pointer" thinking was originally going. But **only** for large/sovereign apps, not for normal cases. --- ## 4. The constitutional rule (the part the operator wants "right") Per the operator's directive: "make this constitutional, whatever." **Rule** (proposed for FVW v8.2 §17.5 or similar — `gallery_entry_shapes`): > **Every gallery entry has a constitutional core in the gallery.** > The constitutional core is the recipe book (FVW §11: 3 main + 5 provenance + 2 workflow = 10 items) plus the identity (module.json, module-meta.json, facets.json). > > The `kind` field in `module.json` determines the **code** location: > > - `kind: "module-code"` → code lives in `/src/` > - `kind: "module-recipe-only"` → code lives in `source_location` (another repo) > - `kind: "app"` → code lives in `/src/` > - `kind: "app-recipe-only"` → code lives in `source_location` (another repo) > - `kind: "bundle"` → no code of its own; lists sub-entries > > **Recipe books ALWAYS live in the gallery.** This is non-negotiable. The recipe book is the constitutional shape of the entry. The gallery's job is to be the discoverable home of constitutional shapes. > > **Code MAY live in the gallery or in another repo.** The `source_location` field declares the canonical code home (which may be the gallery itself for `*-code` and `app` kinds, or another repo for `*-recipe-only` kinds). > > **Code in the gallery is the default for new modules.** Code in another repo is the exception, and requires a `justification` field in `module-meta.json`. The last clause is important: **default is "code in gallery"**, not "code elsewhere". This is the constitutional direction. Plan B was wrong to assume the default is "code elsewhere" — it should be the opposite. --- ## 5. How freshcloud-mail fits (the test case) freshcloud-mail is the test case. Per the operator's instinct, it's an app, not a module. So: ### Proposed: `apps/freshcloud-mail/` in the gallery ``` apps/freshcloud-mail/ ├── module.json # kind: "app", tier: "off-the-shelf", tags: ["app", "mail", "freshcloud"] ├── module-meta.json # versioned metadata ├── facets.json # (optional — proprietary bits) ├── package.json # composer.json symlink or copy ├── recipe-book/ # FVW §11 (3+5+2 = 10 items) — IN THE GALLERY │ ├── recipe.md │ ├── codex.md │ ├── rules.md │ ├── module-meta.json │ ├── ingredients.json │ ├── diffs/ │ ├── trace-atlas/ │ ├── dna/ │ ├── plan.md │ └── coverage-matrix.md ├── src/ # FreshCloud\Mail\* — IN THE GALLERY (Shape 3) ├── tests/ └── api/ ``` But wait — freshcloud-mail is **huge** (PHP, IMAP, SMTP, CalDAV, CardDAV, WebDAV). Putting all of that in the gallery might be too much. So: ### Alternative: `kind: "app-recipe-only"` with the existing `avidtech6/freshmail-2/` as `source_location` ``` apps/freshcloud-mail/ ├── module.json # kind: "app-recipe-only", source_location: "avidtech6/freshmail-2" ├── module-meta.json ├── recipe-book/ # IN THE GALLERY (10 items) └── NO src/ # code is in freshmail-2 ``` This is the Plan B version, **but with the recipe book in the gallery**, not just metadata. So it's Plan B with the constitutional core added. ### Which one is right? I'd argue **the alternative** (app-recipe-only with full recipe book) is the right shape for freshcloud-mail. Reasons: 1. **freshmail-2 already merged the recipes into itself** (per the 2026-07-21 archive of freshcloud-mail-recipes). The doctrine lives with the code there. Vendoring the recipe book into the gallery would create a duplicate and a sync problem. 2. **freshcloud-mail is large**. It's not a small lego block. It's a full app. Vendoring the entire PHP codebase into the gallery would bloat the gallery to gigabytes and create merge conflicts every time freshmail-2 updates. 3. **The recipe book IS the constitutional shape**. It can live in the gallery (read-only, synced from freshmail-2/recipes/) while the code lives in freshmail-2. The gallery has the constitutional view; freshmail-2 has the implementation view. Both stay in sync via the existing FVW §37 (Lego blocks) sync model. 4. **The other 17 modules** (`mail-engine-smtp`, `mail-engine-imap-client`, etc.) would each be their own gallery entry with `kind: "module-recipe-only"` (or `module-code` if they're small enough). They form a bundle `freshcloud-mail-engine-bundle` that lists all 17. ### The "tag it differently" rule (the operator's insight) Per the operator: "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." This IS the `kind` field. But I want to suggest **two orthogonal axes**, not one: - **`kind`** — what is it? (`module`, `app`, `bundle`) - **`code_location`** — where does the code live? (`gallery`, `external`) This is cleaner than overloading `kind`. Examples: | Entry | `kind` | `code_location` | |---|---|---| | `ai-toast` | `module` | `gallery` | | `oscar-card-primitive` (hypothetical) | `module` | `external` | | `freshcloud-mail` | `app` | `external` | | `freshcloud-mail` (if vendored) | `app` | `gallery` | | `ai-bundle` | `bundle` | n/a | | `freshcloud-mail-engine-bundle` | `bundle` | n/a | The `code_location: "external"` entries MUST have a `source_location` field pointing to the canonical code home. The `code_location: "gallery"` entries have their code in the gallery and don't need `source_location`. The `kind: "bundle"` entries don't have code of their own; they have a manifest of sub-entries (which may be any of the above). --- ## 6. The recipe-book-sync model (the bit the operator didn't quite say but I think wants) The operator said: "Have a think about it. And then. Recipes are synced to whatever the other repo is." This implies the operator wants **bidirectional sync** between the gallery recipe book and the source repo. Let me think about this: ### Two sync directions **Direction 1: Gallery → source repo** - The recipe book is in the gallery (canonical) - The source repo has a `recipe-book/` folder that's a copy - A workflow in the gallery pushes recipe book updates to all source repos - Source repos that have `code_location: "external"` get auto-updates of their recipe book **Direction 2: Source repo → gallery** - The recipe book is in the source repo (canonical) - The gallery has a copy that's auto-pulled - A workflow in the source repo (or in the gallery, polling) pulls recipe book updates **Which is canonical?** I think **the gallery is canonical for the constitutional shape** (the recipe book) and **the source repo is canonical for the implementation** (the code). The recipe book is the meta of the code; the code is the implementation of the recipe book. So the recipe book can be canonical in one place and mirrored to the other. For freshcloud-mail, the source repo (`freshmail-2`) is the "everything" repo (code + recipes per the 2026-07-21 merge). The gallery entry has a copy of the recipe book that's pulled from `freshmail-2/recipes/`. If the source repo updates the recipe book, the gallery's copy is updated by a sync workflow. **For new modules**, the gallery is the default home (Shape 1: code + recipes in gallery). The source repo doesn't exist; the gallery IS the source. **For external apps** (like freshcloud-mail, like fvs), the source repo is the "everything" home. The gallery has a copy of the recipe book that's pulled from there. This is a **hybrid canonicality model**: constitutional shape is canonical in the gallery, implementation is canonical in the source repo, and the two stay in sync via workflow. --- ## 7. The "app gallery" question — was there one built? **No.** Searched `/workspace` for "app gallery" / "app-gallery" / `app.gallery` — zero hits. The only "gallery" is the **module gallery** (`avidtech6/fv-module-gallery`), which has `modules/`, `bundles/`, and `gallery-pact/`. There is no `apps/` folder in the gallery, no `app-tier` in the registry schema, no app-gallery concept written down. **However**, the doctrine already has the building blocks: - `kind: "app"` is in the module.json tags (§17.2). Modules can be tagged `app`. - But there's no top-level `apps/` namespace in the gallery. **Recommendation**: add an `apps/` folder to the gallery, parallel to `modules/` and `bundles/`. This is the "app gallery" — the home for full apps, not just modules. Each app entry has a recipe book (FVW §11) at the app level, and code either in `apps//src/` (Shape 3) or in `source_location` (Shape 3.5). This is a small addition to the gallery. It doesn't require any new FVW v8.1 doctrine. It just requires: - Add `apps/` folder to the gallery - Update the registry schema to allow `kind: "app"` - Write the `apps/README.md` documenting the pattern - Move freshcloud-mail (or its recipe book) to `apps/freshcloud-mail/` --- ## 8. The position (my recommendation, summarised) **The gallery is the constitutional home of all FVW-shaped things** (modules, apps, bundles). For each: 1. **The recipe book is always in the gallery.** This is non-negotiable. 2. **The code is in the gallery by default** (`code_location: "gallery"`). 3. **The code is external if the entry is too large or sovereign** (`code_location: "external"`, with `source_location` pointing to the source repo). 4. **`kind`** discriminates between module / app / bundle. 5. **`code_location`** discriminates between gallery / external. 6. **Sync workflows** keep the gallery recipe book and the source repo recipe book in sync. 7. **For freshcloud-mail**: `kind: "app"`, `code_location: "external"`, `source_location: "avidtech6/freshmail-2"`, recipe book pulled from `freshmail-2/recipes/`. This satisfies: - "Make this constitutional" → it's a rule (FVW v8.2 §17.5 or similar) - "Recipe books in the gallery" → yes, always - "If a module has code, tag it one way" → `code_location: "gallery"` - "If only recipe books, tag another way" → `code_location: "external"` - "Pointer to another location is fine" → yes, with `source_location` - "Don't want all the code in the gallery" → right, by default; only for small/generic things - "Make the constitutional shape discoverable" → recipe book in gallery = discoverable The Plan B "metadata + pointer" version is too thin because it leaves the recipe book out. The opposite extreme (all code in gallery for everything) is also wrong because it bloats the gallery with code that already has a home. The middle path is: **recipe books always in gallery, code in gallery or external, kind + code_location tells you which**. --- ## 9. What to do next (proposed plan) ### Step 1: Get operator approval on the position - Read this doc - Confirm or amend the 4-shape model - Confirm the rule (recipe books always in gallery, code_location default = gallery) - Confirm the `kind` + `code_location` split ### Step 2: Write the constitutional rule - Add FVW v8.2 §17.5 (or whatever number) to the doctrine - The section: "Gallery Entry Shapes" — 4 kinds, recipe books always in gallery, code_location rule - Update CHANGELOG (FVW v8.2 minor bump) ### Step 3: Add `apps/` to the gallery - Create `apps/` folder in `avidtech6/fv-module-gallery` - Write `apps/README.md` documenting the pattern - Update the registry schema to allow `kind: "app"` ### Step 4: Migrate freshcloud-mail to the gallery (as the first app) - Create `apps/freshcloud-mail/` in the gallery - Set `kind: "app"`, `code_location: "external"`, `source_location: "avidtech6/freshmail-2"` - Pull the recipe book from `freshmail-2/recipes/` (via workflow or manual) - Add the 17 mail-engine modules as `kind: "module-recipe-only"` entries - Update `registry.json` to include the 17 modules + 1 app + 1 bundle ### Step 5: Set up the sync workflow - `fv-module-gallery/.github/workflows/sync-recipe-books.yml` - For every entry with `code_location: "external"`, pull the recipe book from `source_location/recipes/` and update the gallery copy - Run on a schedule (daily) and on webhook from source repos ### Step 6: Migrate other large apps (optional, later) - fvs: `apps/fvs/` with `kind: "app-recipe-only"` (or whatever the v3.5 kind is) - smartpantry: `apps/smartpantry/` with `kind: "app-recipe-only"` - docHub: `apps/dochub/` with `kind: "app-recipe-only"` - These are parked, not in current sprint ### Estimated effort - Step 1: 0 (read this doc) - Step 2: 1 hour (write FVW v8.2 §17.5) - Step 3: 30 min (create apps/ + registry schema update) - Step 4: 2-3 hours (migrate freshcloud-mail + 17 modules) - Step 5: 1-2 hours (write sync workflow) - Step 6: parked --- ## 10. The "app gallery" question, restated **Was there an app gallery built?** No. **Should there be one?** Yes — call it `apps/` in the existing `avidtech6/fv-module-gallery`. It's a parallel folder to `modules/` and `bundles/`, not a separate repo. **What goes in it?** Full apps, with their recipe books (always) and code (sometimes). The pattern is the same as modules, just at the app level. **Is this the same as the module gallery or a separate thing?** Same. One gallery, three folders: `modules/`, `bundles/`, `apps/`. The gallery UI (`fv-gallery-ui`) needs a new route to browse `apps/`, parallel to the modules route. --- ## Open questions for operator 1. **The 4-shape model** — is this the right shape count? Or should Shape 3 and 3.5 collapse into one? 2. **The `kind` + `code_location` split** — too granular? Should it be just `kind` with sub-types? 3. **The "app gallery" naming** — keep it as `apps/` in the existing gallery, or call it a separate thing? 4. **The freshcloud-mail test case** — is `code_location: "external"` (with the recipe book in gallery) the right shape, or should we vendor the code into the gallery too? 5. **The sync direction** — gallery pulls from source repo, or source repo pushes to gallery? Or both? 6. **The FVW section** — should this be §17.5 (extension of modules-and-tiers) or a new section? --- ## Related docs - `/workspace/gallery-investigation.md` — the gallery state today (1 of 11 modules extracted, no apps folder) - `/workspace/canonical-home-proposal.md` — the FVW canonical home is the gallery (D-2026-07-22) - `/workspace/facets-in-fvw-v8.md` — facets are proposed but not written into FVW v8 - `/workspace/recipe-book-shape.md` — the recipe book is 10 items, not 3 - `/workspace/audit/freshcloud-mail-recipes/README.md` — the recipes were merged into freshmail-2 on 2026-07-21 - `avidtech6/fv-module-gallery/gallery-pact/registry-plan.md` — the 5-layer registry model (the gallery's design doc, not in /workspace yet)