You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
</a><ahref=https://www.buymeacoffee.com/dubadubtarget=_blankrel="noopener noreferrer" class="block px-4 py-2 bg-yellow-400 text-gray-900 font-medium text-sm rounded-md">☕ Buy me a coffee</a></nav></div></header><mainclass=flex-1><articleclass=bg-white><divclass="container mx-auto px-4 py-8 overflow-x-auto"><headerclass=mb-8><h1class="text-4xl font-bold text-cooklang-gray-900 mb-4">How to Automate Grocery Shopping with Plain Text Recipes</h1><divclass=text-cooklang-gray-600><timedatetime=2026-04-09T00:00:00+00:00>April 9, 2026</time></div></header><divclass="prose prose-lg max-w-none text-cooklang-gray-700 overflow-x-auto"><p>I used to buy groceries by wandering through the store, picking things up as I went. It worked when I could physically walk the aisles. When I switched to online ordering, I couldn't do that anymore. I had to know exactly what I needed before I started.</p><p>So I began writing meal plans on sticky notes, listing ingredients by hand, then combining them into an order. After a few weeks of this, the developer in me couldn't take it anymore. The process was repetitive and mechanical — exactly the kind of thing a computer should handle.</p><p>That's how <ahref=/>Cooklang</a> was born.</p><h2id=the-idea>The Idea</h2><p>What if recipes were plain text files where ingredients were tagged with <code>@</code>? Like this:</p><divclass=code-toolbar><preclass=language-cooklangdata-language=cooklang><codeclass=language-cooklang>Then add @salt and @ground black pepper{} to taste.
27
+
</a><ahref=https://www.buymeacoffee.com/dubadubtarget=_blankrel="noopener noreferrer" class="block px-4 py-2 bg-yellow-400 text-gray-900 font-medium text-sm rounded-md">☕ Buy me a coffee</a></nav></div></header><mainclass=flex-1><articleclass=bg-white><divclass="container mx-auto px-4 py-8 overflow-x-auto"><navclass="text-sm text-cooklang-gray-600 mb-4" aria-label=Breadcrumb><olclass="flex flex-wrap items-center gap-x-2"><li><ahref=/blog/class=hover:text-cooklang-orange>Blog</a></li><liclass=text-cooklang-gray-400aria-hidden=true>›</li><li><ahref=/blog/recipe-workflows/class=hover:text-cooklang-orange>Recipe Workflows</a></li><liclass=text-cooklang-gray-400aria-hidden=true>›</li><liclass="text-cooklang-gray-900 truncate max-w-xs" aria-current=page>How to Automate Grocery Shopping with Plain Text Recipes</li></ol></nav><scripttype=application/ld+json>{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","item":"https://cooklang.org/blog/","name":"Blog","position":1},{"@type":"ListItem","item":"https://cooklang.org/blog/recipe-workflows/","name":"Recipe Workflows","position":2},{"@type":"ListItem","name":"How to Automate Grocery Shopping with Plain Text Recipes","position":3}]}</script><headerclass=mb-8><h1class="text-4xl font-bold text-cooklang-gray-900 mb-4">How to Automate Grocery Shopping with Plain Text Recipes</h1><divclass=text-cooklang-gray-600><timedatetime=2026-04-09T00:00:00+00:00>April 9, 2026</time></div></header><divclass="prose prose-lg max-w-none text-cooklang-gray-700 overflow-x-auto"><p>I used to buy groceries by wandering through the store, picking things up as I went. It worked when I could physically walk the aisles. When I switched to online ordering, I couldn't do that anymore. I had to know exactly what I needed before I started.</p><p>So I began writing meal plans on sticky notes, listing ingredients by hand, then combining them into an order. After a few weeks of this, the developer in me couldn't take it anymore. The process was repetitive and mechanical — exactly the kind of thing a computer should handle.</p><p>That's how <ahref=/>Cooklang</a> was born.</p><h2id=the-idea>The Idea</h2><p>What if recipes were plain text files where ingredients were tagged with <code>@</code>? Like this:</p><divclass=code-toolbar><preclass=language-cooklangdata-language=cooklang><codeclass=language-cooklang>Then add @salt and @ground black pepper{} to taste.
28
28
Poke holes in @potato{2}.
29
29
Place @bacon strips{1%kg} on a baking sheet and glaze with @syrup{1/2%tbsp}.</code></pre></div><p>The recipe stays readable — you can follow it as-is. But a computer can also parse it, extract every ingredient with its quantity, and build a shopping list automatically.</p><p>Because it's plain text, I can store recipes in Git, edit them in any text editor, and sync them across devices with whatever I already use. No database, no app subscription, no vendor lock-in.</p><h2id=the-tools>The Tools</h2><p>A markup language alone isn't useful without tools to process it. I built <ahref=/cli/>CookCLI</a> — a command-line program that reads <code>.cook</code> files and does practical things with them.</p><p>The one I use most is <code>shopping-list</code>. Point it at a few recipe files and it combines all ingredients, grouped by store aisle:</p><divclass=code-toolbar><preclass=language-data-language><codeclass=language->$ cook shopping-list Neapolitan\ Pizza.cook Root\ Vegetable\ Tray\ Bake.cook
30
30
@@ -47,5 +47,5 @@
47
47
48
48
TINNED GOODS AND BAKING
49
49
chopped tomato 3 cans
50
-
fresh yeast 1.6 g</code></pre></div><p>Output can be JSON or YAML for piping into other programs. CookCLI also includes a <ahref=/cli/commands/server/>web server</a> for browsing recipes from a phone or tablet, and a <ahref=/cli/commands/search/>search command</a> for finding recipes by ingredient.</p><h2id=my-workflow>My Workflow</h2><p>I organize recipes into directories that represent meal plans. Generating a shopping list for the week is one command:</p><divclass=code-toolbar><preclass=language-bashdata-language=bash><codeclass=language-bash>cook shopping-list ./this-week/*.cook</code></pre></div><p>I cross off what I already have, then order the rest. The process takes about five minutes instead of the thirty-plus it used to take with sticky notes. More importantly, I buy exactly what I need — no forgotten ingredients, no impulse purchases.</p><p>I keep all my recipes in a <ahref=https://github.com/dubadub/cookbook>Git repository</a>. They've been evolving for years — adjusting quantities, adding notes, trying variations. Git tracks every change.</p><p><strong>Update (2025):</strong> I've since built a <ahref=https://github.com/dubadub/cookbook/tree/main/shop-automation>Rust script</a> that maps recipe ingredients to products on my grocery store's website, making the ordering process almost fully automatic. The ecosystem has also grown — there are now <ahref=/app/>mobile apps</a>, an <ahref=/blog/15-cooklang-obsidian-guide/>Obsidian plugin</a>, a <ahref="https://marketplace.visualstudio.com/items?itemName=nicholasglazer.cooklang-vscode-support">VS Code extension</a>, and a <ahref=https://recipes.cooklang.org>community recipe index</a>. Check the <ahref=/docs/getting-started/>getting started guide</a> to try it yourself.</p><p>-Alexey</p></div></div></article></main><footerclass="bg-cooklang-gray-900 text-white mt-auto"><divclass="container mx-auto px-4 py-8"><divclass="grid grid-cols-1 md:grid-cols-4 gap-8"><div><h4class="font-semibold mb-4">Mobile Apps</h4><divclass=space-y-2><ahref="https://play.google.com/store/apps/details?id=md.cook.android" class=block><picture><sourcetype=image/webpsrcset=/google-play-badge.webp><imgsrc=/google-play-badge.pngalt="Download on Google Play" class="h-10 w-auto" width=394height=128loading=lazy>
50
+
fresh yeast 1.6 g</code></pre></div><p>Output can be JSON or YAML for piping into other programs. CookCLI also includes a <ahref=/cli/commands/server/>web server</a> for browsing recipes from a phone or tablet, and a <ahref=/cli/commands/search/>search command</a> for finding recipes by ingredient.</p><h2id=my-workflow>My Workflow</h2><p>I organize recipes into directories that represent meal plans. Generating a shopping list for the week is one command:</p><divclass=code-toolbar><preclass=language-bashdata-language=bash><codeclass=language-bash>cook shopping-list ./this-week/*.cook</code></pre></div><p>I cross off what I already have, then order the rest. The process takes about five minutes instead of the thirty-plus it used to take with sticky notes. More importantly, I buy exactly what I need — no forgotten ingredients, no impulse purchases.</p><p>I keep all my recipes in a <ahref=https://github.com/dubadub/cookbook>Git repository</a>. They've been evolving for years — adjusting quantities, adding notes, trying variations. Git tracks every change.</p><p><strong>Update (2025):</strong> I've since built a <ahref=https://github.com/dubadub/cookbook/tree/main/shop-automation>Rust script</a> that maps recipe ingredients to products on my grocery store's website, making the ordering process almost fully automatic. The ecosystem has also grown — there are now <ahref=/app/>mobile apps</a>, an <ahref=/blog/15-cooklang-obsidian-guide/>Obsidian plugin</a>, a <ahref="https://marketplace.visualstudio.com/items?itemName=nicholasglazer.cooklang-vscode-support">VS Code extension</a>, and a <ahref=https://recipes.cooklang.org>community recipe index</a>. Check the <ahref=/docs/getting-started/>getting started guide</a> to try it yourself.</p><p>-Alexey</p></div><asideclass="mt-12 pt-8 border-t border-cooklang-gray-200"><h3class="text-lg font-semibold text-cooklang-gray-900 mb-4">Part of the <ahref=/blog/recipe-workflows/class="text-cooklang-orange hover:text-orange-600">Recipe Workflows</a> series →</h3><divclass="grid gap-4 md:grid-cols-3"><articleclass="bg-white border border-cooklang-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow"><h4class="text-base font-semibold mb-1"><ahref=/blog/02-practical-savings-on-groceries-with-cooklang/class="text-cooklang-gray-900 hover:text-cooklang-orange">Automated Grocery List: Save Time and Money with Meal Planning</a></h4><pclass="text-sm text-cooklang-gray-600">Build an automated grocery list from your meal plan using Cooklang. Practical tips for shopping list …</p></article><articleclass="bg-white border border-cooklang-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow"><h4class="text-base font-semibold mb-1"><ahref=/blog/43-version-control-recipes-with-git/class="text-cooklang-gray-900 hover:text-cooklang-orange">Version Control Your Recipes with Git</a></h4><pclass="text-sm text-cooklang-gray-600">Every recipe app has a 'what if the company dies?' problem. If your recipes are plain text .cook …</p></article><articleclass="bg-white border border-cooklang-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow"><h4class="text-base font-semibold mb-1"><ahref=/blog/26-how-to-scale-recipes-without-mistakes/class="text-cooklang-gray-900 hover:text-cooklang-orange">How to Scale a Recipe Up or Down (Without Ruining It)</a></h4><pclass="text-sm text-cooklang-gray-600">Scaling recipes sounds like simple math until your cookies come out flat or your soup is inedibly …</p></article></div></aside></div></article></main><footerclass="bg-cooklang-gray-900 text-white mt-auto"><divclass="container mx-auto px-4 py-8"><divclass="grid grid-cols-1 md:grid-cols-4 gap-8"><div><h4class="font-semibold mb-4">Mobile Apps</h4><divclass=space-y-2><ahref="https://play.google.com/store/apps/details?id=md.cook.android" class=block><picture><sourcetype=image/webpsrcset=/google-play-badge.webp><imgsrc=/google-play-badge.pngalt="Download on Google Play" class="h-10 w-auto" width=394height=128loading=lazy>
0 commit comments