Step 5: Save to Notion
Save your meal plan to Notion pages using markdown.
Goal
Generate a meal plan and save it to Notion using the Notion integration with markdown content.
Setup
- Sign up for Notion at https://www.notion.so if you don’t have an account
- Create a workspace if you don’t have one
- Create a “Meal Plans” page in your workspace (use the “empty page” option)
- Create an integration at https://www.notion.so/profile/integrations
- Share the page with your integration (click ••• at top right → Connections → Add your integration)
- Copy your integration token
- Copy the page ID from the URL (the 32-character string, remove hyphens)
- Configure the Notion integration in Conductor:
conductor integrations add notion --token "your-integration-token"The Workflow
Update recipe.yaml:
# yaml-language-server: $schema=../../schemas/workflow.schema.jsonname: meal-plannerdescription: Generate meal plans with detailed recipes and save to Notion
# This example demonstrates:# - Markdown input/output for Notion pages (simpler than block arrays)# - default_markdown parameter (initializes page only when created)# - format: markdown for reading content (returns markdown string)# - Template range loops for dynamic content
inputs: - name: parent_page_id type: string description: Notion page ID where meal planning pages will be created pattern: "^[a-f0-9]{32}$"
- name: days_to_plan type: number default: 3 description: Number of days to plan (1-7)
- name: diet type: string default: "balanced" description: Dietary preference (balanced, vegetarian, low-carb, etc.)
steps: # Step 1: Create pantry page with default content (only applied when page is created) # The is_new field in the response indicates if it was created or found - id: pantry name: Setup Pantry Page notion.upsert_page: parent_id: "{{.inputs.parent_page_id}}" title: "Pantry" default_markdown: | # My Pantry
List the ingredients you have available. The meal planner will use these to generate your meals.
---
Add your ingredients here...
# Step 2: Read pantry contents as markdown (easier for LLM to process) - id: pantry_content name: Read Pantry Contents notion.get_blocks: page_id: "{{.steps.pantry.id}}" format: markdown
# Step 3: Generate meal plan with LLM - id: generate_plan name: Generate Meal Plan type: llm model: balanced output_schema: type: object properties: overview: { type: array, items: { type: string } } days: type: array items: type: object properties: name: { type: string } breakfast: { type: string } lunch: { type: string } dinner: { type: string } shopping_list: { type: array, items: { type: string } } prompt: | Create a {{.inputs.diet}} meal plan for {{.inputs.days_to_plan}} days.
Available pantry ingredients: {{.steps.pantry_content.content}}
Generate DETAILED recipes with full cooking instructions. Each recipe must include: - Dish name - Prep time and cook time - Estimated calories and macros (protein, carbs, fat) per serving - Complete ingredient list with exact measurements - Step-by-step cooking instructions (numbered) - Any tips or variations
FORMAT REQUIREMENTS: - All recipe fields must be plain text strings (not nested objects) - Each day object MUST have four fields: name, breakfast, lunch, dinner - Day names must have numbered prefixes for sorting: "1 - Day 1", "2 - Day 2", "3 - Day 3" - Shopping list must be an array of strings, one item per entry
DAYS ARRAY EXAMPLE: [ {"name": "1 - Day 1", "breakfast": "recipe...", "lunch": "recipe...", "dinner": "recipe..."}, {"name": "2 - Day 2", "breakfast": "recipe...", "lunch": "recipe...", "dinner": "recipe..."} ]
OVERVIEW: Return as an array of strings, one per day in title case (not all caps): ["Day 1: Veggie Omelette -> Grilled Chicken Salad -> Garlic Butter Salmon", "Day 2: Greek Yogurt Parfait -> Turkey Club Wrap -> Beef Stir-Fry"]
RECIPE FORMAT - YOU MUST FOLLOW THIS EXACT STRUCTURE:
"Honey Garlic Salmon
Prep: 10 min | Cook: 15 min | Serves: 2 Calories: 385 | Protein: 34g | Carbs: 18g | Fat: 19g
Ingredients: - 2 salmon fillets (6 oz each) - 3 tbsp honey - 2 tbsp soy sauce - 4 cloves garlic, minced - 1 tbsp olive oil
Instructions: 1. Pat salmon dry and season with salt and pepper. 2. Mix honey, soy sauce, and garlic in a small bowl. 3. Heat olive oil in a skillet over medium-high heat. 4. Place salmon skin-side up, cook 4 minutes until golden. 5. Flip salmon, pour honey garlic sauce over top. 6. Cook 4-5 more minutes, basting with sauce.
Tip: Serve with steamed rice and roasted vegetables."
SHOPPING LIST: Return as a flat array of item strings with quantities: ["2 lemons", "1 bunch parsley", "4 tomatoes", "2 salmon fillets (6 oz each)"]
# Step 4: Update parent page with meal plan overview using markdown # The markdown parameter converts markdown to Notion blocks automatically - id: update_meal_plan name: Update Meal Plan Overview notion.replace_content: page_id: "{{.inputs.parent_page_id}}" markdown: | # Weekly Meal Plan
Your personalized meal plan with breakfast, lunch, and dinner for each day.
---
## Overview {{range .steps.generate_plan.output.overview}} - {{.}} {{end}}
---
## Daily Recipes Click on each day below for detailed recipes with ingredients, instructions, and nutritional info.
# Step 5: Create daily pages with markdown content - id: create_daily_pages name: Create Daily Pages type: parallel foreach: "{{.steps.generate_plan.output.days}}" steps: - id: create_day name: Create Day Page notion.upsert_page: parent_id: "{{.inputs.parent_page_id}}" title: "{{.inputs.item.name}}" markdown: | # {{.inputs.item.name}}
## Breakfast {{.inputs.item.breakfast}}
## Lunch {{.inputs.item.lunch}}
## Dinner {{.inputs.item.dinner}}
# Step 6: Create shopping list with checkboxes using markdown # The - [ ] syntax creates to_do blocks (checkboxes) - id: create_shopping name: Create Shopping List notion.upsert_page: parent_id: "{{.inputs.parent_page_id}}" title: "Shopping List" markdown: | # Shopping List Check off items as you shop!
{{range .steps.generate_plan.output.shopping_list}} - [ ] {{.}} {{end}}
outputs: - name: pantry_url type: string value: "{{.steps.pantry.url}}" description: Link to Pantry page
- name: shopping_list_url type: string value: "{{.steps.create_shopping.url}}" description: Link to Shopping List pageKey Concepts
Markdown Content
Instead of constructing Notion blocks one by one, use the markdown parameter:
notion.replace_content: page_id: "{{.inputs.parent_page_id}}" markdown: | # Weekly Meal Plan
## Overview {{range .steps.generate_plan.output.overview}} - {{.}} {{end}}This converts markdown to Notion blocks automatically, including:
- Headings, paragraphs, lists
- Checkboxes (
- [ ]and- [x]) - Code blocks, quotes, dividers
- Rich text formatting
Default Content
Use default_markdown to initialize a page only when it’s created:
notion.upsert_page: parent_id: "{{.inputs.parent_page_id}}" title: "Pantry" default_markdown: | # My Pantry Add your ingredients here...If the page already exists, default_markdown is ignored. The response includes is_new: true/false.
Reading as Markdown
Read page content as markdown for LLM processing:
notion.get_blocks: page_id: "{{.steps.pantry.id}}" format: markdownReturns content as a markdown string instead of a blocks array.
Run It
conductor run recipe.yaml -i parent_page_id="your-page-id"What You Learned
- Markdown content - Use
markdown:parameter instead ofblocks:arrays - Default content - Initialize pages with
default_markdown(only on create) - Format output - Read content as markdown with
format: markdown - Template loops - Use
{{range}}to generate dynamic lists
Next
Step 6: Deploy - Deploy your workflow to run on a schedule.