Skip to content

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

  1. Sign up for Notion at https://www.notion.so if you don’t have an account
  2. Create a workspace if you don’t have one
  3. Create a “Meal Plans” page in your workspace (use the “empty page” option)
  4. Create an integration at https://www.notion.so/profile/integrations
  5. Share the page with your integration (click ••• at top right → Connections → Add your integration)
  6. Copy your integration token
  7. Copy the page ID from the URL (the 32-character string, remove hyphens)
  8. Configure the Notion integration in Conductor:
Terminal window
conductor integrations add notion --token "your-integration-token"

The Workflow

Update recipe.yaml:

# yaml-language-server: $schema=../../schemas/workflow.schema.json
name: meal-planner
description: 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 page

Key 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: markdown

Returns content as a markdown string instead of a blocks array.

Run It

Terminal window
conductor run recipe.yaml -i parent_page_id="your-page-id"

What You Learned

  • Markdown content - Use markdown: parameter instead of blocks: 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.