You searched for “how to set up OpenClaw for automated meal planning and groceries.” I spent the last three weekends wiring exactly that for my family, and it now buys us about 70 minutes every Sunday. Below is the full playbook: from the recipe database to weather-aware grilling suggestions, all running on an OpenClaw agent that posts our plan to Slack at 7 am and nudges us again after work.

The moving parts and why they matter

OpenClaw (v0.14.2 at the time of writing) handles the orchestration. Composio gives us the 800-plus SaaS connectors, including Notion, Google Sheets, Gmail, and Slack. We only need four real actors:

  • Recipe DB – one table in Notion or Sheets. Columns: name, cuisine, cook_time, tags, ingredients, instructions, seasonality.
  • OpenClaw Agent – runs the logic, keeps memory of past meals, and calls tools.
  • Weather API – I used api.open-mete o.com. Free, no key required for basic forecast.
  • Notification channel – Slack in my case, WhatsApp works the same.

Everything else (scheduling, retries, browser automation if you order online) comes for free inside OpenClaw.

Prerequisites and quick install

1. Node >= 22, Git, and the CLI

OpenClaw is Node-first. Make sure you are on Node 22 or newer:

$ fnm install 22 $ fnm use 22 $ node -v # v22.1.0

Then install the agent globally or per-project:

$ mkdir meal-planner && cd meal-planner $ npm init -y $ npm install openclaw@0.14.2 --save

2. Composio account + tokens

Create a free Composio account, generate an API key, and connect the integrations you care about (Notion or Google Sheets, Slack, WhatsApp, Gmail). Copy the OAuth refresh tokens—they go into .env.

3. Weather API endpoint

No key needed if you hit the /forecast JSON endpoint. We’ll wrap it in a tiny function.

Schema design: the minimum recipe database

Use Notion if you enjoy the UI; pick Google Sheets if you want raw CSV export. Both are 100 % supported by Composio. Here’s the Notion version I shipped:

  1. Create a new database called Recipes.
  2. Add columns:
    • Name – title
    • Cook Time (min) – number
    • Tags – multi-select (e.g., vegan, keto, grill)
    • Ingredients – text, one per line quantity|unit|item|store|aisle
    • Seasonality – select (winter, spring, summer, fall, all)
    • Last Cooked – date (the agent updates this)

Google Sheets schema is identical—first row as headers. OpenClaw queries with simple SELECT-like filters.

Bootstrapping the OpenClaw agent

Create claw.config.js in the project root:

