.recipe front door

`.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.jpg

The assets directory is OPTIONAL. Files inside assets MUST be referenced by package-relative paths from recipe.json.

Processing model

  1. 1Open the .recipe file as a ZIP archive.
  2. 2Read schema-version.txt and parse it as an integer.
  3. 3Reject versions lower than 1 or greater than or equal to 10.
  4. 4Decode manifest.json and recipe.json as UTF-8 JSON.
  5. 5Resolve image paths relative to the package root.
  6. 6Ignore unknown JSON fields in compatible minor versions.

manifest.json

formatVersionstring

REQUIRED. Package format version. Current value: 1.0.

generatedBystring

REQUIRED. Human-readable name of the app or tool that generated the package.

appVersionstring

REQUIRED. Version of the generating app or tool.

exportDatedate-time

REQUIRED. ISO 8601 export timestamp.

recipeIdstring

REQUIRED. UUID or stable source identifier for the exported recipe.

recipeNamestring

REQUIRED. Human-readable recipe title.

recipe.json

versioninteger

REQUIRED. Recipe payload version. Current value: 1.

idstring

REQUIRED. UUID or stable recipe identifier.

namestring

REQUIRED. Recipe title.

summarystring

REQUIRED. Short recipe description. May be an empty string.

createdAtdate-time

REQUIRED. Original creation timestamp.

modifiedAtdate-time

REQUIRED. Last known modification timestamp.

isAIGeneratedboolean

REQUIRED. Whether AI generated or assisted the recipe.

aiGenerationPromptstring | null

OPTIONAL. Prompt provenance when available.

ingredientsIngredientData[]

REQUIRED. Ordered ingredient rows.

stepsStepData[]

REQUIRED. Ordered instruction steps.

nutritionNutritionData | null

OPTIONAL. Per-serving nutrition values when known.

dietaryLabelsstring[]

REQUIRED. Known labels such as vegetarian, vegan, glutenFree, dairyFree, nutFree, lowCarb, highProtein.

optionalDetailsOptionalDetailsData

REQUIRED. Servings, times, equipment, tags, notes, storage, and related metadata.

enabledOptionalDetailsstring[]

REQUIRED. UI visibility hints from the exporting app.

recipeImageImageReference

REQUIRED. Optional package-relative recipe image reference.

Nested models

IngredientData

idstring

UUID or stable ingredient id.

quantitynumber

Numeric ingredient amount.

unitstring

Current units: g, oz, fl oz, tsp, tbsp, cup, ml, l, piece, pinch, dash.

namestring

Ingredient display name.

orderinteger

Zero-based or stable display order.

StepData

idstring

UUID or stable step id.

orderinteger

Step display order.

textstring

Instruction text.

whystring | null

Optional rationale or cooking explanation.

hasTimerboolean

Whether the step includes a timer.

timerMinutesinteger

Timer minutes. Use 0 when absent.

timerSecondsinteger

Timer seconds. Use 0 when absent.

hasImageboolean

Whether this step references an image.

imagePathstring | null

Package-relative image path, for example assets/steps/step-0.jpg.

NutritionData

energyKcalnumber | null

Energy in kilocalories.

energyKJnumber | null

Energy in kilojoules.

fatnumber | null

Total fat in grams.

saturatedFatnumber | null

Saturated fat in grams.

transFatnumber | null

Trans fat in grams.

cholesterolnumber | null

Cholesterol in milligrams.

saltnumber | null

Salt in grams.

sodiumnumber | null

Sodium in milligrams.

carbohydratesnumber | null

Carbohydrates in grams.

sugarsnumber | null

Sugars in grams.

fibernumber | null

Dietary fiber in grams.

proteinnumber | null

Protein in grams.

OptionalDetailsData

servingsMininteger | null

Minimum servings.

servingsMaxinteger | null

Maximum servings.

originstring | null

Recipe origin or cuisine note.

authorstring | null

Recipe author.

prepTimeinteger | null

Prep time in minutes.

cookTimeinteger | null

Cook time in minutes.

totalTimeinteger | null

Total time in minutes.

equipmentstring[] | null

Equipment list.

tagsstring[] | null

Free-form tags.

tipsstring[] | null

Cooking tips.

sciencestring[] | null

Food science notes.

storageCounterstring | null

Counter storage note.

storageFreezerstring | null

Freezer storage note.

storageReheatstring | null

Reheating note.

flavorProfilestring[] | null

Flavor descriptors.

ImageReference

hasImageboolean

Whether an image is present.

imagePathstring | null

Package-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
  }
}