Menura Manual, as shipped in the download
Menura — User Manual
Menus and price lists turned into structured, exportable items. Version 3.1.4 [src: app/controllers/api.php:71].
About this manual
Every statement here was written by reading Menura's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.
Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out — which matters more here than in most products, because one of the fields is allergens.
What Menura is
A menu or wholesale price list goes in as a photograph or a PDF. A vision model reads it. What comes out is a clean, canonical menu: sections, names, descriptions, integer-cent prices, modifiers, allergens and dietary flags [src: app/controllers/mcp.php:42].
The model reads; a deterministic layer does the structuring, with no network call, so the structure and the prices you export are trustworthy regardless of which model produced them [src: app/src/Extraction.php:8].
Nothing in that layer touches the database or the network, which is what makes the money and menu-structure logic testable with no API key at all [src: app/src/Extraction.php:11].
⚠️ Allergens: Menura reports gaps and never guesses
This is the most important thing in the product, and the source states it without hedging.
The allergen report tells you which items have no allergen data recorded. It is completeness only — it reports gaps, and it never infers an allergen [src: app/controllers/mcp.php:143].
The report carries its own explanation, and it is worth quoting in full because it is the right policy: "Gaps only. Menura never infers an allergen — a wrong allergen claim is a safety issue, so an unknown stays unknown until a person fills it in." [src: app/controllers/mcp.php:165]
An empty allergen list therefore means "nobody has recorded this yet", never "this dish contains nothing". Treat a gap as work outstanding, not as an answer.
Prices
Prices parse to integer cents from the formats a menu actually uses — $12.50, 1.234,56 €, spaces as thousands separators, parentheses or a leading minus for negatives, and raw numbers [src: app/src/Extraction.php:30].
"Market Price", "MP" and an em dash return nothing rather than zero, so the item shows as price-on-request [src: app/src/Extraction.php:31]. A dish with no fixed price never becomes a free one.
Lists — modifiers, allergens, dietary flags
All three are normalised the same way [src: app/src/Extraction.php:144]. A comma, semicolon, pipe or newline-delimited string is accepted, as is an array of strings or of objects.
The rules are worth knowing because they determine what your export looks like:
- Entries are trimmed and blanks dropped.
- Duplicates are removed case-insensitively, and the first spelling wins.
- Input order is preserved.
- Each entry is clipped to 190 characters and the list capped at 50 — both to defend the database row against oversized model output [src: app/src/Extraction.php:148].
Menu status
A menu moves uploaded → extracted → reviewed, with extracting and error as the states in between [src: app/controllers/mcp.php:44]. A human reviews what the model extracted; "reviewed" means a person has checked it.
Exporting
Three shapes [src: app/src/Extraction.php:316]:
Nested CSV — the rich export, keeping section, modifiers, allergens and dietary columns [src: app/src/Extraction.php:313].
POS CSV — one clean row per sellable item with the minimal columns a point-of-sale system expects: SKU, name, category, price, description [src: app/src/Extraction.php:345]. The SKU is a stable slug of section plus name, so a re-import matches what you imported before [src: app/src/Extraction.php:343].
JSON — the full canonical structure [src: app/src/Extraction.php:378].
⚠️ The POS export carries no allergen columns
Stated because it is easy to miss and matters given the subject. The flat POS layout deliberately has no nesting and no modifier or allergen columns — the section becomes the category and that is all [src: app/src/Extraction.php:342].
If allergen data needs to reach your till system, the POS export is not the route. Use the nested CSV or the JSON.
Users and roles
Three roles [src: app/controllers/app.php:86]. The source names the point of the product's own reviewer seat: correcting what the model extracted, and exporting it [src: app/controllers/app.php:89].
This table was produced by executing the product's own permission function against every permission the routes ask for.
| Permission | viewer | member | admin |
|---|---|---|---|
menu.view and other .view permissions | yes | yes | yes |
audit.view | yes | yes | yes |
item.edit | — | yes | yes |
menu.export | — | yes | yes |
menu.upload | — | yes | yes |
extraction.run | — | — | yes |
menu.delete | — | — | yes |
settings.edit | — | — | yes |
team.manage | — | — | yes |
Running an extraction is admin-only [src: app/controllers/app.php:92], because it spends the owner's own model credits.
⚠️ The audit trail is readable by a viewer
Menura's viewer role is granted *.view — a wildcard rather than a list [src: app/controllers/app.php:90]. Because the audit permission is named audit.view, the wildcard matches it, so a viewer can read the audit trail.
The comment on the line below lists audit.view among what the admin role covers via its own wildcard [src: app/controllers/app.php:92], which reads as though it were admin-only. The behaviour and that comment do not agree, and the behaviour is what this manual describes. It has been raised against the product.
Backups follow the model
Menura's database backup downloads are permission-gated, requiring the settings permission [src: app/controllers/api.php:235]. A viewer cannot download the database.
The API and agent access
Five tools are exposed to an agent, of which one writes [src: app/controllers/mcp.php:47]: listing menus, menu detail, export rows and the allergen report on the read side; correcting an item on the write side.
Extraction is not available to an agent — it spends the owner's own model credits and is triggered from the application [src: app/controllers/mcp.php:45].
Models and files
The default model per provider is stated once: gpt-4o-mini for OpenAI, claude-haiku-4-5-20251001 for Anthropic and llama3.2-vision for Ollama [src: app/src/Llm.php:44]. A model the provider refuses — retired, misspelt, or not pulled into Ollama — fails with a message naming the model and the setting to change [src: app/src/Llm.php:76].
Anthropic and OpenAI read PDFs; OpenAI receives the PDF as a file part [src: app/src/Llm.php:104]. Ollama reads images only, so a PDF is refused before any call with a message to convert the pages to PNG or JPEG [src: app/src/Llm.php:96].
The QR menu
A reviewed menu can be published as a mobile page at /m/<code> on your own install, with a table QR code to print. The code is 24 random hex characters and stays the same if you take the page offline and publish it again [src: app/src/QrMenu.php:30]. Publishing and 86-ing need the item-editing permission [src: app/controllers/qrmenu.php:28]; the guest page needs no login and serves a menu only while it is published [src: app/controllers/qrmenu.php:52].
86 an item and it leaves the guest page at once; it stays on the menu, in the exports and in the PDF [src: app/src/QrMenu.php:52]. The guest page shows sections, names, descriptions, prices, modifiers, dietary tags and listed allergens, and nothing else [src: app/src/QrMenu.php:65]. It does not take orders or payments.
What Menura does not do
It never infers an allergen [src: app/controllers/mcp.php:165]. A gap stays a gap until a person fills it.
It does not tell you a dish is safe. It tells you whether anybody has recorded what is in it.
It does not price a "market price" dish [src: app/src/Extraction.php:31]. No price becomes no price, not zero.
It does not let an agent spend your model credits [src: app/controllers/mcp.php:45].
It does not carry allergens into the POS export [src: app/src/Extraction.php:342]. That layout is deliberately minimal.