module.exports = { name: "MealPlannerBot", description: "Plans weekly meals, creates shopping list, and sends reminders", memory: { provider: "file", // swap with redis for multi-node path: "./memory.json" }, tools: [ "composio/notion.read", "composio/notion.write", "composio/sheets.read", "composio/sheets.write", "composio/slack.send", "browser.open", // optional for online grocery checkout "shell.run" // to call curl for weather ], scheduler: true // keep-alive cron support };

Run the gateway UI once to make sure tokens are set:

$ npx openclaw gateway

Log in, paste the Composio API key, and confirm the Notion/Sheets scopes.

Planning logic: choosing seven dinners

This is the core reasoning prompt. OpenClaw allows a JavaScript planner that runs before tool calls. Drop ./planner.js:

module.exports = async function planner(ctx) { const today = new Date(); const week = Array.from({ length: 7 }, (_, i) => new Date(today.getTime() + 864e5 * i)); // 1. Pull recipes we have not cooked in the last 30 days const recentIds = await ctx.tool("composio/notion.read", { database: "Recipes", filter: { field: "Last Cooked", after: new Date(Date.now() - 30 * 864e5).toISOString() }, select: ["id"] }); const pool = await ctx.tool("composio/notion.read", { database: "Recipes", filter: { field: "id", not_in: recentIds } }); // 2. Simple rotation algorithm — could be ML-based later const plan = []; while (plan.length < 7) { const pick = pool.splice(Math.floor(Math.random() * pool.length), 1)[0]; plan.push({ date: week[plan.length], recipe: pick }); } ctx.memory.set("thisWeek", plan); return plan; };

The agent stores the week in memory so the next task can assemble the shopping list.

Building the shopping list and grouping by store/aisle

Create ./shopper.js:

module.exports = async function shopper(ctx) { const plan = ctx.memory.get("thisWeek"); if (!plan) throw new Error("No plan in memory"); const items = {}; for (const { recipe } of plan) { for (const line of recipe.properties.Ingredients.split("\n")) { const [q, unit, item, store, aisle] = line.split("|"); const key = `${store}|${aisle}|${item}`; items[key] = items[key] || { qty: 0, unit, item, store, aisle }; items[key].qty += Number(q); } } const sorted = Object.values(items).sort((a, b) => { if (a.store === b.store) return a.aisle.localeCompare(b.aisle); return a.store.localeCompare(b.store); }); // Persist to Sheets for mobile access await ctx.tool("composio/sheets.write", { spreadsheet: "Groceries", range: "A2", values: sorted.map(i => [i.store, i.aisle, i.item, i.qty, i.unit]) }); ctx.memory.set("shoppingList", sorted); return sorted; };

Yes, this is still imperative JavaScript, but it runs inside the agent sandbox, no external server needed.

Weather-aware grilling suggestions

On Thursdays at 17 : 00 the bot decides if Saturday is grill-worthy. Add ./forecast.js:

module.exports = async function forecast(ctx) { const res = await ctx.tool("shell.run", { command: "curl -s 'https://api.open-meteo.com/v1/forecast?latitude=40.7&longitude=-73.9&hourly=temperature_2m,precipitation_probability&start='+$(date -u +%Y-%m-%d)+'&hourly=temperature_2m,precipitation_probability'" }); const data = JSON.parse(res.stdout); const satIndex = data.hourly.time.findIndex(t => t.startsWith(ctx.nextSaturday("YYYY-MM-DD"))); const temp = data.hourly.temperature_2m[satIndex + 15]; // 3pm const rain = data.hourly.precipitation_probability[satIndex + 15]; if (temp > 20 && rain < 25) { ctx.memory.push("tags", "grill_ok"); return "Looks good for grilling"; } return "Skip the grill"; };

The above is hacky but reliable. In practice you’d cache the response to keep the weather API polite.

Scheduling morning and evening reminders

OpenClaw’s scheduler is cron-syntax. Add to claw.cron:

# Weekly plan every Sunday 08:00 local 0 8 * * SUN run planner.js | shopper.js | pushPlan # Weather check Thursday 17:00 0 17 * * THU run forecast.js | pushGrill # Daily 07:00 remind what to thaw / prep 0 7 * * * run pushMorning # Daily 18:00 remind what to cook tonight 0 18 * * * run pushEvening

Each pipeline ends in a push* script that sends Slack blocks:

module.exports = async function pushEvening(ctx) { const dinner = ctx.memory.get("thisWeek").find(p => sameDay(p.date, new Date())); await ctx.tool("composio/slack.send", { channel: "#family", blocks: [ { type: "section", text: { type: "mrkdwn", text: `*Dinner tonight:* ${dinner.recipe.properties.Name}` } } ] }); };

Swap composio/whatsapp.send and supply a phone number if your household lives there.

Running locally vs. deploying to ClawCloud

Local dev loop

Use $ npx openclaw dev to run with hot reload. The gateway appears on localhost:3000 for manual chats. Schedules run as long as the tab is open—handy for debugging but fragile.

One-click deploy

Switch to the hosted runtime once it works:

$ npm exec openclaw deploy -- --cloud

The CLI zips the current dir, uploads to your ClawCloud workspace, installs Node 22, and starts the daemon. First deploy takes ~45 s. After that, git push cloud main auto-rebuilds.

ClawCloud’s free tier covers three agents and 25k tool calls/month—enough for a family. Heavy API users (Instacart checkout, nutrition analysis) will want the pro-50k plan.

What breaks and how to fix it

  • OAuth token expires – Composio auto-refreshes, but if you hit a 401, regenerate the integration and redeploy.
  • Notion rate limits – Large imports can exceed the soft cap (3 requests/s). Stick a await sleep(400) inside bulk writes.
  • Sheets rows shift – The script writes to A2 downward. If someone sorts the sheet manually, the next run will append duplicates. Lock the first 1000 rows or migrate to separate tab per week.
  • Weather JSON changes – The Open-Meteo API occasionally renames fields in beta. Pin the forecast version via ?v=2.3 in the URL.

Next steps: iterate, measure, and share

You now have an agent that:

  • Rotates through recipes without repeats
  • Stores the week’s plan in memory and Notion
  • Generates a deduped shopping list sorted by store → aisle
  • Checks Saturday weather and flags “grill ok”
  • Sends two Slack reminders per day

From here the obvious wins are nutrition macros, auto-ordering via Instacart’s web UI (the browser.click tool is already present), and feedback loops (“thumbs down” a recipe and watch it disappear for a quarter). If you build something neat, open a GitHub discussion or drop a link on HN—half of this article came from those comments.

Happy hacking and enjoy the extra hour of weekend.