---
name: groceries-ef3aaafc2678
description: "> \"Tea. Earl Grey. Hot. And add milk to the replicator queue.\""
---

# 🛒 GROCERIES

> "Tea. Earl Grey. Hot. And add milk to the replicator queue."

Dutch supermarket integration with smart shopping automation.
Sister scripts for Albert Heijn API, meal planning, and list management.

## Quick Start

```bash
# Anonymous (no login needed)
python scripts/ah.py search "hagelslag"
python scripts/ah.py bonus --week current
python scripts/ah.py stores --near "Amsterdam"

# Authenticated (requires 1Password setup)
python scripts/ah.py login
python scripts/ah.py receipts --limit 10
python scripts/ah.py orders
python scripts/ah.py list add "melk" "brood" "kaas"
```

## Architecture

**PUBLIC** — The tools (shareable):
```
moollm/skills/groceries/        # THIS REPO — Share freely
├── CARD.yml                    # Quick reference
├── SKILL.md                    # Protocol docs
├── scripts/
│   └── ah.py                   # Albert Heijn API client
├── templates/                  # Config templates
│   └── config.yml.tmpl
└── examples/                   # 🖖 Trekified examples
    ├── enterprise-galley.yml   # TNG: Ship's galley
    ├── ds9-replimat.yml        # DS9: Supply crisis
    ├── voyager-neelix.yml      # VOY: Neelix's kitchen
    └── klingon-kitchen.yml     # Warrior's guide to cooking
```

**PRIVATE** — Your data (your repo or local):
```
YourHome/household/shopping/    # YOUR REPO — Personal data
├── INDEX.yml                   # Master index
├── current-list.yml            # Today's shopping list
├── grocery/
│   ├── ah-cache.yml            # Product cache, favorites, deals
│   ├── meal-planning.yml       # Your recipes (English + Dutch terms)
│   ├── albert-heijn.yml        # Order history (if scraping)
│   └── delivery-apps.yml       # What you order (for recipe ideas)
└── zooplus.yml                 # Cat supplies (separate tracking OK)
```

**The Split:**
| PUBLIC (skill) | PRIVATE (your repo) |
|----------------|---------------------|
| ah.py script | Your product cache |
| API documentation | Your price tracking |
| Trek examples | Your deal alerts |
| Generic templates | Your shopping lists |
| How-to guides | Your order history |
| Recipe structures | Your actual recipes |

## Private Cache Usage

Your private repo stores the actual data. The public skill provides tools.

### ah-cache.yml (Your Repo)

Track products you buy, prices, and deals:

```yaml
# YourHome/household/shopping/grocery/ah-cache.yml

regulars:
  mexican_essentials:
    items:
      - product: "AH Rundergehakt"
        webshop_id: 123456  # From: ah.py search "rundergehakt" --json
        usual_qty: "750g"
        frequency: "weekly"

bonus_tracking:
  watch_list:
    - "Rundergehakt"
    - "Tortilla wraps"
    - "Avocado's"
  current_deals:
    week: 5
    relevant:
      - "Rundergehakt 500g: €4.49 (was €5.49)"

price_reference:
  rundergehakt_500g:
    normal: "~€5.50"
    good_deal: "<€4.50"
```

### Workflow

```bash
# 1. Check this week's bonus deals
python ah.py bonus --week current

# 2. Search for products you need
python ah.py search "rundergehakt"

# 3. Update your ah-cache.yml with:
#    - Product IDs (for list sync)
#    - Current bonus prices
#    - Price history

# 4. Generate shopping list based on:
#    - Weekly meal plan
#    - What's on bonus
#    - What's running low
```

---

## Credentials — 1Password Integration

Store your supermarket credentials in 1Password, retrieve via `op`:

```bash
# Setup (one time)
op signin

# The script uses:
op read "op://Personal/Albert Heijn/email"
op read "op://Personal/Albert Heijn/password"
```

### Config Template

Copy `templates/config.yml.tmpl` to `~/.moollm/skills/groceries/config.yml`:

```yaml
# ~/.moollm/skills/groceries/config.yml
# GITIGNORED — contains personal data

credentials:
  method: "1password"  # or "env" or "direct"
  
  # 1Password paths
  op:
    ah:
      email: "op://Personal/Albert Heijn/email"
      password: "op://Personal/Albert Heijn/password"
    jumbo:
      email: "op://Personal/Jumbo/email"
      password: "op://Personal/Jumbo/password"
      
  # Or environment variables
  # env:
  #   ah_email: "AH_EMAIL"
  #   ah_password: "AH_PASSWORD"

preferences:
  default_store: "ah"
  delivery_address: "Your address here"
  
  # Dietary preferences for suggestions
  diet:
    vegetarian: false
    vegan: false
    gluten_free: false
    lactose_free: false
    
  # Favorite brands (for SUGGEST)
  brands:
    coffee: ["Douwe Egberts", "Lavazza"]
    cheese: ["Old Amsterdam", "Beemster"]
```

## Albert Heijn API

### Endpoints

