Skill: charliedouglas/gousto-meal-picker (version 1.2.1)

--- name: gousto-meal-picker description: "Automate weekly Gousto meal kit selection via REST API with configurable dietary rules (allergens, cook time, protein variety). Handles order updates, menu scoring, and token refresh via browser automation." metadata: openclaw: requires: bins: [node, curl, agent-browser] notes: "Requires zsh shell. agent-browser is only needed for initial login and token refresh (Gousto WAF blocks curl on auth endpoints)." --- # Gousto Meal Picker Automates weekly Gousto recipe selection via their REST API. No browser needed for picking — only for initial auth and token refresh. ## Setup ### 1. First-time auth (browser required) Use `agent-browser` to log into Gousto and save session state: ```bash agent-browser open "https://www.gousto.co.uk/my-gousto" --headed # User logs in manually (CAPTCHA blocks automated login) agent-browser state save <workspace>/gousto/gousto-auth.json agent-browser close ``` ### 2. Create config Create `<workspace>/gousto/config.json`: ```json { "userId": "<auth_user_id from /user/current>", "numericUserId": "<numeric id>", "deviceId": "<from gousto_session_id cookie>", "subscriptionId": "<from subscription endpoint>", "shippingAddressId": "<from order>", "deliveryTariffId": "<from order>", "plan": { "mealsPerWeek": 4, "portions": 2 }, "rules": { "maxCookTimeMins": 45, "maxMealsOver40Mins": 1, "noNuts": true, "noFish": true, "maxPastaPerWeek": 1, "maxRicePerWeek": 1, "preferHealthy": true } } ``` **No passwords or credentials are stored in config.json.** Auth is handled entirely via browser cookies saved in `gousto-auth.json` (from the login step above). The config only contains Gousto account IDs and selection rules. To discover IDs: log in via browser, then call `GET /user/current` and inspect a pending order via `GET /order/v2/orders/<id>`. See `references/api.md` for endpoint details. ### 3. Initialise selections tracker Create `<workspace>/gousto/selections.json`: ```json { "selections": {} } ``` ## Usage ### Run the picker ```bash node <skill-dir>/scripts/gousto-pick.mjs [--dry-run] [--week ORDER_ID] ``` - `--dry-run` — show what would be selected without updating the order - `--week ORDER_ID` — target a specific order instead of auto-detecting ### Recommended cron schedule Gousto menus open on **Tuesdays at 12pm UK**, 13 days before Monday delivery. Schedule the picker for **Tuesdays at 1pm UK**: ``` cron: "0 13 * * 2" (Europe/London) ``` ### Token refresh Auth tokens expire ~10 hours after login. When the token expires, the agent should: 1. Open Gousto in agent-browser (loads saved state → auto-refreshes) 2. Save updated state: `agent-browser state save <workspace>/gousto/gousto-auth.json` 3. Retry the script Auth endpoints are WAF-protected — curl cannot hit `/oauth/access-token` or `/login` directly. Browser-based refresh is the only reliable method. ## Selection Rules (all configurable) All rules are set in `config.json` under `"rules"`. Every filter can be toggled on/off. ### Hard filters (set to `true` to exclude) | Rule | Default | Description | |------|---------|-------------| | `noNuts` | `true` | Exclude recipes containing nuts (checks allergens + name) | | `noFish` | `true` | Exclude fish dishes | | `fishAndChipsException` | `false` | Allow fish & chips even when `noFish` is true | | `noSeafood` | `false` | Exclude all seafood (broader: crab, lobster, squid, etc.) | | `noVegetarian` | `true` | Exclude vegetarian meals | | `noPlantBased` | `true` | Exclude plant-based/vegan meals | | `noDairy` | `false` | Exclude dairy-containing meals | | `noGluten` | `false` | Exclude gluten-containing meals | | `maxCookTimeMins` | `45` | Exclude recipes over this cook time | | `excludeAllergens` | `[]` | Array of Gousto allergen slugs to exclude (e.g. `["sesame", "celery"]`) | | `excludeKeywords` | `[]` | Exclude recipes whose name contains any of these strings | ### Soft constraints (limits per week) | Rule | Default | Description | |------|---------|-------------| | `maxMealsOver40Mins` | `1` | Max meals with 40+ min cook time | | `maxPastaPerWeek` | `1` | Max pasta dishes | | `maxRicePerWeek` | `1` | Max rice dishes | | `maxSameProtein` | `2` | Max meals with the same protein | ### Scoring preferences | Rule | Default | Description | |------|---------|-------------| | `preferHealthy` | `true` | Boost healthy/low-cal recipes, penalise high-cal | | `preferQuicker` | `true` | Boost faster cook times | ### Example config ```json { "rules": { "noNuts": true, "noFish": false, "noVegetarian": false, "maxCookTimeMins": 30, "maxPastaPerWeek": 2, "excludeKeywords": ["spicy", "chilli"], "excludeAllergens": ["sesame"], "preferHealthy": false } } ``` ## Security notes - **No passwords stored** — auth uses browser cookies only (saved in `gousto-auth.json`) - **Treat `gousto-auth.json` as sensitive** — it contains OAuth tokens. Restrict file permissions (`chmod 600`) - **Single API endpoint** — the script only communicates with `production-api.gousto.co.uk` - **Use `--dry-run` first** — verify selections before enabling automated ordering - **Required runtime** — Node.js, curl, zsh shell, and agent-browser (for login/token refresh only) ## File structure ``` gousto/ ├── config.json — User config, API IDs, dietary rules ├── gousto-auth.json — Browser state (cookies with Bearer token) ├── selections.json — History of selections made ```


Security scan verdicts — ClawScan: clean | static analysis:  | VirusTotal: clean | SkillSpector: clean (LOW)