Skill: zahlmann/bring-shopping-list (version 1.0.0)

--- name: bring-shopping-list description: Use when asked about the shopping list, groceries, "add to shopping list", "what's on the list", "remove from list", or any shopping/grocery related request. Integrates with the Bring! shopping list app. argument-hint: "[add|remove|list] [items...]" user-invocable: false metadata: openclaw: requires: env: - BRING_EMAIL - BRING_PASSWORD bins: - uv primaryEnv: BRING_EMAIL --- # Bring! Shopping List Manage a Bring! shopping list — add items, remove items, mark items as completed, and check what's on the list. ## Setup 1. Install [uv](https://docs.astral.sh/uv/) if not already installed 2. Set environment variables for your Bring! account: ```bash export BRING_EMAIL="[REDACTED_SECRET]" export BRING_PASSWORD="your-password" ``` Or add them to a `.env` file in your project root. > If you use Google login for Bring!, go to your Bring! account settings and set a separate password first. ## Usage All commands use `bring.py` in this skill's directory. Adjust the path based on where you installed the skill. ### With uv (recommended) ```bash uv run --with bring-api --with python-dotenv python bring.py list --json uv run --with bring-api --with python-dotenv python bring.py add "Milk" "Eggs" "Butter:Irish" uv run --with bring-api --with python-dotenv python bring.py remove "Milk" uv run --with bring-api --with python-dotenv python bring.py complete "Eggs" ``` ### With pip ```bash pip install -r requirements.txt python bring.py list --json python bring.py add "Milk" "Eggs" "Butter:Irish" python bring.py remove "Milk" python bring.py complete "Eggs" ``` ## Handling Requests 1. Parse the user's message for: - Items to add ("add milk and eggs to the list") - Items to remove ("remove milk from the list") - Checking the list ("what's on the shopping list?") - Item details/specs ("milk, but low fat" -> `Milk:low fat`) 2. Run the appropriate CLI command 3. Confirm the action naturally ## Notes - Requires `BRING_EMAIL` and `BRING_PASSWORD` environment variables - Items can have optional specs via colon syntax: `name:specification` - Uses the first (default) shopping list in the account - Dependencies (`bring-api`, `python-dotenv`) are handled inline by `uv run --with`, or via `pip install -r requirements.txt`

path: requirements.txt
content: bring-api
python-dotenv


path: README.md
content: # bring-shopping-list

