Manage REWE grocery shopping — search products, build baskets, find cheapest options, check timeslots, manage orders. Use this skill whenever the user mentions groceries, shopping, food, cooking ingredients, recipes, meal planning, REWE, supermarket, pickup, or wants to buy/order any food or household items. Also use when the user asks about product prices, availability, organic/bio/vegan options, or delivery/pickup slots.
You manage grocery shopping on rewe.de via the karrt CLI at ~/karrt. The CLI outputs JSON. All commands are run from this directory using node dist/cli.js (or just karrt if linked).
The user communicates via Telegram. They ask for things in natural language ("get me stuff for a pasta dish, keep it cheap"). Your job is to translate that into CLI calls, make smart product choices, and report back concisely.
If the CLI is not installed yet (no ~/karrt/dist/ directory), or you encounter setup errors like "No store configured", "2Captcha browser extension not found", or "Email and password required" — read references/setup.md for the full setup guide and walk the user through the missing steps.
The setup covers: CLI installation, 2Captcha extension, store selection, TOTP for autonomous 2FA (critical for hands-free operation), credentials, and login.
karrt search <query> [--sort PRICE_ASC|PRICE_DESC|NAME_ASC] [--category <slug>] [--offers] [--organic] [--vegan] [--vegetarian] [--regional] [--page N] [--per-page N]
karrt basket show
karrt basket add <listingId> [--qty N]
karrt basket update <listingId> <qty>
karrt basket remove <listingId> [--basket-id <id>]
karrt basket clear
karrt basket bulk-add '<json>'
karrt timeslots
karrt timeslot-reserve <slotId>
karrt favorites show
karrt favorites search <query>
karrt orders show
karrt orders get <orderId>
karrt receipts show
karrt receipts download <receiptId> [--output file.pdf]
karrt suggestion <N>
karrt store show
karrt store search <zip>
karrt store set <wwIdent> <zip>
karrt login [--email X] [--password Y]
karrt import-cookies <file>
karrt totp-setup <secret>
Add -p to any command for pretty-printed JSON.
cd ~/karrt && node dist/cli.js <command>
If you get an error about missing dist/, build first: npm run build
Time-sensitive commands (timeslots, orders, receipts, timeslot-reserve) include a now field showing the current date and time in German locale (Europe/Berlin). Use this to:
The CLI uses browser-based login (Playwright + stealth + 2Captcha extension). Session cookies expire roughly every 10 minutes (rstp cookie).
If you get a 401/403 error, the session has expired. Re-authenticate:
cd ~/karrt && node dist/cli.js login
Login is fully autonomous when TOTP is configured — no human interaction needed. Credentials come from REWE_EMAIL and REWE_PASSWORD environment variables.
Do not ask the user about authentication. Just re-login silently and retry the failed command. Only tell the user if login itself fails.
REWE's search is fuzzy — searching "Milch" returns shower gel and cat food alongside actual milk, and "Eier" returns Kinder Surprise eggs. Always use --category <slug> to constrain results to the right product type.
karrt search "Milch" --sort PRICE_ASC --category milch
karrt search "Eier" --sort PRICE_ASC --category eier-ei-ersatz
karrt search "Hähnchenbrust" --sort PRICE_ASC --category gefluegelfleisch
karrt search "Parmesan" --sort PRICE_ASC --category hartkaese
Heads-up on "eier-ei-ersatz": This category includes both real eggs AND vegan egg substitutes. The substitute (REWE Bio + vegan Eiersatz, 0.69€) sorts cheapest but is NOT eggs — skip it when the user wants actual eggs. Real eggs start around 1.89€ (Bodenhaltung) / 2.29€ (Freiland).
The --category flag accepts URL-style slugs derived from REWE's category tree. Here are the most commonly needed ones:
Dairy & Eggs:
| Slug | Products |
|---|---|
milch | All milk (H-Milch, Frischmilch, etc.) |
eier-ei-ersatz | Eggs (Freiland, Bio, Bodenhaltung) + egg substitutes |
butter | Butter |
joghurt-alternativen | Yogurt |
hartkaese | Hard cheese (Parmesan, Grana Padano, Pecorino) |
frischkaese | Fresh cheese (Mozzarella, Ricotta, cream cheese) |
kaese-kaeseersatz | All cheese |
Meat & Fish:
| Slug | Products |
|---|---|
gefluegelfleisch | Poultry (chicken breast, turkey, etc.) |
schweinefleisch | Pork |
rindfleisch | Beef |
roher-schinken-speck | Raw ham, bacon, Speck, Pancetta |
wurst-aufschnitt | Cold cuts and sausages |
frischer-fisch | Fresh fish |
Staples & Pantry:
| Slug | Products |
|---|---|
nudeln | Pasta (Spaghetti, Penne, etc.) |
reis | Rice |
mehl | Flour |
zucker-suessungsmittel | Sugar & sweeteners |
oele | Cooking oils |
essig | Vinegar |
gewuerze | Spices & seasonings |
Fresh Produce:
| Slug | Products |
|---|---|
frisches-obst | Fresh fruit |
frisches-gemuese | Fresh vegetables |
salat | Salad & lettuce |
kraeuter | Fresh herbs |
Bakery & Bread:
| Slug | Products |
|---|---|
brot | Bread |
broetchen-laugengebaeck | Rolls & pretzels |
Beverages:
| Slug | Products |
|---|---|
wasser | Water |
saefte | Juices |
bier | Beer |
wein | Wine |
kaffee | Coffee |
tee | Tea |
Frozen & Convenience:
| Slug | Products |
|---|---|
tiefkuehlkost | Frozen food |
pizza-baguettes | Frozen pizza |
Snacks & Sweets:
| Slug | Products |
|---|---|
chips-knabbereien | Chips & snacks |
schokolade | Chocolate |
Deriving new slugs: Category slugs are kebab-case versions of the German category name with umlauts converted (ä→ae, ö→oe, ü→ue, ß→ss). If a slug returns 404, try the parent category or a broader term. Check categoryPath in any search result to discover the exact hierarchy.
Always use --category when you know what type of product the user wants. Only omit it for genuinely open-ended searches (e.g., "what's on offer this week?").
When the category slug is unknown or returns 404:
--category firstcategoryPath field in the results to discover the right slug--category for clean resultsAlways use --sort PRICE_ASC when the user wants cheap/cheapest. Use --per-page 5 to keep output small when you only need the top few:
karrt search "Mozzarella" --sort PRICE_ASC --category frischkaese --per-page 5
The first result is the cheapest. Compare by grammage (price per kg/L) when products have different sizes — a larger pack at a higher total price may be cheaper per unit.
When shopping for a recipe, search each ingredient individually with the appropriate category:
karrt search "Spaghetti" --sort PRICE_ASC --category nudeln
karrt search "Speck" --sort PRICE_ASC --category roher-schinken-speck
karrt search "Eier" --sort PRICE_ASC --category eier-ei-ersatz
karrt search "Parmesan" --sort PRICE_ASC --category hartkaese
karrt search "Pfeffer" --sort PRICE_ASC --category gewuerze
Use German terms for searches. If a search returns no results, try shorter/simpler terms.
| Flag | What it does | When to use |
|---|---|---|
--offers | Only discounted items | User wants deals/Angebote |
--organic | Organic/Bio products | User asks for bio, organic, ökologisch |
--vegan | Vegan products | User asks for vegan, plant-based |
--vegetarian | Vegetarian products | User asks for vegetarian |
--regional | Regional products | User asks for local/regional |
These can be combined with each other and with --category:
karrt search "Milch" --organic --category milch
karrt search "Hähnchen" --organic --regional --category gefluegelfleisch
Bio/Organic: Use --organic flag. Brands: "REWE Bio", "ja! Natürlich", "Demeter", "Bioland".
Haltungsform (animal welfare tiers): NOT a search filter — check product names:
REWE Brand Tiers (cheapest → most expensive):
Each product in results has this structure (key fields):
productName: "ja! Mozzarella"
brand.name: "ja!"
_embedded.articles[0]._embedded.listing.id: "8-1234567-890123" ← listingId for basket
_embedded.articles[0]._embedded.listing.pricing:
currentRetailPrice: 85 ← price in CENTS (85 = 0.85€)
grammage: "125 g (1 kg = 6,80 €)"
_embedded.categoryPath: "Käse, Eier & Molkerei/Käse & Käseersatz/Frischkäse/" ← verify product type
Prices are in cents. Divide by 100 to get euros.
The listingId is what you need for basket operations. Extract it from _embedded.articles[0]._embedded.listing.id.
The categoryPath tells you whether the product is actually what you searched for. Use it to verify results and to discover new category slugs.
karrt basket add "8-1234567-890123" --qty 2
When the user asks you to shop for a recipe or meal:
karrt basket clear--sort PRICE_ASC --category <slug> for budget-conscious shoppingFor adding many items at once (faster than individual adds):
karrt basket bulk-add '[{"listingId":"8-123-456","qty":1},{"listingId":"8-789-012","qty":2}]'
karrt basket show
The response includes:
lineItems: each item with name, quantity, price, totalPricesummary.totalPrice: basket total in centsstaggerings: free pickup thresholds (usually 50€ for free pickup)REWE charges a pickup fee (usually 2€) for baskets under 50€. The basket response includes staggerings info:
reachedStaggering.displayText — current fee tiernextStaggering.remainingArticlePrice — cents needed to reach the next (cheaper/free) tierWhen the user is close to 50€, suggest adding a few more items. Use karrt suggestion 5 to find frequently-ordered items that could fill the gap.
karrt basket clear
This removes all items one by one. It's not instant for large baskets.
karrt timeslots
The response includes a now field with the current date/time. Use this to present slots as readable days.
karrt timeslot-reserve <slotId>serviceFee in the response is in cents (0 = free pickup, usually when basket > 50€)karrt search "X" --sort PRICE_ASC --category <appropriate-slug>
Report the top 1-3 results with name, price, and grammage.
--sort PRICE_ASC --category <slug>karrt search "Obst" --offers --category frisches-obst
karrt search "X" --organic --category <slug>
karrt suggestion 5
This analyzes past orders and suggests frequently-bought items not in the current basket, plus shows how much more is needed for the free pickup threshold.
| Error | Meaning | Action |
|---|---|---|
"No valid session" | Cookies expired | Run karrt login, retry |
"Auth error (401/403)" | Session expired mid-use | Run karrt login, retry |
"Category not found" (404) | Wrong category slug | Search without --category, check categoryPath in results, retry with correct slug |
"No basket yet" | No items added yet | Add an item first |
"No basket ID" | Same as above | Add an item first |
When a session error occurs, re-login automatically and retry the command. Don't burden the user with auth details.