Lowest observed price per gram for flower, concentrates and vapes at Illinois dispensaries, from full menu imports.
CommerceHTML · PythonGitHub @CstannahillOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Next.js/React/TypeScript frontend (web/) with FastAPI, SQLite and APScheduler ingestion. The default application uses persisted observations with no sample-menu fallback.
Use Python 3.13+ and Node 22.12+ or 24+.
python -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.txt
Set-Location web
npm ci
npm run build
Set-Location ..
.venv/Scripts/python.exe -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
Open API documentation. Use one worker; a process lease prevents concurrent ingestion workers sharing this database. Scheduled jobs run while the process is running. Port 8000 avoids the Razer Synapse service commonly occupying port 8080.
For web development, run npm run dev in web/ (port 3000). Keep the backend service bound to localhost: this local application has no multi-user authentication.
Coverage remains incomplete. The selected Minonk 61760 / 100-mile region contains 190 registry locations, with retained accepted menus for 22 stores at the latest check. Earlier ZIP 61358 / 50-mile and GPS / 100-mile measurements describe different regions and must not be mixed with this denominator. Endpoint counts can include alternative sources and license channels. See the pipeline audit and catalog/source recovery evidence. This does not establish the best deal across every regional dispensary. Illinois is the only implemented registry; jurisdiction boundary intersections have not been calculated.
See measured acceptance and per-store gaps, original audit, and implementation ledger.
terpscout.db stores the catalog, observations, snapshots, diffs, jobs and settings in additive live_* tables. The pre-migration DB is retained as terpscout.db.before-live.sqlite3. Original index.html remains intact and is available only as a labeled legacy simulated reference. The former backend entrypoint is archived under docs/reference/.
data/evidence/ retains compressed source responses and manifests with URL, status, time, digest and evidence ID. Snapshots retain traversal manifests and source records. Back up the database and evidence together. There is no automatic evidence pruning yet.
Schedules: 2/day (08:00, 20:00), 3/day (07:00, 15:00, 23:00), or 4/day (00:00, 06:00, 12:00, 18:00), America/Chicago, plus daily registry refresh. Settings persist. Interrupted runs are recorded; a new run retries them. Public network destinations and redirects are validated, DNS destinations pinned, requests bounded, and failures retained. Provider restrictions require an authorized feed, retailer cooperation, or an appropriate human browser step.
.venv/Scripts/python.exe -m unittest discover -s tests
Set-Location web
npm run typecheck
npm test
npm run build
Set-Location ..
.venv/Scripts/python.exe scripts/live_acceptance.py --zip 61358 --radius 50 --output data/live-acceptance-final.json
The last command performs real public requests through the running API and persists measured results. Fixture tests do not establish current access to every provider.
The current pipeline searches websites when there is no brand connector, inspects branch identity and embedded menu platforms, and uses a generic structured HTML/visible-card/JavaScript fallback when needed. Generic extraction captures partial observations even without complete pagination proof; inspect these separately in the menu dialog. A featured carousel's total cannot authorize a full snapshot or removals. Explicitly identified all-products lists require reconciled totals and stable independent traversals.
The additional Dispense adapter was validated against the observed public storefront SDK, venue identity, its in-stock quantityMin=1 filter and skip/limit/count pagination. It discovered its public SDK configuration from linked retailer scripts and completed 1,474 products across two traversals. Mystic Greenz Lincoln was found through general search without a retailer connector and imported 583 variants through Sweed. These targeted app jobs added 2,057 variants. They do not establish exhaustive regional coverage.
In Menu Sync, Website discovery & browser fallback controls JavaScript rendering and ordinary age/terms actions. Age confirmation and terms acceptance start unchecked and are persisted only when the user selects them. Node.js, installed Chrome and the Playwright package installed by npm ci are required; TERPSCOUT_BROWSER_CHANNEL can select another installed Chromium channel. Browser requests pass through the public fetch boundary, with bounded rendering, domain-scoped cookies, durable sessions under data/browser-sessions/, and capture manifests. Keep those local session files private when sharing diagnostic artifacts.
Store cards show actual diagnostic messages and provide a targeted retry. The run API also accepts store_ids so troubleshooting one location does not rescan an entire region. GET /api/v1/menus/{id}/observations exposes the latest partial extraction separately from accepted products. GET/PATCH /api/v1/settings/browser controls browser behavior.
data/expanded-app-acceptance.json records the targeted application run; data/dispense-live-acceptance.json records the independent Dispense probe. scripts/scan_website_candidates.py --region-id <saved-region-id> --inspect audits all previously unconfigured brands and saves website leads/platform evidence. Its results are candidate discovery, not inventory imports. See docs/DISCOVERY_FALLBACK_RESULTS.md for measured results and remaining limits.