| Endpoint | Auth | Description |
|----------|------|-------------|
| `/mobile-auth/v1/auth/token/anonymous` | No | Get anonymous token |
| `/mobile-auth/v1/auth/token` | Login | Get user token |
| `/mobile-services/product/search/v2` | Anon | Search products |
| `/mobile-services/v1/receipts` | User | Get receipts |
| `/mobile-services/v2/receipts/{id}` | User | Get receipt details |
| `/mobile-services/shoppinglist/v2/items` | User | Manage shopping list |
| `/gql` | Varies | GraphQL (bonus, categories) |

### Headers Required

```
User-Agent: Appie/8.22.3
Content-Type: application/json
Authorization: Bearer {access_token}  # for authenticated requests
```

### Authentication Flow

```
1. Visit: https://login.ah.nl/secure/oauth/authorize?client_id=appie&redirect_uri=appie://login-exit&response_type=code
2. Login with credentials
3. Get redirected to: appie://login-exit?code=CODE
4. Exchange code for token:
   POST https://api.ah.nl/mobile-auth/v1/auth/token
   {"clientId": "appie", "code": "CODE"}
5. Receive: {"access_token": "...", "refresh_token": "...", "expires_in": 7199}
```

## Sister Script: ah.py

### Structure (follows sister-script pattern)

```python
#!/usr/bin/env python3
"""Albert Heijn API client — groceries skill sister script."""

import argparse
import json
import subprocess
from pathlib import Path
from dataclasses import dataclass
from enum import Enum
import requests

# CONFIGURATION
CONFIG_PATH = Path.home() / ".moollm/skills/groceries/config.yml"
TOKEN_CACHE = Path.home() / ".moollm/skills/groceries/.tokens.json"
API_BASE = "https://api.ah.nl"
USER_AGENT = "Appie/8.22.3"

# STATE
@dataclass
class AuthState:
    access_token: str | None = None
    refresh_token: str | None = None
    expires_at: float = 0

# CLI DEFINITION
def create_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description="Albert Heijn API client",
        epilog="See 'ah.py COMMAND --help' for details."
    )
    sub = parser.add_subparsers(dest="command")
    
    # SEARCH — Find products
    search = sub.add_parser("search", help="Search for products")
    search.add_argument("query", help="Search term")
    search.add_argument("--limit", type=int, default=10)
    search.add_argument("--bonus", action="store_true", help="Only bonus items")
    
    # BONUS — Get current deals
    bonus = sub.add_parser("bonus", help="Get bonus/sale items")
    bonus.add_argument("--week", default="current")
    bonus.add_argument("--category", help="Filter by category")
    
    # STORES — Find stores
    stores = sub.add_parser("stores", help="Find stores")
    stores.add_argument("--near", help="Location (city or coordinates)")
    stores.add_argument("--limit", type=int, default=5)
    
    # LOGIN — Authenticate
    sub.add_parser("login", help="Login to AH account")
    
    # RECEIPTS — Get purchase history
    receipts = sub.add_parser("receipts", help="Get receipts")
    receipts.add_argument("--limit", type=int, default=20)
    receipts.add_argument("--detail", help="Get specific receipt ID")
    
    # ORDERS — Get online orders
    orders = sub.add_parser("orders", help="Get online order history")
    orders.add_argument("--limit", type=int, default=10)
    
    # LIST — Manage shopping list
    list_cmd = sub.add_parser("list", help="Manage shopping list")
    list_sub = list_cmd.add_subparsers(dest="list_action")
    list_sub.add_parser("show", help="Show current list")
    list_add = list_sub.add_parser("add", help="Add items")
    list_add.add_argument("items", nargs="+", help="Items to add")
    list_clear = list_sub.add_parser("clear", help="Clear list")
    
    return parser

# IMPLEMENTATION
# (See full script in scripts/ah.py)
```

## Methods

### SEARCH — Find Products

```yaml
invoke: python scripts/ah.py search "kaas" --limit 5

example_output:
  - title: "AH Jong belegen kaas plakken"
    price: 2.49
    unit: "200g"
    bonus: true
    bonus_price: 1.99
```

### BONUS — Current Deals

```yaml
invoke: python scripts/ah.py bonus --week current

# Or via GraphQL for full details:
query: |
  query bonusCategories($input: PromotionSearchInput) {
    bonusCategories(filterSet: WEB_CATEGORIES, input: $input) {
      id
      title
      promotions {
        title
        price { now { amount } was { amount } }
      }
    }
  }
```

### LIST-SYNC — Sync to AH App

```yaml
invoke: python scripts/ah.py list add "melk" "brood" "eieren"

# Adds to AH shopping list via API:
# PATCH /mobile-services/shoppinglist/v2/items
# {"items": [{"productId": 123, "quantity": 1, "type": "SHOPPABLE"}]}
```

### RECEIPTS — Purchase History

```yaml
invoke: python scripts/ah.py receipts --limit 5

example_output:
  - transaction_id: "ABC123"
    date: "2026-01-28"
    store: "AH Amsterdam Centrum"
    total: 45.67
    items: 23
```

### ANALYZE — Pattern Analysis

