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
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.
/askreturns source passages verbatim with attribution. Summarising needs a hosted model — seeassistant/CLAUDE.md§2. - No key. The embedding model runs in-process. That is what puts this outside §2's blocker.
Evaluation
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.