Skip to content

Concepts

A recipe is a template. A batch is the truth.

Section titled “A recipe is a template. A batch is the truth.”

You never harvest exactly the 600g of reapers the recipe calls for. You got 340g. So a batch doesn’t reference your recipe’s ingredients, it copies them when you start, and then it’s yours to edit.

The upshot: editing a recipe next year never rewrites what’s printed on last year’s bottles. The batch’s ingredient list is frozen history; the recipe is a living template.

The copy runs the other way too. After a season of tweaking a batch’s list, Promote to recipe on the batch page copies its ingredients back into a recipe — either replacing the linked recipe’s list (“this is next year’s template now”) or forking a new recipe named after the batch, which the batch then links to as its first vintage. Only the list moves; the recipe’s description and method stay put. Promoting replaces rather than versions — Mash deliberately has no recipe-versioning machinery, because the batches themselves are the history.

Made a batch before you wrote the recipe? Link it after the fact: the batch edit page has a Recipe selector (link, change, or unlink any time). Linking is reference-only — the batch’s ingredients stay exactly as entered. The recipe page lists every batch made from it.

There is exactly one exception, and it’s deliberate: allergen flags. The “Contains” line on a bottle page (see Public pages & sharing) is derived live from the ingredient’s current flags, not a frozen copy on the batch. If you find out next month that an ingredient you’ve used for years actually contains soy, correcting it once in the recipe editor fixes every bottle page that ever used it — this year’s and last year’s — instead of leaving the old ones wrong. A safety correction is not “history”; it should propagate.

A recipe’s admin page lists every batch it has ever stamped — its vintages — side by side: lot code, made and bottled dates, days from made to bottled, yield, the Scoville estimate (with a ~ when it’s estimated rather than overridden), the vote tally, and the first pick date from any linked harvest. It’s the same idea a winery’s vintage chart is: one recipe, many years, and a batch’s rescaled amounts mean no two rows necessarily taste the same, on purpose.

Mistakes happen, and the admin has erasers — but they respect one rule: anything the public may have seen is never silently destroyed.

A batch that was never published and never announced has no bottle in the world pointing at it, so its edit page offers a Delete batch button. Deleting removes the batch and everything it owns — its log entries, ingredient list, and photos — for good.

Once a batch has been published or announced, delete is gone and Archive takes its place. Archiving drops the batch out of the admin batch list (a Show archived toggle brings it back) but leaves its /b/<slug> page exactly as it was — so a QR code already printed on a jar keeps working. Unarchive any time. A batch is never removed from the public shelf by archiving; that’s what unpublishing is for.

There’s also a year-end sweep: filter the batch list to one year (click a year group header) and, if any of that year’s batches are marked gone, the list offers to Archive all N ‘gone’ batches from that year in one click. No confirmation dialog — the sweep is just as reversible as archiving one batch at a time, via the Show archived toggle.

Recipes work the same way by a different measure. A recipe no batch was made from can be deleted outright (its ingredient list goes with it). The moment a batch references it, delete is refused — removing it would erase what those batches record being made from — and you archive the recipe instead (the checkbox in its editor). Archiving drops the recipe out of the “new batch” picker and out of the admin recipe list (a Show archived toggle brings it back), but every batch already made from it keeps pointing at it exactly as before. Unarchive any time.

Tell a batch what you actually picked and Mash rescales the rest of the recipe to match. Two kinds of amounts behave differently, on purpose:

  • Absolute amounts (600g peppers, 2 cups vinegar) scale proportionally.
  • Percentage amounts (“salt at 2% of mash weight”) stay put, because a ratio isn’t an amount. 2% salt is 2% salt whether you made one jar or ten.

Published batches show a Scoville estimate computed from the peppers you actually weighed, diluted by everything else in the jar. The same 340g of reapers is Extreme in a small ferment and merely Very hot stirred into three kilos of mango, and the gauge says so.

Mash ships a built-in catalog of roughly a hundred pepper cultivars — from bell peppers to Pepper X — and guesses an ingredient’s Scoville rating from its name, aliases and common misspellings included (“bhut jolokia” finds the Ghost Pepper’s rating). The values are typical midpoints from published Scoville charts, not lab measurements, which is one more reason the batch number reads as an estimate. A pepper the catalog doesn’t recognise counts as unknown — it adds mass (diluting the estimate) but no heat. To fix that, open Ingredients in the admin, expand the pepper’s row, and enter its SHU; every batch using that ingredient updates its estimate immediately. Blank means unknown, and 0 is a real value — a bell pepper has no heat, which is different from not knowing.

