pranaysuyash/shopstack

Local-first, off-the-grid household inventory management with Gradio UI, SQLite persistence, and swappable provider interfaces.

0

stars

118

commits

Python

primary language

Aug 26, 2026

updated

README


title: ShopStack emoji: 🛒 colorFrom: green colorTo: blue sdk: docker pinned: false tags: [shopstack, inventory, shopping, offline-first, household, fastapi]

ShopStack

Doc links: Several links in this README point to Docs/ paths that are intentionally local-only (see Docs/README.md). They work in a local workspace but 404 from a clean clone. For canonical architecture, see shopstack/module_registry.py and the code under shopstack/. Git-tracked docs (MODEL_CATALOG.md, this README) are reachable from any clone.

Local-first, off-the-grid shopping intelligence platform. Know what you have, what to use soon, what to buy, what to skip, and where to buy from — without sending your data to the cloud.

ShopStack is a stack of shopping intelligence layers: home inventory (ShopStock), shopping lists and market baskets (ShopBasket), retailer price comparison (ShopCompare), scanning and import (ShopLens), price history and preferences (ShopMemory), and a reasoning agent (ShopAgent) that decides buy/skip/use-soon across all modules.

Philosophy

ShopStack runs entirely locally — SQLite database (WAL mode), mockable provider interfaces, and an API-first FastAPI frontend shell that works offline. The "Off the Grid" path means zero cloud dependencies for core functionality. The default mock providers let you build and test the full app without loading any ML models.

Total parameter limit: ≤32 billion parameters across all loaded models.

Modules

ModulePurpose
ShopStockInventory, pantry, fridge, expiry, low-stock, use-soon
ShopBasketShopping list, cart builder, market basket optimization
ShopCompareRetailer price comparison (Swiggy, Blinkit, Zepto, ...)
ShopLensScanning: barcode, photo, receipt, barcode
ShopMemoryPrice history, household preferences, field notes
ShopAgentReasoning: buy/skip/use-soon/compare decisions
SourcesRetailer datasets (Swiggy Instamart + future)

See Docs/ARCHITECTURE.md for the full system architecture and Docs/SERVICES_ARCHITECTURE.md for the service layer.

Frontend Shell

ShopStack is organized around workflow experiences in the FastAPI shell:

  • Today — Decision-first dashboard: what to buy, skip, use soon, and compare
  • Ask ShopStack — Natural language queries across all modules
  • Shopping List — Create, classify (buy/skip/use-soon), and complete shopping plans
  • Market Lens — Scan items via camera or voice, compare to inventory
  • Add Purchase — Record what was bought (price, store, location)
  • Find Item at Home — Search inventory by location and status
  • Use Soon — Expiring and aging items flagged for attention
  • Price Memory Check — Price history, trends, and best-store intelligence
  • Traces — Workflow audit trail with redacted export
  • Field Notes — Household notes and preferences

Quick Start

uv venv --python 3.13
uv pip install -e ".[dev]"
uv run python app.py

Open http://localhost:7860 in your browser.

Market Snapshot Import

ShopStack can ingest the real Swiggy Instamart fresh vegetables snapshot found in data/swiggy_fresh_vegetables_cards_6jun26.json (or the matching CSV) into the local price observation database.

uv run python scripts/import_swiggy_snapshot.py

Imported observations are tagged with source_event_id = swiggy_fresh_vegetables_20260606 so they can be filtered or audited later.

Tests

uv run pytest tests/ -v
uv run pytest benchmarks/ -v -m benchmark

Run uv run pytest tests/ --collect-only -q for the current test count.

Current Verified by Code Inspection

As of the current code inspection, the following metrics are verified:

  • 26 Database Tables, 2 Views, 2 Triggers, 10 Indexes: app_config, condition_events, correction_events, find_feedback, household_locations, household_members, household_objects, households, inventory_events, inventory_lots, market_record_components, market_records, market_snapshots, movement_events, negative_memory, object_notes, object_sightings, person_associations, preference_signals, price_observations, purchase_events, reconciliation_events, shopping_list_items, shopping_lists, stores, traces (Tables), price_history, agent_traces (Views).
  • 17 Tools: Including semantic_find_item.

Note: For the canonical current-state metrics, run python3 scripts/repo_truth.py. The README is updated when new tables/tabs/tools are added; do not hand-maintain these numbers.

Engineering Mandate: Do not narrow scope to hackathon/MVP. ShopStack is designed as a long-term, bold, and comprehensive intelligence platform. Follow motto_v5.md principles exactly.

Project Structure