```yaml
# After fetching receipts, analyze patterns:

patterns:
  most_bought:
    - "AH Halfvolle melk": 47 times
    - "AH Volkoren brood": 43 times
    - "Avocado": 38 times
    
  weekly_spend:
    average: "€127.50"
    min: "€45.00"
    max: "€210.00"
    
  shopping_days:
    saturday: 45%
    sunday: 30%
    wednesday: 15%
    
  bonus_usage:
    percent_bonus_items: "34%"
    estimated_savings: "€45/month"
```

## Trekified Examples

All examples use Star Trek terminology for safe public sharing:

### Enterprise Galley (examples/enterprise-galley.yml)

```yaml
# USS Enterprise NCC-1701-D — Deck 10 Forward Galley
# Trekified grocery data for safe sharing

ship: "🖖USS Enterprise NCC-1701-D"
location: "🖖Deck 10, Forward Section"
galley_chief: "🖖Lieutenant Commander Data (acting)"

replicator_queue:
  protein:
    - item: "🖖Replicated protein base (bovine)"
      english: "Ground beef"
      qty: "750g"
      
  produce:
    - item: "🖖Vulcan root vegetable"
      english: "Onion"
      qty: 2
    - item: "🖖Risan bell fruit"
      english: "Bell pepper"  
      qty: 3
      
  dairy:
    - item: "🖖Dairy matrix Type-7"
      english: "Sour cream"
      qty: 2
      priority: CRITICAL
      note: "🖖Captain's standing order"

commissary:
  preferred: "🖖Starbase 375 Commissary"
  backup: "🖖Deep Space 9 Promenade"
  
  account:
    officer: "🖖Captain Picard"
    contact: "🖖picard@starfleet.fed"
```

### DS9 Replimat (examples/ds9-replimat.yml)

```yaml
# Deep Space Nine — Promenade Replimat
# Quark's complaint: "The replicators are inferior to real food!"

station: "🖖Deep Space Nine"
establishment: "🖖Replimat (Promenade, Level 1)"
manager: "🖖Ensign Recurring Background Character"

inventory_issues:
  always_out_of:
    - "🖖Altarian mineral water (lime)"  # Jarritos
    - "🖖Bajoran spring wine"
    - "🖖Cardassian yamok sauce"
    
  overstocked:
    - "🖖Replicated tube grubs"
    - "🖖Synthesized gagh (dead)"

regular_orders:
  major_kira:
    usual: "🖖Raktajino, extra strong"
    frequency: "3x daily"
    
  odo:
    usual: "Nothing (doesn't eat)"
    frequency: "Judges others"
    
  quark:
    usual: "Real food, not replicated garbage"
    source: "🖖Personal suppliers (don't ask)"
```

## Integration with Your Repo

The groceries skill works with your personal MOOLLM repo:

```yaml
# In your repo: household/shopping/grocery/INDEX.yml

meta:
  skill: groceries
  integration:
    config: "~/.moollm/skills/groceries/config.yml"
    scripts: "moollm/skills/groceries/scripts/"
    
# Your real data stays in your repo
# Skill provides the automation
```

## Resources

### Libraries

| Language | Package | Status |
|----------|---------|--------|
| Go | `github.com/gwillem/appie-go` | Active (Jan 2026) |
| Node.js | `albert-heijn-wrapper` | Active |
| Python | `skills/groceries/scripts/ah.py` | This skill |

### Documentation

- **API Gist**: `gist.github.com/jabbink/8bfa44bdfc535d696b340c46d228fdd1`
- **GraphQL Schema**: `github.com/gwillem/appie-go/doc/graphql-schema-20260118.md`
- **OpenAPI Spec**: `github.com/NickBouwhuis/Albert-Heijn-OpenAPI`

### Community

- **Price Comparison**: `lijssie.nl` (AH, Jumbo, Dirk, Coop, etc.)
- **Gist Comments**: Active discussion on jabbink's gist

## See Also

- `skills/sister-script` — Script structure pattern
- `skills/trekify` — Privacy through technobabble
- `skills/inventory` — General inventory tracking


---
Source attribution: SimHacker
Original project: https://github.com/SimHacker/moollm/blob/b38fddeee4512e9111afe056cee4348097e54a3f/skills/groceries/SKILL.md
License: MIT
License information: https://opensource.org/license/mit
Original upstream instructions; downloaded from Dave AI.

## Upstream license notice

MIT License

Copyright (c) 2026 Don Hopkins

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



# Dave AI resource metadata

Creator / publisher: SimHacker
Original project: https://github.com/SimHacker/moollm/blob/b38fddeee4512e9111afe056cee4348097e54a3f/skills/groceries/SKILL.md
Attribution basis: Source repository record

Fields of work: Marketing, Sales
Roles: Customer Success Manager, Growth Marketer, Product Marketer
Specialties: API
Tools: Albert Heijn Api
Country applicability: Netherlands
Classification basis: Source catalog labels
Instruction SHA-256: fb592a451ed738c04462ebc804d9b54b2697bf69d11642e135f7afdc1ed4dc18
