> "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.
Pro scans all 11 files and shows the line behind each finding
Scanned 10/6/2026
npx -y skills add SimHacker/moollm --skill groceries --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Groceries?
Add the live security badge to your README β it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/simhacker-groceries)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
# π 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
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!