Mo Paws — a multi-model AI pet companion
A cross-platform assistant for dog owners: breed-aware answers, a structured behaviour assessment, and a health schedule that actually remembers what's due. Owned end to end — auth and data model through to the routing layer that decides which model answers each question.
At a glance
The problem
Ask a general-purpose chatbot "how much should my 4-month-old Pomeranian be eating?" and you get a confident, generic answer that ignores breed, age and the fact that you asked the same thing last week. Ask a forum and you get eleven contradictory answers. Neither remembers your dog.
Mo Paws is the version I wanted for Mocha, my Pomeranian: an assistant that knows the breed, keeps the pet's profile and health schedule as first-class data, and gives an answer grounded in a curated source rather than whatever the model happened to memorise.
The engineering problem underneath it is unglamorous and specific — make it fast, make it cheap, and make it impossible for one user to read another user's pet data.
Constraints I designed against
- Consumer latency budget. A pet owner on a phone abandons a screen that thinks for four seconds. First token has to feel immediate.
- A hard cost ceiling. Small team, no enterprise budget — per-request cost is a design constraint, not an afterthought.
- Multi-tenant from day one. Every row belongs to a user. A bug in an API handler must not be able to leak another household's pet.
- Correctness where it matters. Feeding amounts, vaccination intervals and breed-specific risk are not places to let a model improvise.
- One person, one codebase. Anything that doubles the maintenance surface has to earn it.
Architecture
Highlighted nodes are the three places most of the engineering time went.
In the product
Decisions & trade-offs
Rule-based retrieval instead of a vector index
One router, three providers
RLS as the authorization boundary
if statement, and every schema migration has to carry its policy changes with it.Streaming + preloading over a faster model
Answers cite what they read
The model proposes; the owner commits
Capacitor instead of a native rewrite
Assessment grounded in published frameworks
Where it landed
- Cold-start latency down 75–80%. Preloading plus routing moved first response from "is this broken?" to conversational.
- Full breed coverage. 206 breed profiles spanning 205/205 of the stored AKC baseline list, so breed lookups never fall back to model memory.
- No cross-tenant data path. Every pet, profile and schedule row is gated by RLS policy rather than by handler discipline.
- Single codebase across three platforms, with the same auth, retrieval and routing behaviour on each.
- Answers are attributable. Each response lists the records it read and how many sources it used, so a wrong answer can be traced instead of argued about.
- No silent writes. Every AI-proposed care item needs an explicit confirmation before it touches the pet's schedule.
- Provider-outage tolerance. A failing provider degrades to a fallback model instead of an error screen.
What I'd do differently
Build the eval harness before the third prompt rewrite. Today prompt changes get a regression pass and structured-output schema validation with retries — which catches format breakage but not quality drift. A proper offline eval set with graded answers should have existed from the start; retrofitting one means reconstructing the cases I already fixed by hand.
Instrument cost per conversation earlier. I added latency and cost awareness to the router before I had good per-conversation attribution, so the first version of the routing policy was reasoned from first principles instead of measured. Measurement changed two of the thresholds.
Treat the knowledge base as a versioned artifact sooner. It started as content and became a dependency. It should have had a schema, a validator and a review step from entry one.