shopstack/
  __init__.py
  _version.py               # v0.1.0
  config.py                 # Settings (pydantic-settings, env prefix SHOPSTACK_)
  model_registry.py         # 58 model entries (10 active / 46 candidate / 2 rejected; all ≤32B total active)
  schemas/
    models.py               # All Pydantic domain models (14+ classes, 16 enums)
  providers/
    interfaces.py           # 11 abstract provider ABCs
    mock_providers.py       # Full mock implementations for all 11 (Indian/Hinglish data)
    registry.py             # ProviderRegistry factory wired to Settings
  persistence/
    database.py             # SQLite Database (WAL, 26 tables, 2 views, 2 triggers, 10 indexes, full CRUD)
  services/                 # Business logic services (decision engine, shopping, dashboard, preferences, freshness)
  tools/
    registry.py             # ToolRegistry — 17 tools executing against Database
  traces/
    export.py               # Trace creation, JSONL export, PII redaction
  market/sources/           # Data source adapters for market snapshots and external feeds
  ui/                       # (reserved)
  configs/                  # (reserved)

app.py                      # FastAPI entry shim (launches the backend host)
tests/                      # pytest test suite (run `pytest tests/ --collect-only -q` for current count)
benchmarks/                 # pytest benchmark suite (9 latency markers)

Architecture

FastAPI host (shopstack/server.py)
  → ToolRegistry (17 tools, validates args, calls Database)
    → Database (SQLite WAL, 26 tables, 2 views, 2 triggers, 10 indexes)
  → ProviderRegistry (wired from Settings)
    → MockProviders (default — 11 interfaces, all offline)
    → Market services (market source registry load + snapshot status helpers in `shopstack.services.market_sources`)
  → Settings (pydantic-settings, env-overridable)
  → ModelRegistry (58 entries, not loaded by default)

11 Provider Interfaces

InterfaceMock Behavior
STTProviderReturns predefined Hindi/Hinglish phrases
TTSProviderWrites a note about what would be spoken
VisionProviderRandomly samples from 26 common kitchen items
ObjectDetectionProviderReturns plausible bounding boxes + confidences
GroundingProviderReturns grounded item references
SegmentationProviderReturns placeholder masks
OCRProviderReturns mock extracted text
PlannerProviderReturns structured multi-step plans
ToolCallParserProviderParses intent → tool call candidates
EmbeddingsProviderReturns random 384-d vectors
ImageEditProviderReturns a dummy edited image path

17 Tools

ToolPurpose
add_inventory_itemAdd a new item to household inventory
update_inventory_itemUpdate details of an existing inventory item
consume_inventory_itemRecord consumption (partial or full)
move_inventory_itemMove an item to a different storage location
find_itemSearch for an item across inventory and locations
semantic_find_itemSearch for an item using exact, prefix, and semantic embedding search with match quality scores
create_or_update_shopping_listCreate/update the active shopping list
compare_visible_item_to_inventoryCompare detected item against current stock
record_price_observationRecord a price observation for an item
get_use_soon_itemsGet items expiring or aging soon
get_next_buy_suggestionsGet suggestions for what to buy next
export_anonymized_traceExport an anonymized agent trace
undo_last_inventory_changeUndo the most recent change (add, consume, or move) to an inventory item
calculate_nutritionLook up nutrition (calories, protein, carbs, fat) for a food item by name
check_price_dropReport items whose current market price is 15%+ below their historical median
find_substituteSuggest category or ingredient substitutes for a sold-out or unavailable item
get_weather_recommendationRecommend whether to shop in-store, order delivery, or delay based on weather

26 Database Tables

Core tables (the full set of 26 is enumerated in Current Verified by Code Inspection above): inventory_lots, purchase_events, shopping_lists, shopping_list_items, household_locations, movement_events, price_observations, stores, traces, app_config

Compatibility aliases: price_history and agent_traces are exposed as read/delete-compatible views for older docs, tests, and scripts.

18 hierarchical household locations seeded on every init (safe via COUNT check): Home → Kitchen → Fridge → Fridge Door → ..., Pantry → Shelf → ..., etc.

Trace System

Every tool execution creates an agent trace stored in the database. Traces include perception snapshots, inventory context, decision rationale, proposed tool calls, and human confirmation status. On export, traces are redacted for PII:

  • Phone numbers (10+ digits)
  • Email addresses
  • Aadhar numbers (12-digit pattern)
  • PAN numbers (5 letters + 4 digits + 1 letter)
  • Geo addresses (street patterns)

Explicitly not redacted: generic name fields, canonical item names, location names.

Screens

TabPurpose
Plan Today's ShoppingDashboard workflow — today view, use-soon signals, and shopping recommendations
Shopping ListView / create / manage the active shopping list
Market Lens: Should I Buy This?Camera / voice input → detect → compare vs inventory
Add PurchaseManual purchase recording form with store, price, item details
Find an Item at HomeSearch + map lookup for likely storage location
Use Soon / Waste SaverExpiring and aging items with priority list
Price Memory CheckHistorical price observations per item
Find Item LocationStorage hierarchy and item count view
Model StackActive model stack + budget status and candidate catalog
Agent TraceAgent session trace viewer with redaction preview
Field NotesAgent reasoning and decision log

FastAPI /api/v1 REST API

