| name | karrt |
| description | 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. |
REWE Grocery Shopping
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.
First-Time Setup
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.
Quick Reference
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.
How to Run Commands
cd ~/karrt && node dist/cli.js <command>
If you get an error about missing dist/, build first: npm run build
Date & Time Handling
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:
- Convert "tomorrow" / "next Tuesday" / "this weekend" into actual dates
- Present timeslots as human-readable day names ("Tuesday 08:00–09:00") relative to now
- All API timestamps are UTC — convert to Europe/Berlin (UTC+1 winter, UTC+2 summer) when presenting to the user
- REWE typically does not offer Sunday pickup
Authentication
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.
Searching for Products
The Category Filter (Important!)
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).
Category Slug Reference
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.
Search Strategy
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:
- Do a quick search without
--category first
- Check the
categoryPath field in the results to discover the right slug
- Re-search with
--category for clean results
Finding the Cheapest Option
Always 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.
Search Strategy for Recipes / Meal Planning
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.
Attribute Filters
| 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
Understanding Product Quality Labels
Bio/Organic: Use --organic flag. Brands: "REWE Bio", "ja! Natürlich", "Demeter", "Bioland".
Haltungsform (animal welfare tiers): NOT a search filter — check product names:
- Haltungsform 1 (Stallhaltung) — basic factory farming, cheapest
- Haltungsform 2 (StallhaltungPlus) — slightly better conditions
- Haltungsform 3 (Außenklima) — outdoor access
- Haltungsform 4 (Premium) — highest welfare, most expensive
- Bio/organic meat is typically Haltungsform 4
REWE Brand Tiers (cheapest → most expensive):
- "ja!" — Budget brand, cheapest for most staples
- "REWE Beste Wahl" — Mid-tier quality
- "REWE Bio" — Organic line
- "REWE Feine Welt" — Premium/gourmet
Understanding Search Results
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.
Basket Management
Adding Items
karrt basket add "8-1234567-890123" --qty 2
Building a Shopping List
When the user asks you to shop for a recipe or meal:
- Clear the basket first (if they want a fresh start):
karrt basket clear
- Search each ingredient with
--sort PRICE_ASC --category <slug> for budget-conscious shopping
- Pick the best match — consider: price, brand (ja! = cheapest), size, and whether it matches
- Add each item to the basket
- Show a summary with item names, quantities, and total cost
- Check timeslots if the user wants to pick up
Bulk Add
For 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}]'
Viewing the Basket
karrt basket show
The response includes:
lineItems: each item with name, quantity, price, totalPrice
summary.totalPrice: basket total in cents
staggerings: free pickup thresholds (usually 50€ for free pickup)
Free Pickup Threshold
REWE charges a pickup fee (usually 2€) for baskets under 50€. The basket response includes staggerings info:
reachedStaggering.displayText — current fee tier
nextStaggering.remainingArticlePrice — cents needed to reach the next (cheaper/free) tier
When 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.
Clearing the Basket
karrt basket clear
This removes all items one by one. It's not instant for large baskets.
Timeslots & Pickup
karrt timeslots
The response includes a now field with the current date/time. Use this to present slots as readable days.
- REWE pickup is available most days, typically 08:00–18:00 hourly slots
- Timeslot IDs look like UUIDs — pass them to
karrt timeslot-reserve <slotId>
- Reservations expire (usually ~30 min) — reserve close to when the user wants to finalize
- The
serviceFee in the response is in cents (0 = free pickup, usually when basket > 50€)
Smart Shopping Patterns
"Find me the cheapest X"
karrt search "X" --sort PRICE_ASC --category <appropriate-slug>
Report the top 1-3 results with name, price, and grammage.
"Get me ingredients for [dish]"
- Think through what ingredients the dish needs
- Search each one with
--sort PRICE_ASC --category <slug>
- Pick one product per ingredient (prefer ja! brand for budget, REWE Bio for organic)
- Add all to basket
- Report: what you picked, individual prices, total
"What's on offer?"
karrt search "Obst" --offers --category frisches-obst
"Show me organic/bio options for X"
karrt search "X" --organic --category <slug>
"Suggest items to fill my cart for free pickup"
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 Handling
| 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.
Presenting Results to the User
- Prices: Always in euros with 2 decimal places (e.g., "0.85€")
- Products: Name + brand + price + grammage on one line
- Basket summaries: Table or list format with total at the bottom
- Timeslots: Group by day, show as "Tuesday 08:00–09:00" not raw ISO timestamps
- Keep it concise: The user is on Telegram — short messages, no walls of JSON
- Use German product names: Don't translate "Hähnchenbrustfilet" to "chicken breast fillet" in the summary — keep the original name so the user recognizes it at pickup