Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c558e45
chore: scaffold repo structure and environment
ScooterStuff Jun 10, 2026
807cf52
feat(scraper): polite cached scraper + parsed datasets
ScooterStuff Jun 10, 2026
537877c
feat(data): postgres+pgvector hybrid data layer
ScooterStuff Jun 10, 2026
257eafa
feat(agent): tool-calling agent with scope guard and SSE
ScooterStuff Jun 10, 2026
50d788e
feat(eval): 40-case harness with published results
ScooterStuff Jun 10, 2026
7edcdd5
feat(ui): branded chat with rich blocks and fix-it journey
ScooterStuff Jun 10, 2026
7f35ddc
test: testing pyramid + CI pipeline
ScooterStuff Jun 10, 2026
e6391ca
feat(ops): docker, makefile, structured config/logging
ScooterStuff Jun 10, 2026
4bdf354
docs: README with eval table, architecture, tradeoffs, limitations
ScooterStuff Jun 10, 2026
9da3359
chore: regenerate eval results on final code
ScooterStuff Jun 10, 2026
9671b43
fix(scraper): full browser-like header set to bypass 403
ScooterStuff Jun 11, 2026
4940bfa
perf(embeddings): LRU cache on embed_one for repeat queries
ScooterStuff Jun 11, 2026
642fafd
fix(prompts): mandatory tool-use directive; fix .env.example inline c…
ScooterStuff Jun 11, 2026
80ec1bc
data: scale catalog to 120 parts / 3.7k compat / 95 causes (real embe…
ScooterStuff Jun 11, 2026
8228a38
eval: regenerate RESULTS.md against real model and scaled data — 40/4…
ScooterStuff Jun 11, 2026
a0c1139
docs: slide deck for the Loom walkthrough
ScooterStuff Jun 11, 2026
67fb866
docs: loom script + workflow and architecture diagrams
ScooterStuff Jun 11, 2026
745cd21
docs: reframe slides 2-3 around user jobs and trust (product framing)…
ScooterStuff Jun 11, 2026
42ca240
feat(ui): photo-to-model-number via client-side OCR; drop mock order …
ScooterStuff Jun 12, 2026
b684bd5
docs: technical deep-dive deck + script (post photo-OCR feature)
ScooterStuff Jun 12, 2026
98e5866
merge: bring in scaled catalog + real-eval results from origin/main
ScooterStuff Jun 12, 2026
6575f8d
chore: drop cart, order_support tool, and e2e suite
ScooterStuff Jun 12, 2026
02abc9d
feat: pluggable appliances via TOML + "How I know this" honesty trace
ScooterStuff Jun 12, 2026
21ed5c9
fix(retrieval): OR-mode tsquery fallback so natural-language queries …
ScooterStuff Jun 12, 2026
c6046ec
refactor(appliances): drive MockLLM from appliances.toml + add docs/T…
ScooterStuff Jun 12, 2026
ac7358b
Initial plan
Copilot Jun 12, 2026
7219436
Fix backend lint failure in llm_client imports
Copilot Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.py]
indent_style = space
indent_size = 4

[*.{js,jsx,json,yml,yaml,css,html}]
indent_style = space
indent_size = 2

[Makefile]
indent_style = tab
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
LLM_BASE_URL=https://api.openai.com/v1
LLM_API_KEY=sk-...
LLM_MODEL=gpt-4o
# pragma: allowlist secret
DATABASE_URL=postgresql://ps:ps@localhost:5432/partselect
EMBEDDING_MODEL=text-embedding-3-small
# Leave EMBEDDING_API_KEY empty to default to LLM_API_KEY.
EMBEDDING_API_KEY=
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Keep shell scripts LF so they execute correctly inside Linux containers
# even when cloned on Windows with core.autocrlf=true.
*.sh text eol=lf
backend/entrypoint.sh text eol=lf
82 changes: 82 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: CI

on:
push:
pull_request:
workflow_dispatch: # also enables the manual eval job below

jobs:
backend:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
{ POSTGRES_USER: ps, POSTGRES_PASSWORD: ps, POSTGRES_DB: partselect }
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U ps -d partselect"
--health-interval 5s --health-timeout 5s --health-retries 10
env:
DATABASE_URL: postgresql://ps:ps@localhost:5432/partselect
MOCK_LLM: "1"
MOCK_EMBEDDINGS: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11", cache: pip }
- run: pip install -r backend/requirements.txt -r backend/requirements-dev.txt ruff
- run: ruff check backend scraper eval tests && ruff format --check backend scraper eval tests
- run: pytest --cov --cov-fail-under=80 --cov-report=term --cov-report=xml
- uses: actions/upload-artifact@v4
with: { name: coverage, path: coverage.xml }

frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
{
node-version: 20,
cache: npm,
cache-dependency-path: frontend/package-lock.json,
}
- run: npm ci --no-audit --no-fund
working-directory: frontend
- run: npx react-scripts test --watchAll=false
working-directory: frontend
env: { CI: "true" }
- run: npm run build
working-directory: frontend
env: { CI: "true" }

# Manual only: needs a real LLM key and costs money - run before submitting,
# never on every push.
eval:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
{ POSTGRES_USER: ps, POSTGRES_PASSWORD: ps, POSTGRES_DB: partselect }
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U ps -d partselect"
--health-interval 5s --health-timeout 5s --health-retries 10
env:
DATABASE_URL: postgresql://ps:ps@localhost:5432/partselect
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11", cache: pip }
- run: pip install -r backend/requirements.txt
- run: python backend/ingest.py --load-seed
- run: nohup python -m uvicorn backend.app.main:app --port 8000 &
- run: sleep 3 && python eval/run_eval.py
- uses: actions/upload-artifact@v4
with: { name: eval-results, path: eval/RESULTS.md }
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
node_modules/
.env
__pycache__/
*.pyc
.venv/
venv/
scraper/data/raw_html/
.next/
build/
.pytest_cache/
.coverage
htmlcov/
playwright-report/
test-results/
scraper/data/
20 changes: 20 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
exclude: (package-lock\.json|backend/data/|scraper/fixtures/|scraper/data/|playbook/|docker-compose.*\.yml)
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: scraper/fixtures/
- id: end-of-file-fixer
exclude: scraper/fixtures/
- id: check-merge-conflict
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Contributing

```bash
cp .env.example .env # or skip and use MOCK_LLM=1
make setup # venv + deps + pre-commit hooks
make test # pytest + jest
make lint # ruff check + format
```

- Conventional commits: `feat(scope): …`, `fix(scope): …`, `test: …`, `chore: …`.
- `pre-commit install` runs ruff/format/detect-secrets on every commit.
- Agent *quality* changes need an eval case in `eval/cases.json`; run
`make eval` and commit the regenerated `eval/RESULTS.md`.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 ScooterStuff

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.PHONY: setup ingest dev test eval lint up down fresh smoke

PY := .venv/bin/python
PIP := .venv/bin/pip

setup: ## venv + backend deps + frontend deps + git hooks
python3 -m venv .venv
$(PIP) install -r backend/requirements.txt -r backend/requirements-dev.txt ruff pre-commit
cd frontend && npm install --no-audit --no-fund
.venv/bin/pre-commit install

ingest: ## load the committed seed into Postgres (no API keys needed)
$(PY) backend/ingest.py --load-seed

rebuild-data: ## re-ingest from JSON + re-embed via API (needs embedding key)
$(PY) backend/ingest.py --rebuild && $(PY) backend/ingest.py --dump-seed

dev: ## backend (:8000) + frontend (:3000) dev servers
($(PY) -m uvicorn backend.app.main:app --reload --port 8000 &) && cd frontend && npm start

test: ## unit + integration tests (backend & frontend)
$(PY) -m pytest -q
cd frontend && CI=true npx react-scripts test --watchAll=false

eval: ## eval harness against a running backend (:8000)
$(PY) eval/run_eval.py

smoke: ## the three canonical spec queries against :8000
bash backend/smoke.sh

lint: ## ruff + format check
.venv/bin/ruff check backend scraper eval tests
.venv/bin/ruff format --check backend scraper eval tests

up: ## docker compose up (set MOCK_LLM=1 for keyless demo)
docker compose up --build -d

down:
docker compose down

fresh: ## clean-clone simulation: build everything and smoke it
docker compose down -v --remove-orphans || true
MOCK_LLM=1 MOCK_EMBEDDINGS=1 docker compose up --build -d
sleep 5 && BASE=http://localhost:8000 bash backend/smoke.sh

help:
@grep -E '^[a-z-]+:.*##' Makefile | sed 's/:.*##/ —/'
Loading