ShopStack exposes a versioned HTTP API under /api/v1/* for the mobile app and other HTTP clients. The API is mounted directly on the FastAPI host at startup, alongside the HTML shell served at /.

Architecture

HTTP Client (shopstack-mobile, curl, etc.)
  │
  ├── GET  /api/v1/meta/...           ← public (no auth)
  ├── POST /api/v1/auth/...           ← public (bootstraps sessions)
  ├── POST /api/v1/sms/...            ← public (Twilio webhooks)
  │
  └── ALL /api/v1/{inventory,shopping,dashboard,
                  search,intelligence,account,traces,
                  corrections,command,household}/*  ← Bearer token required

Auth model

ConceptImplementation
Device identitydevice_id + device_secret generated client-side, registered via POST /auth/register
TokenOpaque bearer token (40-char hex), returned on register/login, refreshed via POST /auth/refresh
TransportAuthorization: Bearer <token> header
Storageexpo-secure-store (iOS/Android) or localStorage (web fallback)
Household scopingAuthenticated operations are scoped to the user's household

Endpoints

RouterEndpointsDescription
/metawhoami, health, runtimeServer identity, health check, model runtime status
/authregister, login, refresh, logoutDevice registration, authentication, session management
/inventorylist lots, get lot, add lot, consume lotHousehold inventory CRUD
/householdlist, create, switchMulti-household support
/shoppingget active, create list, add items, complete, mark-purchasedShopping list management
/dashboardtodayToday's snapshot: pantry count, use-soon, low items, recent purchases
/commandpreview, execute, recentNatural language command processing
/searchglobal, inventory, voice-intentText + semantic search across inventory
/traceslist, get, exportWorkflow audit trail with PII-redacted export
/intelligencedecision explain, recurring plan, meal planAI-powered insights
/accountprivacy (purge, retention), undo, store-mode toggleAccount management
/correctionslist, createCorrection event management
/smswebhookTwilio SMS webhook handler (Twilio-signed)

OpenAPI schema

The full OpenAPI 3.0 schema is auto-generated from route declarations:

python -c "from shopstack.api.v1.openapi import openapi_schema_json; print(openapi_schema_json())"

The schema is the canonical API contract between the backend and the mobile client. Contract tests in tests/test_api_v1_openapi_schema.py assert schema structure. TypeScript types in shopstack-mobile/src/api/types.ts are hand-mapped from the Python Pydantic schemas.

shopstack-mobile (React Native / Expo)

shopstack-mobile/ is a React Native (Expo) app that consumes the /api/v1 REST API — giving ShopStack a native mobile interface alongside the FastAPI frontend shell. It is the primary household-facing entry point: used in kitchens and stores, offline-first, and designed around decisions (buy/skip/use-soon/compare) rather than data tables.

Architecture

shopstack-mobile/
├── app/                          # expo-router file-based navigation
│   ├── _layout.tsx               # Root: persisted React Query + auth gate
│   ├── (auth)/                   # Login, Register
│   ├── (tabs)/                   # Home, Pantry, Shop, Cook, Trips, More
│   │   ├── index.tsx             # Decision-first dashboard
│   │   ├── inventory.tsx         # Pantry quick-add + staple chips
│   │   ├── shopping.tsx          # Active list + completion
│   │   ├── recipes.tsx           # Cook tonight + missing-to-list
│   │   ├── trips.tsx             # Trip signals + low/use-soon items
│   │   ├── more.tsx              # Settings + account
│   │   └── search.tsx            # Search page reached via floating action
│   ├── login.tsx                 # Token-aligned auth
│   └── register.tsx              # Token-aligned auth
└── src/
    ├── theme/tokens.ts           # Warm Pantry design tokens
    ├── components/               # Primitives + composites
    │   ├── primitives/
    │   └── composite/
    ├── hooks/                    # TanStack Query data layer
    ├── api/
    │   ├── types.ts              # TypeScript interfaces (70+ types)
    │   ├── client.ts             # HTTP client with Bearer token injection
    │   ├── auth.ts               # Device registration & auth
    │   └── *.ts                  # Endpoint modules
    └── storage/
        └── token.ts              # expo-secure-store wrapper

Primary navigation (6 tabs)

TabPurpose
HomeDecision banner: today's dominant action + 3 story tiles
PantryQuick-add, offline status, staple chips, pantry rows
ShopActive shopping list, check-off, complete
CookMeal-plan / recipe cards; add missing ingredients to list
TripsTrip recommendations, ranked low/use-soon items
MoreSettings, account, privacy, traces

Key decisions

DecisionChoice
FrameworkExpo managed workflow (no bare RN needed for HTTP CRUD)
Navexpo-router (file-based, deep links built-in)
CachingTanStack React Query + secure offline persistence
Auth tokensexpo-secure-store (hardware-backed on iOS/Android)
Design systemWarm Pantry Intelligence: cream paper, olive, terracotta, amber; system fonts; light-first
Quick-add intelligence/api/v1/command/execute when online, local fallback offline
SearchFloating action button across all tabs, not a top-level tab

Setup

cd shopstack-mobile
npm install
npm run typecheck     # Verify TypeScript before running
npx expo start        # Scan QR with Expo Go, or press 'w' for web

See shopstack-mobile/README.md for full details.

Frontend Shell (FastAPI HTML UI)

shopstack/ui/frontend_shell.py renders a standalone HTML/CSS frontend served by FastAPI. It now shares the same Warm Pantry token system as shopstack-mobile (light-first with dark mode support, system fonts, olive/amber/terracotta palette) and provides:

  • Full auth flow (login, register, device management)
  • Dashboard view (today's snapshot)
  • Inventory browser with add/consume actions
  • Shopping list creation and management
  • Global + inventory search
  • Intelligence panels (recurring plan, meal plan, decision explain)
  • Privacy controls (retention, purge, undo)
  • Trace history viewer
  • Store mode (check-off items while shopping)
  • Mobile-responsive light-first theme with system fonts only

The frontend shell is loaded through FastAPI routes and communicates entirely through the /api/v1/* REST endpoints.

Configuration

All settings are pydantic-settings with SHOPSTACK_ env prefix:

Operational resource guards are documented in Docs/RESOURCE_OPTIMIZATION_POLICY.md.

VariableDefaultDescription
SHOPSTACK_DB_PATHdata/shopstack.dbSQLite database file path
SHOPSTACK_APP_PORT7860FastAPI server port
SHOPSTACK_OFF_THE_GRIDtrueUse mock providers (no cloud)
SHOPSTACK_LOCAL_AUTO_UNLOADtrueUnload local model runtime after each local provider call
SHOPSTACK_LOCAL_WHISPER_AUTO_UNLOADtrueUnload local STT model after each transcription
SHOPSTACK_TRACE_MAX_ROWS2000Maximum number of trace rows to retain
SHOPSTACK_TRACE_TTL_DAYS30Delete traces older than this many days
SHOPSTACK_STT_BACKENDmockSTT provider selection
SHOPSTACK_TTS_BACKENDmockTTS provider selection
SHOPSTACK_VISION_BACKENDmockVision provider selection
SHOPSTACK_OBJECT_DETECTION_BACKENDmockObject detection provider
... per-provider backends default to mock

Model Catalog

See MODEL_CATALOG.md for the full living model catalog — including downloaded & tested models, parameter budget tracking, runtime backends (MLX, llama.cpp/GGUF, transformers), HF Pro and Modal Labs credit resources, and experiment logs.

The programmatic registry lives in shopstack/model_registry.py (16+ entries across STT, TTS, Vision, OCR, Embeddings, and Planner categories).

  • Active / loaded models: actually selected at runtime.
  • Candidate models: documented options available for future activation.
  • Budget check: only active/loaded models are counted against the 32B cap (enforced by validate_active_model_budget()).

Active design constraint: Total parameter count across all simultaneously active models must not exceed 32 billion. Mock mode shows an active-loaded stack of 0B.

Key Design Decisions

  • Single shared schemas file — models are interconnected and share enums; a single file avoids circular imports.
  • Provider ABCs named *ProviderSTTProvider, not STT; mock classes named Mock*Provider.
  • PurchaseEvent enriched with per-item fieldscanonical_name, quantity, unit, total_price live on the event, not on a separate join table.
  • PriceObservation defaultsobservation_date defaults to date.today().
  • PII redaction is targeted — only phone, email, Aadhar, PAN, and address patterns are redacted. Generic name keys are preserved.
  • No auto-purchase or payment scraping — design-level constraint. ShopStack tells you what to buy, it doesn't buy for you.

Development

uv pip install -e ".[dev]"
uv run pytest tests/ -v
uv run pytest benchmarks/ -v -m benchmark
uv run python app.py

Deployment

ShopStack can run via Docker or on any of the supported platforms.

Docker (local)

docker compose up --build
# Open http://localhost:7860

Data persists in a Docker volume (shopstack_data).

Docker (standalone)

docker build -t shopstack .
docker run -p 7860:7860 -v shopstack_data:/app/data shopstack

Railway

  1. Push your repo to GitHub.
  2. Create a new project on RailwayDeploy from GitHub repo.
  3. Railway auto-detects Dockerfile and railway.json.
  4. Add a Volume with mount path /app/data (1 GB) for SQLite persistence.
  5. (Optional) Set SHOPSTACK_HF_API_KEY and SHOPSTACK_PLANNER_BACKEND=huggingface for cloud-backed planning.

Render

  1. Push your repo to GitHub.
  2. Create a new Web Service on RenderDeploy from Dockerfile.
  3. Select the Starter plan ($7/mo) — required for persistent disk.
  4. Add a Disk mount at /app/data with 1 GB.
  5. render.yaml is auto-detected if you connect via Blueprint.

Fly.io

# Install flyctl first: https://fly.io/docs/hands-on/install-flyctl/
flyctl launch --dockerfile ./Dockerfile
flyctl volumes create shopstack_data --region <your-region> --size 1
flyctl deploy

See fly.toml for configuration reference.

License

MIT

Contributors

pranaysuyash

118 commits

pranaysuyash/shopstack

Local-first, off-the-grid household inventory management with Gradio UI, SQLite persistence, and swappable provider interfaces.

0

stars

118

commits

Python

primary language

Aug 26, 2026

updated

README


title: ShopStack emoji: 🛒 colorFrom: green colorTo: blue sdk: docker pinned: false tags: [shopstack, inventory, shopping, offline-first, household, fastapi]

ShopStack

Doc links: Several links in this README point to Docs/ paths that are intentionally local-only (see Docs/README.md). They work in a local workspace but 404 from a clean clone. For canonical architecture, see shopstack/module_registry.py and the code under shopstack/. Git-tracked docs (MODEL_CATALOG.md, this README) are reachable from any clone.

Local-first, off-the-grid shopping intelligence platform. Know what you have, what to use soon, what to buy, what to skip, and where to buy from — without sending your data to the cloud.

ShopStack is a stack of shopping intelligence layers: home inventory (ShopStock), shopping lists and market baskets (ShopBasket), retailer price comparison (ShopCompare), scanning and import (ShopLens), price history and preferences (ShopMemory), and a reasoning agent (ShopAgent) that decides buy/skip/use-soon across all modules.

Philosophy

ShopStack runs entirely locally — SQLite database (WAL mode), mockable provider interfaces, and an API-first FastAPI frontend shell that works offline. The "Off the Grid" path means zero cloud dependencies for core functionality. The default mock providers let you build and test the full app without loading any ML models.

Total parameter limit: ≤32 billion parameters across all loaded models.

Modules

ModulePurpose
ShopStockInventory, pantry, fridge, expiry, low-stock, use-soon
ShopBasketShopping list, cart builder, market basket optimization
ShopCompareRetailer price comparison (Swiggy, Blinkit, Zepto, ...)
ShopLensScanning: barcode, photo, receipt, barcode
ShopMemoryPrice history, household preferences, field notes
ShopAgentReasoning: buy/skip/use-soon/compare decisions
SourcesRetailer datasets (Swiggy Instamart + future)

See Docs/ARCHITECTURE.md for the full system architecture and Docs/SERVICES_ARCHITECTURE.md for the service layer.

Frontend Shell

ShopStack is organized around workflow experiences in the FastAPI shell:

  • Today — Decision-first dashboard: what to buy, skip, use soon, and compare
  • Ask ShopStack — Natural language queries across all modules
  • Shopping List — Create, classify (buy/skip/use-soon), and complete shopping plans
  • Market Lens — Scan items via camera or voice, compare to inventory
  • Add Purchase — Record what was bought (price, store, location)
  • Find Item at Home — Search inventory by location and status
  • Use Soon — Expiring and aging items flagged for attention
  • Price Memory Check — Price history, trends, and best-store intelligence
  • Traces — Workflow audit trail with redacted export
  • Field Notes — Household notes and preferences

Quick Start

uv venv --python 3.13
uv pip install -e ".[dev]"
uv run python app.py

Open http://localhost:7860 in your browser.

Market Snapshot Import

ShopStack can ingest the real Swiggy Instamart fresh vegetables snapshot found in data/swiggy_fresh_vegetables_cards_6jun26.json (or the matching CSV) into the local price observation database.

uv run python scripts/import_swiggy_snapshot.py

Imported observations are tagged with source_event_id = swiggy_fresh_vegetables_20260606 so they can be filtered or audited later.

Tests

uv run pytest tests/ -v
uv run pytest benchmarks/ -v -m benchmark

Run uv run pytest tests/ --collect-only -q for the current test count.

Current Verified by Code Inspection

As of the current code inspection, the following metrics are verified:

  • 26 Database Tables, 2 Views, 2 Triggers, 10 Indexes: app_config, condition_events, correction_events, find_feedback, household_locations, household_members, household_objects, households, inventory_events, inventory_lots, market_record_components, market_records, market_snapshots, movement_events, negative_memory, object_notes, object_sightings, person_associations, preference_signals, price_observations, purchase_events, reconciliation_events, shopping_list_items, shopping_lists, stores, traces (Tables), price_history, agent_traces (Views).
  • 17 Tools: Including semantic_find_item.

Note: For the canonical current-state metrics, run python3 scripts/repo_truth.py. The README is updated when new tables/tabs/tools are added; do not hand-maintain these numbers.

Engineering Mandate: Do not narrow scope to hackathon/MVP. ShopStack is designed as a long-term, bold, and comprehensive intelligence platform. Follow motto_v5.md principles exactly.

Project Structure

shopstack/
  __init__.py
  _version.py               # v0.1.0
  config.py                 # Settings (pydantic-settings, env prefix SHOPSTACK_)
  model_registry.py         # 58 model entries (10 active / 46 candidate / 2 rejected; all ≤32B total active)
  schemas/
    models.py               # All Pydantic domain models (14+ classes, 16 enums)
  providers/
    interfaces.py           # 11 abstract provider ABCs
    mock_providers.py       # Full mock implementations for all 11 (Indian/Hinglish data)
    registry.py             # ProviderRegistry factory wired to Settings
  persistence/
    database.py             # SQLite Database (WAL, 26 tables, 2 views, 2 triggers, 10 indexes, full CRUD)
  services/                 # Business logic services (decision engine, shopping, dashboard, preferences, freshness)
  tools/
    registry.py             # ToolRegistry — 17 tools executing against Database
  traces/
    export.py               # Trace creation, JSONL export, PII redaction
  market/sources/           # Data source adapters for market snapshots and external feeds
  ui/                       # (reserved)
  configs/                  # (reserved)

app.py                      # FastAPI entry shim (launches the backend host)
tests/                      # pytest test suite (run `pytest tests/ --collect-only -q` for current count)
benchmarks/                 # pytest benchmark suite (9 latency markers)

Architecture

FastAPI host (shopstack/server.py)
  → ToolRegistry (17 tools, validates args, calls Database)
    → Database (SQLite WAL, 26 tables, 2 views, 2 triggers, 10 indexes)
  → ProviderRegistry (wired from Settings)
    → MockProviders (default — 11 interfaces, all offline)
    → Market services (market source registry load + snapshot status helpers in `shopstack.services.market_sources`)
  → Settings (pydantic-settings, env-overridable)
  → ModelRegistry (58 entries, not loaded by default)

11 Provider Interfaces

InterfaceMock Behavior
STTProviderReturns predefined Hindi/Hinglish phrases
TTSProviderWrites a note about what would be spoken
VisionProviderRandomly samples from 26 common kitchen items
ObjectDetectionProviderReturns plausible bounding boxes + confidences
GroundingProviderReturns grounded item references
SegmentationProviderReturns placeholder masks
OCRProviderReturns mock extracted text
PlannerProviderReturns structured multi-step plans
ToolCallParserProviderParses intent → tool call candidates
EmbeddingsProviderReturns random 384-d vectors
ImageEditProviderReturns a dummy edited image path

17 Tools

ToolPurpose
add_inventory_itemAdd a new item to household inventory
update_inventory_itemUpdate details of an existing inventory item
consume_inventory_itemRecord consumption (partial or full)
move_inventory_itemMove an item to a different storage location
find_itemSearch for an item across inventory and locations
semantic_find_itemSearch for an item using exact, prefix, and semantic embedding search with match quality scores
create_or_update_shopping_listCreate/update the active shopping list
compare_visible_item_to_inventoryCompare detected item against current stock
record_price_observationRecord a price observation for an item
get_use_soon_itemsGet items expiring or aging soon
get_next_buy_suggestionsGet suggestions for what to buy next
export_anonymized_traceExport an anonymized agent trace
undo_last_inventory_changeUndo the most recent change (add, consume, or move) to an inventory item
calculate_nutritionLook up nutrition (calories, protein, carbs, fat) for a food item by name
check_price_dropReport items whose current market price is 15%+ below their historical median
find_substituteSuggest category or ingredient substitutes for a sold-out or unavailable item
get_weather_recommendationRecommend whether to shop in-store, order delivery, or delay based on weather

26 Database Tables

Core tables (the full set of 26 is enumerated in Current Verified by Code Inspection above): inventory_lots, purchase_events, shopping_lists, shopping_list_items, household_locations, movement_events, price_observations, stores, traces, app_config

Compatibility aliases: price_history and agent_traces are exposed as read/delete-compatible views for older docs, tests, and scripts.

18 hierarchical household locations seeded on every init (safe via COUNT check): Home → Kitchen → Fridge → Fridge Door → ..., Pantry → Shelf → ..., etc.

Trace System

Every tool execution creates an agent trace stored in the database. Traces include perception snapshots, inventory context, decision rationale, proposed tool calls, and human confirmation status. On export, traces are redacted for PII:

  • Phone numbers (10+ digits)
  • Email addresses
  • Aadhar numbers (12-digit pattern)
  • PAN numbers (5 letters + 4 digits + 1 letter)
  • Geo addresses (street patterns)

Explicitly not redacted: generic name fields, canonical item names, location names.

Screens

TabPurpose
Plan Today's ShoppingDashboard workflow — today view, use-soon signals, and shopping recommendations
Shopping ListView / create / manage the active shopping list
Market Lens: Should I Buy This?Camera / voice input → detect → compare vs inventory
Add PurchaseManual purchase recording form with store, price, item details
Find an Item at HomeSearch + map lookup for likely storage location
Use Soon / Waste SaverExpiring and aging items with priority list
Price Memory CheckHistorical price observations per item
Find Item LocationStorage hierarchy and item count view
Model StackActive model stack + budget status and candidate catalog
Agent TraceAgent session trace viewer with redaction preview
Field NotesAgent reasoning and decision log

FastAPI /api/v1 REST API

ShopStack exposes a versioned HTTP API under /api/v1/* for the mobile app and other HTTP clients. The API is mounted directly on the FastAPI host at startup, alongside the HTML shell served at /.

Architecture

HTTP Client (shopstack-mobile, curl, etc.)
  │
  ├── GET  /api/v1/meta/...           ← public (no auth)
  ├── POST /api/v1/auth/...           ← public (bootstraps sessions)
  ├── POST /api/v1/sms/...            ← public (Twilio webhooks)
  │
  └── ALL /api/v1/{inventory,shopping,dashboard,
                  search,intelligence,account,traces,
                  corrections,command,household}/*  ← Bearer token required

Auth model

ConceptImplementation
Device identitydevice_id + device_secret generated client-side, registered via POST /auth/register
TokenOpaque bearer token (40-char hex), returned on register/login, refreshed via POST /auth/refresh
TransportAuthorization: Bearer <token> header
Storageexpo-secure-store (iOS/Android) or localStorage (web fallback)
Household scopingAuthenticated operations are scoped to the user's household

Endpoints

RouterEndpointsDescription
/metawhoami, health, runtimeServer identity, health check, model runtime status
/authregister, login, refresh, logoutDevice registration, authentication, session management
/inventorylist lots, get lot, add lot, consume lotHousehold inventory CRUD
/householdlist, create, switchMulti-household support
/shoppingget active, create list, add items, complete, mark-purchasedShopping list management
/dashboardtodayToday's snapshot: pantry count, use-soon, low items, recent purchases
/commandpreview, execute, recentNatural language command processing
/searchglobal, inventory, voice-intentText + semantic search across inventory
/traceslist, get, exportWorkflow audit trail with PII-redacted export
/intelligencedecision explain, recurring plan, meal planAI-powered insights
/accountprivacy (purge, retention), undo, store-mode toggleAccount management
/correctionslist, createCorrection event management
/smswebhookTwilio SMS webhook handler (Twilio-signed)

OpenAPI schema

The full OpenAPI 3.0 schema is auto-generated from route declarations:

python -c "from shopstack.api.v1.openapi import openapi_schema_json; print(openapi_schema_json())"

The schema is the canonical API contract between the backend and the mobile client. Contract tests in tests/test_api_v1_openapi_schema.py assert schema structure. TypeScript types in shopstack-mobile/src/api/types.ts are hand-mapped from the Python Pydantic schemas.

shopstack-mobile (React Native / Expo)

shopstack-mobile/ is a React Native (Expo) app that consumes the /api/v1 REST API — giving ShopStack a native mobile interface alongside the FastAPI frontend shell. It is the primary household-facing entry point: used in kitchens and stores, offline-first, and designed around decisions (buy/skip/use-soon/compare) rather than data tables.

Architecture

shopstack-mobile/
├── app/                          # expo-router file-based navigation
│   ├── _layout.tsx               # Root: persisted React Query + auth gate
│   ├── (auth)/                   # Login, Register
│   ├── (tabs)/                   # Home, Pantry, Shop, Cook, Trips, More
│   │   ├── index.tsx             # Decision-first dashboard
│   │   ├── inventory.tsx         # Pantry quick-add + staple chips
│   │   ├── shopping.tsx          # Active list + completion
│   │   ├── recipes.tsx           # Cook tonight + missing-to-list
│   │   ├── trips.tsx             # Trip signals + low/use-soon items
│   │   ├── more.tsx              # Settings + account
│   │   └── search.tsx            # Search page reached via floating action
│   ├── login.tsx                 # Token-aligned auth
│   └── register.tsx              # Token-aligned auth
└── src/
    ├── theme/tokens.ts           # Warm Pantry design tokens
    ├── components/               # Primitives + composites
    │   ├── primitives/
    │   └── composite/
    ├── hooks/                    # TanStack Query data layer
    ├── api/
    │   ├── types.ts              # TypeScript interfaces (70+ types)
    │   ├── client.ts             # HTTP client with Bearer token injection
    │   ├── auth.ts               # Device registration & auth
    │   └── *.ts                  # Endpoint modules
    └── storage/
        └── token.ts              # expo-secure-store wrapper

Primary navigation (6 tabs)

TabPurpose
HomeDecision banner: today's dominant action + 3 story tiles
PantryQuick-add, offline status, staple chips, pantry rows
ShopActive shopping list, check-off, complete
CookMeal-plan / recipe cards; add missing ingredients to list
TripsTrip recommendations, ranked low/use-soon items
MoreSettings, account, privacy, traces

Key decisions

DecisionChoice
FrameworkExpo managed workflow (no bare RN needed for HTTP CRUD)
Navexpo-router (file-based, deep links built-in)
CachingTanStack React Query + secure offline persistence
Auth tokensexpo-secure-store (hardware-backed on iOS/Android)
Design systemWarm Pantry Intelligence: cream paper, olive, terracotta, amber; system fonts; light-first
Quick-add intelligence/api/v1/command/execute when online, local fallback offline
SearchFloating action button across all tabs, not a top-level tab

Setup

cd shopstack-mobile
npm install
npm run typecheck     # Verify TypeScript before running
npx expo start        # Scan QR with Expo Go, or press 'w' for web

See shopstack-mobile/README.md for full details.

Frontend Shell (FastAPI HTML UI)

shopstack/ui/frontend_shell.py renders a standalone HTML/CSS frontend served by FastAPI. It now shares the same Warm Pantry token system as shopstack-mobile (light-first with dark mode support, system fonts, olive/amber/terracotta palette) and provides:

  • Full auth flow (login, register, device management)
  • Dashboard view (today's snapshot)
  • Inventory browser with add/consume actions
  • Shopping list creation and management
  • Global + inventory search
  • Intelligence panels (recurring plan, meal plan, decision explain)
  • Privacy controls (retention, purge, undo)
  • Trace history viewer
  • Store mode (check-off items while shopping)
  • Mobile-responsive light-first theme with system fonts only

The frontend shell is loaded through FastAPI routes and communicates entirely through the /api/v1/* REST endpoints.

Configuration

All settings are pydantic-settings with SHOPSTACK_ env prefix:

Operational resource guards are documented in Docs/RESOURCE_OPTIMIZATION_POLICY.md.

VariableDefaultDescription
SHOPSTACK_DB_PATHdata/shopstack.dbSQLite database file path
SHOPSTACK_APP_PORT7860FastAPI server port
SHOPSTACK_OFF_THE_GRIDtrueUse mock providers (no cloud)
SHOPSTACK_LOCAL_AUTO_UNLOADtrueUnload local model runtime after each local provider call
SHOPSTACK_LOCAL_WHISPER_AUTO_UNLOADtrueUnload local STT model after each transcription
SHOPSTACK_TRACE_MAX_ROWS2000Maximum number of trace rows to retain
SHOPSTACK_TRACE_TTL_DAYS30Delete traces older than this many days
SHOPSTACK_STT_BACKENDmockSTT provider selection
SHOPSTACK_TTS_BACKENDmockTTS provider selection
SHOPSTACK_VISION_BACKENDmockVision provider selection
SHOPSTACK_OBJECT_DETECTION_BACKENDmockObject detection provider
... per-provider backends default to mock

Model Catalog

See MODEL_CATALOG.md for the full living model catalog — including downloaded & tested models, parameter budget tracking, runtime backends (MLX, llama.cpp/GGUF, transformers), HF Pro and Modal Labs credit resources, and experiment logs.

The programmatic registry lives in shopstack/model_registry.py (16+ entries across STT, TTS, Vision, OCR, Embeddings, and Planner categories).

  • Active / loaded models: actually selected at runtime.
  • Candidate models: documented options available for future activation.
  • Budget check: only active/loaded models are counted against the 32B cap (enforced by validate_active_model_budget()).

Active design constraint: Total parameter count across all simultaneously active models must not exceed 32 billion. Mock mode shows an active-loaded stack of 0B.

Key Design Decisions

  • Single shared schemas file — models are interconnected and share enums; a single file avoids circular imports.
  • Provider ABCs named *ProviderSTTProvider, not STT; mock classes named Mock*Provider.
  • PurchaseEvent enriched with per-item fieldscanonical_name, quantity, unit, total_price live on the event, not on a separate join table.
  • PriceObservation defaultsobservation_date defaults to date.today().
  • PII redaction is targeted — only phone, email, Aadhar, PAN, and address patterns are redacted. Generic name keys are preserved.
  • No auto-purchase or payment scraping — design-level constraint. ShopStack tells you what to buy, it doesn't buy for you.

Development

uv pip install -e ".[dev]"
uv run pytest tests/ -v
uv run pytest benchmarks/ -v -m benchmark
uv run python app.py

Deployment

ShopStack can run via Docker or on any of the supported platforms.

Docker (local)

docker compose up --build
# Open http://localhost:7860

Data persists in a Docker volume (shopstack_data).

Docker (standalone)

docker build -t shopstack .
docker run -p 7860:7860 -v shopstack_data:/app/data shopstack

Railway

  1. Push your repo to GitHub.
  2. Create a new project on RailwayDeploy from GitHub repo.
  3. Railway auto-detects Dockerfile and railway.json.
  4. Add a Volume with mount path /app/data (1 GB) for SQLite persistence.
  5. (Optional) Set SHOPSTACK_HF_API_KEY and SHOPSTACK_PLANNER_BACKEND=huggingface for cloud-backed planning.

Render

  1. Push your repo to GitHub.
  2. Create a new Web Service on RenderDeploy from Dockerfile.
  3. Select the Starter plan ($7/mo) — required for persistent disk.
  4. Add a Disk mount at /app/data with 1 GB.
  5. render.yaml is auto-detected if you connect via Blueprint.

Fly.io

# Install flyctl first: https://fly.io/docs/hands-on/install-flyctl/
flyctl launch --dockerfile ./Dockerfile
flyctl volumes create shopstack_data --region <your-region> --size 1
flyctl deploy

See fly.toml for configuration reference.

License

MIT

Contributors

pranaysuyash

118 commits

Languages

Python

97.2%

TypeScript

2.7%