Command-line interface for nemlig.com Danish online grocery store. Single-file Python implementation using requests for HTTP and argparse for CLI parsing.
- Product search and details
- Shopping basket management (view, add and remove items)
- Order history viewing
- Python >= 3.11
- uv package manager
- Credentials for nemlig.com account
# Set credentials as environment variables
export NEMLIG_USER="your@email.com"
export NEMLIG_PASS="yourpassword"Search, basket and order history need nothing beyond requests. The remaining
features pull in heavier dependencies and are installed as extras:
| Extra | Enables | Commands |
|---|---|---|
ai |
AI meal planning | plan |
sheets |
Google Forms/Sheets recipe import | import |
scanner |
Barcode and produce scanning | scan, fridge |
all |
Everything above |
uv sync --extra all # or: --extra ai --extra scannerAll commands are available via the justfile:
just search "cocio" # Search products
just details 701025 # Product details
just basket # View basket
just add 701025 2 # Set product quantity (quantity optional, default 1)
just add 701025 0 # Remove product from basket
just history # Order history
just history 12345678 # Order detailsDirect execution:
uv run python nemlig_cli.py -u "$NEMLIG_USER" -p "$NEMLIG_PASS" search "milk"Single file design: All logic in nemlig_cli.py - a straightforward requests-based client.
Authentication: 3-step flow (XSRF token -> Bearer token -> Login). Returns AuthTokens dataclass passed to all API functions.
Dual API endpoints: Main site API (nemlig.com/webapi/*) for auth and basket operations; separate search gateway (webapi.prod.knl.nemlig.it) for product search.
See nemlig_api.md for complete API documentation including request/response schemas.
This project was built by having Claude Code control a real browser to observe and document the nemlig.com API. The technique generalizes to any web application where you need to reverse-engineer an undocumented API.
The workflow enables an AI assistant to control a real browser, observe network traffic, and document API behavior - then implement a client based on the documented findings.
The Chrome DevTools MCP integration is fully self-contained:
.mcp.json- MCP server configuration pointing to the wrapper scriptchrome-devtools-mcp-wrapper.sh- Nix-shell wrapper ensuring reproducible environment with:- Pinned nixpkgs (nixos-25.05) for reproducibility
- Node.js 22 and Chromium from nix
- Project-local Chrome profile (
.chrome-profile/) to avoid tainting global settings - Pinned
chrome-devtools-mcpversion (0.10.1)
No global installation required - the wrapper script handles everything.
Phase 1: Network Traffic Capture
Human operator directs Claude to:
- Open target page with network recording enabled
- Perform the operation being documented (login, search, add to cart, etc.)
- List network requests to see all HTTP traffic
- Get request details for interesting endpoints (headers, body, response)
Example session:
Human: Open nemlig.com and enable network recording. Then login with test credentials and show me the network traffic.
Claude: [Uses Chrome DevTools MCP to navigate, perform login, capture traffic]
[Lists network requests, identifies auth flow]
[Documents the 3-step auth: AntiForgery -> Token -> login]
Phase 2: Documentation
Claude analyzes captured traffic and documents:
- Request URLs, methods, headers
- Request/response body structure
- Authentication requirements
- Parameter meanings
This builds up nemlig_api.md incrementally.
Phase 3: Implementation
Based on the documented API:
- Claude implements Python functions matching documented endpoints
- Human tests implementation against real site
- Debug issues using Chrome DevTools MCP as grounding (compare browser vs client behavior)
Important: MCP tool calls return large responses (>25KB for page snapshots/network dumps). To manage context window size:
- Run all MCP interactions from a sub-agent (Task tool with explore or general-purpose agent)
- Sub-agent summarizes findings and returns only relevant info
- Main conversation stays focused on implementation
Example pattern:
Human: Document the basket API
Claude: [Spawns sub-agent to handle MCP interactions]
Sub-agent: [Opens page, enables recording, adds item to basket]
[Captures AddToBasket request/response]
[Returns summary: endpoint, headers, body format, response structure]
Claude: [Updates nemlig_api.md with documented endpoint]
When the Python client behaves differently than expected:
- Perform same operation in browser via MCP
- Compare exact request headers/body
- Identify missing headers, wrong parameter format, etc.
- Fix client implementation
This provides a reliable reference for expected API behavior.
nemlig-cli/
├── .mcp.json # MCP server configuration
├── chrome-devtools-mcp-wrapper.sh # Nix-shell wrapper for MCP server
├── .chrome-profile/ # Local browser profile (gitignored)
├── arch_api.drawio.svg # API architecture diagram
├── mcp-workflow.drawio.svg # MCP workflow diagram
├── nemlig_api.md # API documentation (built via workflow)
├── nemlig_cli.py # Python client implementation
├── justfile # Command shortcuts
├── pyproject.toml # Python project config
└── CLAUDE.md # AI assistant instructions
MIT