Einkauf (Grocery)

Keeps track of grocery orders — an always-open list for the next order, order history, purchase-frequency planning, and shop integrations such as REWE that the agent drives with a signed-in browser profile up to the cart.

What it does

grocery is a bundled iframe module for household grocery shopping. It is shop-independent at its core and adds shop integrations on top — the first one is REWE, driven by the Clapilot agent in a signed-in browser profile.

  • Nächste Bestellung / Next order — one always-open, shared list of items for the next order. Items can be added, renamed, re-quantified, annotated, marked as "in cart" or "unavailable", and deleted. Items carry a source badge: Geplant (added by automatic planning), Agent, Nochmal bestellt (reorder), or none for manual entries. A planning panel shows the next order date, the order cadence, the auto-planning switch, a Jetzt planen action, and Bald fällig products that will be due soon. The footer offers Bestellung vorbereiten (hands the list to the chat agent together with the selected shop) and Als bestellt markieren (records the current list as a placed order).
  • Bestellungen / Orders — recent orders with status (draft, cart_prepared, placed, delivered, cancelled), shop, dates, total, external order number, and the ordered items including the exact shop article. Orders can be recorded manually (one item per line, for example 2 l Milch), changed in status, reordered onto the list, or deleted.
  • Produkte / Products — every product that was ever on the list or in an order, with order count, learned purchase interval, last purchase, next due date, and a per-product automatisch planen switch. The detail view edits category, unit, default quantity, an interval override, snooze date, notes, stored shop articles, and archive state.
  • Shops — shop integrations. REWE is pre-seeded (disabled until configured); further generic shops can be added. Each shop has an enabled switch, a default flag, website URL, the browser profile the agent uses (see Settings → App-Verbindungen → persistent browser profiles), delivery or pickup, postal code, market, notes, and the name of its shop skill (see below).

All grocery data is workspace-global (household/organization level): every authenticated user of the instance sees and edits the same list, orders, products, and shops. created_by / added_by are attribution only. The one personal part is the browser profile picker, which lists the current user's own browser profiles (profiles hold personal login cookies).

The module is not installed by default. An admin enables it in the Module Store; the global migration db/migrations/333_grocery_module_default_off.sql keeps it off on legacy_all instances. Installing runs bundled-modules/grocery/migrations/001_create_grocery_schema.sql (tables grocery_settings, grocery_shops, grocery_products, grocery_orders, grocery_order_items, grocery_list_items); the handler also bootstraps the schema on first use.

Planning

  • Only placed and delivered orders count as purchase history; unavailable order items never count.
  • Order cadence = manual Bestellrhythmus (days) or the median gap between the last ten order dates (default 7 days).
  • Next order date = manual date (when today or later) or last order date + cadence (at least today); without any history: tomorrow. When an order is placed on or after a manual date, the manual date is cleared and the cadence takes over again.
  • Product interval = manual override or the median gap between the product's last eight purchase dates (needs two purchases). Next due date = last purchase + interval.
  • A product with automatisch planen is due when its next due date is closer to the next order than to the order after (due date ≤ next order date + half a cadence); soon within one more cadence.
  • Due products are added to the open list automatically (source Geplant, typical quantity = median of the last five purchases). Planning runs whenever the list or overview is loaded, after orders are placed, and on Jetzt planen. Deleting a planned item skips that product for the current order only (it is snoozed until the next order date).
  • Products bought three or more times are flagged as häufig and are good candidates for auto-planning.

Orders and the list

  • Adding a product that is already on the list merges the quantity (one list row per product).
  • Als bestellt markieren creates a placed order from all open/in-cart list items and removes them.
  • The agent records a filled shop cart as cart_prepared; the linked list items move to Im Warenkorb. When the order becomes placed/delivered, those items leave the list and feed the statistics; when it is cancelled or deleted, they return to Offen.
  • external_order_id is unique per shop, so importing a shop's order history twice is safe.
  • A shop's "already bought" catalog (REWE: Deine Produkte → Bereits gekauft) is imported with grocery_import_products / POST products/import: products are created or enriched with the exact shop article, without recording orders, so purchase frequencies are only learned from real orders.

Shop integrations and the agent