An agent skill for managing [Bring!](https://www.getbring.com/) shopping lists. Add, remove, complete, and view items on your Bring! shopping list through natural language.

Compatible with Claude Code, Cursor, Windsurf, OpenAI Codex CLI, GitHub Copilot, Gemini CLI, and other agents supporting the [SKILL.md standard](https://agentskills.io/specification).

## Installation

Copy this folder into your agent's skills directory:

```bash
# Claude Code
cp -r bring-shopping-list ~/.claude/skills/

# Cursor
cp -r bring-shopping-list ~/.cursor/skills/

# Codex CLI
cp -r bring-shopping-list ~/.codex/skills/

# or project-specific (example for Claude Code)
cp -r bring-shopping-list your-project/.claude/skills/
```

### Requirements

- Python 3.10+
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
- A Bring! account with email/password login

> **Google login users:** Go to your Bring! account settings and set a separate password for API access.

### Environment Variables

Set these in your shell or in a `.env` file:

```bash
BRING_EMAIL=[REDACTED_SECRET]
BRING_PASSWORD=your-password
```

## Usage

Once installed, your agent will automatically use this skill when you ask about shopping or groceries:

- "Add milk and eggs to the shopping list"
- "What's on my list?"
- "Remove butter from the list"

### CLI

#### With uv (recommended, no install needed)

```bash
uv run --with bring-api --with python-dotenv python bring.py list
uv run --with bring-api --with python-dotenv python bring.py add "Milk" "Eggs" "Butter:unsalted"
uv run --with bring-api --with python-dotenv python bring.py remove "Milk"
uv run --with bring-api --with python-dotenv python bring.py complete "Eggs"
```

#### With pip

```bash
pip install -r requirements.txt
python bring.py list
python bring.py add "Milk" "Eggs" "Butter:unsalted"
python bring.py remove "Milk"
python bring.py complete "Eggs"
```

Items support optional specifications via colon syntax: `"Milk:low fat"`, `"Butter:Irish"`.

## How It Works

The skill uses the unofficial [bring-api](https://github.com/miaucl/bring-api) Python package to interact with Bring's API. It authenticates with your credentials, finds your default shopping list, and performs operations on it.

## License

MIT


path: bring.py
content: """Bring! shopping list CLI — add, remove, complete, and list items."""

import argparse
import asyncio
import json
import os

import aiohttp
from bring_api import Bring
from dotenv import load_dotenv

load_dotenv()

EMAIL = os.environ["BRING_EMAIL"]
[REDACTED_SECRET]"BRING_PASSWORD"]


async def get_bring():
    session = aiohttp.ClientSession()
    bring = Bring(session, EMAIL, PASSWORD)
    await bring.login()
    return bring, session


async def get_default_list(bring):
    response = await bring.load_lists()
    if not response.lists:
        raise RuntimeError("No shopping lists found in Bring account")
    return response.lists[0]


async def cmd_list(args):
    bring, session = await get_bring()
    try:
        lst = await get_default_list(bring)
        items = await bring.get_list(lst.listUuid)
        result = {
            "list_name": lst.name,
            "items": [
                {"name": item.itemId, "spec": item.specification}
                for item in items.items.purchase
            ],
            "recently_completed": [
                {"name": item.itemId, "spec": item.specification}
                for item in items.items.recently
            ],
        }
        if args.json:
            print(json.dumps(result, ensure_ascii=False, indent=2))
        else:
            if result["items"]:
                print(f"{result['list_name']}:")
                for item in result["items"]:
                    spec = f" ({item['spec']})" if item["spec"] else ""
                    print(f"  - {item['name']}{spec}")
            else:
                print("Shopping list is empty!")
    finally:
        await session.close()


async def cmd_add(args):
    bring, session = await get_bring()
    try:
        lst = await get_default_list(bring)
        for item in args.items:
            parts = item.split(":", 1)
            name = parts[0].strip()
            spec = parts[1].strip() if len(parts) > 1 else ""
            await bring.save_item(lst.listUuid, name, spec)
        names = [i.split(":")[0].strip() for i in args.items]
        print(json.dumps({"added": names, "list": lst.name}))
    finally:
        await session.close()


async def cmd_remove(args):
    bring, session = await get_bring()
    try:
        lst = await get_default_list(bring)
        for item in args.items:
            await bring.remove_item(lst.listUuid, item.strip())
        print(json.dumps({"removed": args.items, "list": lst.name}))
    finally:
        await session.close()


async def cmd_complete(args):
    bring, session = await get_bring()
    try:
        lst = await get_default_list(bring)
        for item in args.items:
            await bring.complete_item(lst.listUuid, item.strip())
        print(json.dumps({"completed": args.items, "list": lst.name}))
    finally:
        await session.close()


def main():
    parser = argparse.ArgumentParser(description="Bring! shopping list CLI")
    sub = parser.add_subparsers(dest="command", required=True)

    p_list = sub.add_parser("list", help="Show current shopping list")
    p_list.add_argument("--json", action="store_true", help="JSON output")

    p_add = sub.add_parser("add", help="Add items to the list")
    p_add.add_argument("items", nargs="+", help="Items to add (use 'name:spec' for details)")

    p_remove = sub.add_parser("remove", help="Remove items from the list")
    p_remove.add_argument("items", nargs="+", help="Items to remove")

    p_complete = sub.add_parser("complete", help="Mark items as completed")
    p_complete.add_argument("items", nargs="+", help="Items to complete")

    args = parser.parse_args()

    commands = {
        "list": cmd_list,
        "add": cmd_add,
        "remove": cmd_remove,
        "complete": cmd_complete,
    }
    asyncio.run(commands[args.command](args))


if __name__ == "__main__":
    main()


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