`.recipe` package format v1
Draft technical specification for portable recipe packages. This document defines the archive layout, required JSON members, media references, compatibility rules, and importer behavior used by Do-Re-Ci-Pe.
This version
https://dorecipe.app/open-standard/spec
Latest published version
https://dorecipe.app/open-standard/spec
Feedback
Use the form on the .recipe front door
Reference implementation
Do-Re-Ci-Pe / Recipe Recall
Abstract
The `.recipe` format is a ZIP-based package for exchanging recipes between applications and archives. It contains a schema marker, package metadata, a structured recipe JSON document, and optional image assets. It is designed to preserve cooking-specific information while remaining easy to inspect with common developer tools.
Status of this document
This is a draft specification derived from the current Do-Re-Ci-Pe implementation. It is suitable for review and experimental implementation, but should not yet be treated as a final standard.
Feedback is requested on field naming, nullability, media handling, units, licensing metadata, localization, and compatibility rules.
Conformance
The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL are used in their conventional standards-document sense.
Conforming writers
Writers MUST produce a ZIP archive containing schema-version.txt, manifest.json, and recipe.json at the package root.
Conforming readers
Readers MUST validate the schema version before importing recipe data and SHOULD ignore unknown JSON fields in compatible versions.
Package layout
example.recipe
|-- schema-version.txt
|-- manifest.json
|-- recipe.json
+-- assets/
|-- recipe-image.jpg
+-- steps/
|-- step-0.jpg
+-- step-1.jpgThe assets directory is OPTIONAL. Files inside assets MUST be referenced by package-relative paths from recipe.json.
Processing model
- 1Open the .recipe file as a ZIP archive.
- 2Read schema-version.txt and parse it as an integer.
- 3Reject versions lower than 1 or greater than or equal to 10.
- 4Decode manifest.json and recipe.json as UTF-8 JSON.
- 5Resolve image paths relative to the package root.
- 6Ignore unknown JSON fields in compatible minor versions.
manifest.json
formatVersionstringREQUIRED. Package format version. Current value: 1.0.
generatedBystringREQUIRED. Human-readable name of the app or tool that generated the package.
appVersionstringREQUIRED. Version of the generating app or tool.
exportDatedate-timeREQUIRED. ISO 8601 export timestamp.
recipeIdstringREQUIRED. UUID or stable source identifier for the exported recipe.
recipeNamestringREQUIRED. Human-readable recipe title.
recipe.json
versionintegerREQUIRED. Recipe payload version. Current value: 1.
idstringREQUIRED. UUID or stable recipe identifier.
namestringREQUIRED. Recipe title.
summarystringREQUIRED. Short recipe description. May be an empty string.
createdAtdate-timeREQUIRED. Original creation timestamp.
modifiedAtdate-timeREQUIRED. Last known modification timestamp.
isAIGeneratedbooleanREQUIRED. Whether AI generated or assisted the recipe.
aiGenerationPromptstring | nullOPTIONAL. Prompt provenance when available.
ingredientsIngredientData[]REQUIRED. Ordered ingredient rows.
stepsStepData[]REQUIRED. Ordered instruction steps.
nutritionNutritionData | nullOPTIONAL. Per-serving nutrition values when known.
dietaryLabelsstring[]REQUIRED. Known labels such as vegetarian, vegan, glutenFree, dairyFree, nutFree, lowCarb, highProtein.
optionalDetailsOptionalDetailsDataREQUIRED. Servings, times, equipment, tags, notes, storage, and related metadata.
enabledOptionalDetailsstring[]REQUIRED. UI visibility hints from the exporting app.
recipeImageImageReferenceREQUIRED. Optional package-relative recipe image reference.
Nested models
IngredientData
idstringUUID or stable ingredient id.
quantitynumberNumeric ingredient amount.
unitstringCurrent units: g, oz, fl oz, tsp, tbsp, cup, ml, l, piece, pinch, dash.
namestringIngredient display name.
orderintegerZero-based or stable display order.
StepData
idstringUUID or stable step id.
orderintegerStep display order.
textstringInstruction text.
whystring | nullOptional rationale or cooking explanation.
hasTimerbooleanWhether the step includes a timer.
timerMinutesintegerTimer minutes. Use 0 when absent.
timerSecondsintegerTimer seconds. Use 0 when absent.
hasImagebooleanWhether this step references an image.
imagePathstring | nullPackage-relative image path, for example assets/steps/step-0.jpg.
NutritionData
energyKcalnumber | nullEnergy in kilocalories.
energyKJnumber | nullEnergy in kilojoules.
fatnumber | nullTotal fat in grams.
saturatedFatnumber | nullSaturated fat in grams.
transFatnumber | nullTrans fat in grams.
cholesterolnumber | nullCholesterol in milligrams.
saltnumber | nullSalt in grams.
sodiumnumber | nullSodium in milligrams.
carbohydratesnumber | nullCarbohydrates in grams.
sugarsnumber | nullSugars in grams.
fibernumber | nullDietary fiber in grams.
proteinnumber | nullProtein in grams.
OptionalDetailsData
servingsMininteger | nullMinimum servings.
servingsMaxinteger | nullMaximum servings.
originstring | nullRecipe origin or cuisine note.
authorstring | nullRecipe author.
prepTimeinteger | nullPrep time in minutes.
cookTimeinteger | nullCook time in minutes.
totalTimeinteger | nullTotal time in minutes.
equipmentstring[] | nullEquipment list.
tagsstring[] | nullFree-form tags.
tipsstring[] | nullCooking tips.
sciencestring[] | nullFood science notes.
storageCounterstring | nullCounter storage note.
storageFreezerstring | nullFreezer storage note.
storageReheatstring | nullReheating note.
flavorProfilestring[] | nullFlavor descriptors.
ImageReference
hasImagebooleanWhether an image is present.
imagePathstring | nullPackage-relative path. Use null when hasImage is false.
Importing and compatibility
Current schema
schema-version.txt contains 1. manifest.json uses formatVersion 1.0.
Compatible range
Versions 1 through 9 are reserved for compatible revisions.
Breaking range
Versions 10 and above are reserved for incompatible major revisions.
Importers SHOULD create new local identifiers when importing a copy, unless the user explicitly chooses to replace an existing recipe with the same source id.
Example recipe.json
{
"version": 1,
"id": "D63F28D7-2A72-4C1F-91A1-70662683A7A2",
"name": "Tomato Toast",
"summary": "A fast lunch with ripe tomatoes and crisp bread.",
"createdAt": "2026-06-22T12:00:00Z",
"modifiedAt": "2026-06-22T12:00:00Z",
"isAIGenerated": false,
"aiGenerationPrompt": null,
"ingredients": [
{
"id": "9B5B9B7A-07A8-4E9D-9ED9-96E77F44E7B5",
"quantity": 2,
"unit": "piece",
"name": "sourdough bread",
"order": 0
}
],
"steps": [
{
"id": "7E9DAAC9-E196-4D14-BDFE-42B90E49324C",
"order": 0,
"text": "Toast the bread until crisp.",
"why": "A crisp base keeps tomatoes from making the toast soggy.",
"hasTimer": true,
"timerMinutes": 3,
"timerSeconds": 0,
"hasImage": false,
"imagePath": null
}
],
"nutrition": null,
"dietaryLabels": ["vegetarian"],
"optionalDetails": {
"servingsMin": 1,
"servingsMax": 1,
"origin": null,
"author": "Do-Re-Ci-Pe",
"prepTime": 5,
"cookTime": 3,
"totalTime": 8,
"equipment": ["toaster"],
"tags": ["lunch"],
"tips": null,
"science": null,
"storageCounter": null,
"storageFreezer": null,
"storageReheat": null,
"flavorProfile": ["bright", "crisp"]
},
"enabledOptionalDetails": ["servings", "author", "totalTime"],
"recipeImage": {
"hasImage": false,
"imagePath": null
}
}