Skip to content

What is Gram?

Gram is an open-source declarative, computational recipe DSL (Domain-Specific Language) built for developers.

Most recipe websites are written for search engines and humans, resulting in verbose stories, unstructured ingredient lists, and uncoordinated timers.

Gram takes a different approach: Recipes as Code.

Most recipe formats out there are just static blocks of text. Gram takes a different approach: it takes your natural cooking instructions written in plain text and compiles them into structured, calculated, and relational data.

Cooking is a bit like an algorithm: you take raw ingredients as input and output a finished dish. But to me, it’s above all a passion. That’s where Gram comes from: I love cooking, and I wanted a tool that combines the rigor of code with creativity in the kitchen.

I’ve always loved the idea of writing recipes in plain text, heavily inspired by pioneering projects like the excellent Cooklang. Cooklang is fantastic for quick, straightforward home recipes. But when things get a bit more complex—like professional pastry formulas with multiple sub-components, baker’s math, or tricky scheduling—relying entirely on natural language can get messy.

Gram also draws structural inspiration from the classic Cooking for Engineers tabular format. Because Gram compiles recipes into a predictable JSON tree, the door is wide open for developers to build advanced visual renderers in the future, like Gantt schedules or tabular flowcharts.

I created Gram as an alternative for these more demanding scenarios. It introduces relational logic, physical accuracy, and modular composition into your recipe writing:

  • Relational Variables: If you make a dough in step 1, you can reference it as an ingredient in step 5, cleanly preventing duplication.
  • Physical Accuracy & Calculations: Gram understands the difference between the “zest of 1 lemon” and “juice of 2 lemons”, ensuring your shopping list accurately aggregates to “Buy 2 lemons” instead of 3. It also computes real physical mass and relative ingredient ratios (70% @&flour).
  • Strict Data Contracts: By using explicit tags (@, ~, ^, #), Gram ensures that temperatures, times, ingredients, and cookware are never confused by the parser.
  • Modularity & Reusability (@use): Split shared bases (pastries, stocks, sauces) into their own .gram files. Gram seamlessly inlines their steps, automatically scales their quantities to match what your dish asks for (it measures the base’s own mass — no manual scaling to declare or keep in sync), and merges their raw ingredients onto your unified shopping list.

The Gram ecosystem gives you everything you need to treat recipes like software:

Parser & Compiler

@gram-lang/kitchen: Simulates the execution timeline, aggregates base shopping lists, and scales dynamic quantities.

Semantic Analyzer

@gram-lang/analyzer: Handles mass standardization, yield calculation, nutritional estimation, and advanced shopping list aggregation based on your local database.

Language Server (LSP)

Brings proper editor support to recipes (autocompletion, diagnostics, hover tooltips).

CLI

@gram-lang/cli: Compile, scale, diff, and manage your ingredient database straight from your terminal.

Renderer

@gram-lang/renderer: Instantly generate Semantic HTML or Markdown from your compiled JSON.

Gram remains highly readable, but quietly introduces some powerful data structures. Here is a look at a classic French pastry recipe written in Gram:

---
title: 'Cannelés'
portions: 10
---

## Batter ~{-1d} ->&batter

[Mix] In a #mixing bowl{}, combine the @flour{300 g}, @sugar{500 g}, and @salt{3 g}. ->&dry ingredients{}

[Heat] In a #large saucepan{}, bring the @milk{1 l}, @butter{100 g}, and @vanilla bean{1}(split and scraped) to ^{85C}. ->&hot milk{}

[Mix] Pour the &hot milk{} over the &dry ingredients{} all at once. Whisk vigorously.

[Incorporate] Add the @egg yolks{6}<@eggs{6} and the @rum{100 ml}.

[Rest] Cover with #plastic wrap{} touching the surface and chill in the refrigerator for at least ~_refrigerator{24 h}.

Notice how the [Incorporate] step uses <@eggs{6}? This composite ingredient syntax tells Gram that you are only using the yolks, but the shopping list should correctly aggregate the whole eggs required. The ~{-1d} section tag creates a retro-planning schedule relative to the final baking time, and ->&hot milk{} sets up an intermediate variable you can pour later.