The public page shows what the batch is, by weight. Volume measurements convert (2 cups of vinegar is ~473g and counts toward the bar); anything that genuinely can’t be weighed, like “4 cloves of garlic”, is named beneath the bar rather than quietly dropped from it.

Every batch gets a human-readable lot code (REAPER-2607-A: recipe, year+month, batch letter) and a QR code pointing at its public page. Lot codes use your local month, so set TZ (Configuration).

Batch URLs contain a random token, so they can’t be guessed or enumerated. An unpublished batch returns a plain 404 to the public; see Public pages & sharing.

Say where a pepper came from, and the bottle page links to the seed listing so the person holding the jar can grow their own.

Start typing in any ingredient row and a dropdown offers your pantry: matches ranked with honest prefixes first, and enough typo tolerance that pablano still finds Poblano Pepper. Each match whispers its kind, its usual unit, and how many purchase links are saved for it. Picking one fills the name, the unit (if you haven’t typed one), the kind (in a recipe), and lights up its saved links — no retyping what Mash already knows.

Typing something genuinely new is still fine: whenever the dropdown shows near-matches without an exact one, its last row is + Add “…” as a new ingredient, so creating a near-duplicate is a deliberate choice rather than a typo’s side effect. A name with no matches at all just stays a normal field — new ingredients are created on save, like always.

Type a source URL into any ingredient row — recipe or batch — and Mash remembers it against that ingredient, because seed listings move around season to season and last year’s link is worth having back. Type the same ingredient name again later and its + link disclosure grows a count, + link (2 saved), with a row of chips underneath: click one and it fills the URL and label for you, no retyping or re-Googling a supplier. Nothing submits until you save the row like normal.

Admin → Ingredients lists every saved link by ingredient, for editing, deleting, or adding one by hand — useful when a listing goes stale and you want to swap it without touching a recipe or batch. Above those link cards, a summary table lists every ingredient Mash knows about — icon, kind, Scoville rating, flagged allergens, and how many links are saved for it — a single reference view instead of paging through recipes to remember what “Midnight Reaper” was rated at.

A harvest is a diary entry: what you picked, when, how much, and an optional note or photo. Log one from Admin → Harvests, then link it to a batch — batch-level, not per-ingredient, because the batch form rewrites its whole ingredient list on every save, and a link hung off one ingredient row wouldn’t survive that. The link is purely informational; it never touches amounts or scaling.

Nothing about a harvest is public by default. Toggle “Show harvest dates” on a batch and its linked harvests appear on the bottle page as a Picked line — ingredient name and date only. The weight and any note stay in the admin.

Set yield on a batch once you’ve bottled it: a container count (how many jars, bottles, or whatever you filled) plus an optional word describing the container (“jars” by default, or “bottles”, “pints”, anything you type — it’s just a label and doesn’t affect the arithmetic). The count is what drives the public Yield stamp on the bottle page; the word is display-only. If you need to note a total volume (“about 3 quarts total”), put that in the batch’s story — it’s not a separate tracked field. Yield is a plain count on the batch — Mash doesn’t track what happened to any individual jar after that.

If you’re upgrading from an older version of Mash that tracked yield as a raw quantity, the migration copies over whole, non-negative numbers as the new container count automatically. Any yield that was a volume (like 1.5) or otherwise couldn’t map cleanly to a count is left alone on the batch — the old value and unit are appended as a line in the batch’s story instead, so nothing is silently lost.

Every published batch’s public page carries a small Want a bottle? form — name, email, and an optional note, nothing else. Submitting it lands the request in Admin → Community → Requests, newest first, with an open-count badge on the Community nav so a new ask doesn’t get lost. Asking again for a batch you’ve already asked about (same email, still open) is deduped silently — the visitor sees the same confirmation either way, and Mash never confirms or denies what the requests table already holds.

Complete marks a request done and, if SMTP_URL is configured, emails the requester that their bottle is set aside; without mail configured it’s plain bookkeeping — a checklist of who to hand a jar to. Reopen undoes a mistaken complete (completing again sends another email). Delete removes the row for good. A completed request never blocks a new one for the same batch — asking again next batch-cycle is the point.

Bottle requests are never connectable to votes or comments: the requests table joins only to batches, with no relationship to any public artifact, and there are no per-jar serials. Who asked for a jar and what the anonymous feedback says are non-correlatable by construction, even to you.