# Doormile AI — retrieval sidecar Semantic intent routing and document Q&A over a local ChromaDB. **This is dev tooling.** The production image is still the static nginx build. The console works with this stack absent — the assistant falls back to its deterministic matcher whenever `REACT_APP_AI_URL` is unset or unreachable. ## Run it ```bash docker compose up -d # chroma :8000, sidecar :8787 docker compose exec ai-sidecar npm run seed curl localhost:8787/health ``` Then point the console at it: ``` REACT_APP_AI_URL=http://localhost:8787 ``` Leave that unset and nothing changes — the bot behaves exactly as it does today. ## What it does | Endpoint | Purpose | |---|---| | `POST /route` | which intent is this question? + confidence | | `POST /ask` | which documentation passages answer this? | | `GET /health` | model + collection counts | ## What it deliberately does not do - **No operational data is embedded.** No bookings, riders or customers. A vector store is a snapshot; this data changes by the minute. Every figure the operator sees still comes from a live API call. - **No generation.** `/ask` returns source passages verbatim with attribution. Summarising needs a hosted model — see `assistant/CLAUDE.md` §2. - **No key.** The embedding model runs in-process. That is what puts this outside §2's blocker. ## Evaluation ```bash docker compose exec ai-sidecar npm run eval ``` Runs the **held-out** set in `eval-set.json` — phrasings that appear nowhere in `phrasings.json` and were not used to tune the thresholds. Retrieval always looks good against its own seed data, so this is the only number worth quoting. Ship criteria: ≥80% accuracy and **zero false write routes**. ## After changing anything Re-run `npm run seed` after editing `phrasings.json`, any indexed markdown, or the embedding model. Nothing errors if you forget — answers just quietly drift from the source, which is the worst kind of failure to chase.