Shops are driven by the chat agent through the local browser tools (browser_open with the shop's browser_profile_id, browser_snapshot, browser_click, browser_type, browser_navigate, browser_read). Setup for REWE:

  1. Settings → App-Verbindungen → persistent browser profiles: create or pick a profile and sign in to rewe.de in the live view (ideally also choose Lieferservice/Abholservice and the market), then Finish sign-in.
  2. Grocery → Shops → REWE: enable it, select that browser profile, choose delivery or pickup, and store the postal code.
  3. On the list tab choose REWE and press Bestellung vorbereiten (or ask the agent in chat).

The agent then follows the bundled base skill clapilot-grocery (workspace-seed/skills/clapilot-grocery/SKILL.md) and the shop skill named on the shop (grocery-shop-rewe): it opens REWE with the profile, adds every open list item to the cart (reusing the article stored in shop_refs from earlier runs), records the order as cart_prepared with the chosen articles and prices, and hands off with request_browser_signin so the user reviews the cart in the live view and places the order. The agent never submits the order or payment. After the user confirms the order was placed, the agent (or the user in the Orders tab) sets the status to placed with the REWE order number.

Shop skills

Shop-specific know-how lives in an agent-maintained skill per shop (grocery-shop-<shop_key>):

  • For REWE the module ships a template (bundled-modules/grocery/skills/grocery-shop-rewe/SKILL.md) and installs it once into /app/workspace/skills/grocery-shop-rewe/ when the REWE shop is enabled or the shop list is loaded (never overwriting an existing copy). It is origin: agent and pinned: true, so the agent may edit it with skills_update and the Skill Curator leaves it alone; it survives reseeds and upgrades.
  • For other shops the agent creates grocery-shop-<shop_key> with skills_create on the first run and pins it.
  • After every shop run the agent extends the skill with what it learned (URLs, add-to-cart steps, cart location, quirks, household article preferences). Skills are visible under Module → Skills.

Agent tools

grocery_get_overview, grocery_list_items, grocery_add_items, grocery_update_item, grocery_remove_items, grocery_list_orders, grocery_get_order, grocery_record_order, grocery_update_order, grocery_list_products, grocery_update_product, grocery_import_products, grocery_plan_next_order, grocery_list_shops, grocery_update_shop — install-gated on the grocery module (native bundle grocery), available in chat and live agents, and via clapilot-cli grocery <action>. See Agent Tool Contracts for arguments and mutation semantics and API Reference for the module API.

The module page context (moduleSlug: grocery) activates a Grocery action rule, so questions like "what do we need?", "add oat milk", "we always need eggs every week", or "prepare the REWE order" are answered with the grocery tools instead of from memory. The module's Bestellung vorbereiten button posts clapilot:module-agent-prompt to the app shell, which sends the prepared request as a chat message (the same path as the Dashboard agent prompts).

Clients

Web

The bundled iframe module described above, including the Shops tab.

iOS and macOS

The Apple clients have a native SwiftUI Grocery screen in the side menu (MainAppSection.grocery, route /modules/grocery, shown only while the grocery module is installed; Views/GroceryView.swift and the Grocery* views next to it). It runs against the same module API (/api/modules/grocery/api/*) and never loads the web page for list, orders, or products. The top segmented control switches between three tabs:

  • Nächste Bestellung — the shared list grouped into Offen, Im Warenkorb, and Nicht verfügbar with sticky section headers. Rows show the source badge (Geplant, Agent, Nochmal bestellt), the note, the prepared cart, or the due date of a planned product, and a quantity stepper with the web module's steps (writes are debounced). Swiping a row removes it; on a planned row the action reads Überspringen and only skips the product for this order. A long-press or right-click menu changes the status. Tapping a row opens the item detail for name, quantity, unit, note, and status. It is a full-screen view on iPhone and a sheet on macOS. The planning surface shows the next order date and its source, the automatic-planning switch, the cadence and counters, Bald fällig products with an add button, and Jetzt planen. A prepared cart shows a notice that opens its order. On iPhone the add row (name, quantity, unit) and Bestellung vorbereiten stay anchored below the list. On macOS and iPad the add row sits above the list and the planning surface is a trailing column.
  • Bestellungen — compact rows with date, status chip, shop, item count, and total. The detail (full screen on iPhone, split pane with a collapsible list column on macOS) changes the status, shows the items with the exact shop article and link, and offers Nochmal bestellen and delete with a confirmation.
  • Produkte — server-side search and the filters Alle, Automatisch, Fällig, Häufig, and Archiviert. Each row has order count, interval, and next due date, plus the per-product automatic-planning switch. The detail shows the learned statistics and edits name, category, unit, default quantity, interval override, and notes. It also lists the stored shop articles, has Auf die Liste, and has the archive switch.

Bestellung vorbereiten sends the same localized request as the web button (agentPromptShop with the selected or default enabled shop and its agent_skill, or agentPromptNoShop). It uses the dashboard prompt path: the app switches to the chat and submits the message, and the Grocery page context (moduleSlug: grocery, groceryTab, openItemCount, nextOrderDate, the open order or product) stays attached so the agent uses the grocery tools. Shops stay web-only. Shops im Web verwalten opens the web module in an in-app sheet with the current session.