In development
Bodivo
A training and nutrition app that learns how your body actually responds instead of handing you a fixed plan, and tells you plainly when it does not yet know enough to say.
Adaptive fitness and nutrition — it models the individual rather than the plan, and says so when it does not know.
- Platform
- Web
- Status
- In development
- Demonstrates
- Evidence-typed state
02
What it is for
For one person at first, and built multi-tenant from the beginning anyway.
A training app hands you a plan. The plan does not know that you slept badly, that the last three sessions went better than it expected, or that it has no data on you at all yet. Bodivo is built to answer three questions the moment it opens: where am I, how am I doing, and what should I do next. The weight is on the last one. The part I care about is that it refuses to answer any of the three when the evidence is not there.
03
Why it exists
A training plan is a guess made once, in advance, by someone who has never met you.
The apps that replaced the paper plan mostly kept its shape and added charts — and to fill those charts they render a zero where they have no reading, draw a trend through two points, and call a week of noise progress. Each is a small lie and the aggregate is why nobody trusts them. The people with the problem are anyone training seriously enough to want the plan to respond to them.
04
Screens




05
What it does
Provenance-typed metrics
Every value declares measured, calculated or unknown. An unknown is never rendered as zero.
Adaptive challenge
A daily verdict — push, progress, hold or recover — from typed, signed signals across seven families.
Goal-shaped progress
What counts as progress for a marathon block is not what counts for a lean bulk, and the model reshapes accordingly.
Evidence-backed characteristics
A belief about the person and the evidence for it are separate rows; one cannot exist without the other.
Calibration
Baseline assessment that establishes what is actually known before anything is prescribed.
Agent governance contract
Teams, tool registry, compute tiers and reach limits, declared before any model runtime is connected.
RLS tested in SQL
Row-level security and migration safety verified by a SQL test suite, not only by application tests.
Nutrition and recovery
Meals, macros, hydration, sleep, mood and heart rate, all feeding the same evidence layer.
06
What it runs on
Client
- 01
- React 19
- 02
- TanStack Start
- 03
- TanStack Router
- 04
- shadcn/ui
- 05
- Tailwind
Backend
- 01
- Supabase Postgres
- 02
- 55 tables
- 03
- 36 migrations
- 04
- SQL-level RLS tests
Services
- 01
- Vitest
- 02
- Playwright
- 03
- No model provider — by design
07
How it's built
TanStack Start with server-side rendering over Supabase Postgres — fifty-five tables across thirty-six migrations. The layering is the architecture: around thirty domain modules are pure, with no database access, no clock reads and no randomness, because today is passed in as a parameter. Only files suffixed .server.ts touch the database. Seventy-eight test files sit against that pure core, which is what makes forty-odd thousand lines of rules maintainable.
The belief system is two tables rather than one: a characteristic and the evidence for it are separate rows, so a claim about the person always has something behind it. Proposals are recorded as experiments and checked against what happened.
There is no language model anywhere in the running system. The agent topology — teams, specialists, a governed tool registry, and a compute ladder where deterministic work may never be sent to a model — is declared as a typed contract with no runtime attached, and the app reports that honestly on its own system page.
08
Architecture
One figure, read left to right. Border treatment carries the node type; the color is the project's.
- Service
- Store
- External
- Model
09
A piece of the code
src/lib/domain/agents.ts
/** No model runtime is wired to this registry yet. Surfaced honestly in /system. */export const AGENT_RUNTIME_CONNECTED = false;/** * Where the work belongs on the cost/quality ladder. * * Deterministic work must never be sent to a model: it is arithmetic with a * right answer. Cached is derived state recomputed on an event, not per * view. Light handles language, classification and summarising. * Reasoning is reserved for genuinely open-ended synthesis over conflicting * evidence, and is always triggered by an event with an evidence floor met. */export type ComputeTier = "deterministic" | "cached" | "light" | "reasoning";/** What a specialist may do at most. Never widened by an autonomy setting. */export type AgentReach = "read_only" | "propose_only" | "propose_and_execute";Excerpt — trimmed for reading, not a full file.
10
The hard parts
01 — Problem
Every fitness app renders a zero when it has no data. A weight chart starting at zero, a trend line drawn through two points, an encouraging verdict from a week of noise. Each is a lie, and the aggregate is why nobody trusts these apps.
Approach
Provenance is part of the value rather than metadata about it. Every metric declares measured, calculated or unknown; a trend carries its sample count, its span, whether it is sufficient, whether it is stale, and a plain statement of what was observed or what is missing. A view with no evidence returns why, and what would fill it.
Tradeoff
The interface is harder to build and, early on, emptier. A new user sees a lot of "not enough evidence yet" where a competitor shows a confident zero. That is the correct trade and it is also why the product looks sparse.
02 — Problem
The daily verdict has to come from signals that are always partly missing. The naive system defaults to recovery whenever data is thin, which produces a coach that tells you to rest forever.
Approach
Recovery is never the default: it requires a hard constraint or at least two corroborating signals. Injury and illness win outright. Missing data lowers confidence and never forces a conservative verdict. Being behind trajectory biases toward pushing when capacity supports it; being ahead caps the verdict rather than licensing acceleration. Every decision reports the signals it used and the ones it did not have.
Tradeoff
Deliberately asymmetric — it is easier to reach push from thin evidence than recovery. That is a risk posture, taken because a system that quietly under-trains someone is worse than one that occasionally over-reaches.
03 — Problem
A constraint someone recorded but never rated in severity. The original schema stored it as medium, which is unreadable: is that their judgement, or a default nobody set?
Approach
Unstated became its own value, neither blocking nor limiting. It guards nothing and contributes only a guardrail line.
Tradeoff
Three-state severity everywhere it is consumed rather than two. Promoting silence to a hard block would have turned every constraint ever recorded into a forced rest day.
04 — Problem
The usual order is to call the model, see whether it is useful, and add guardrails after something goes wrong. By then the model's reach is load-bearing and narrowing it breaks features.
Approach
The topology, the tool registry, the compute tiers and the reach limits are declared as a typed contract with no runtime. Deterministic work — arithmetic with a right answer — may never be sent to a model. A specialist's reach is never widened by an autonomy setting. The app exports the fact that no runtime is connected and shows it on its own system page.
Tradeoff
A large file that currently executes nothing. If the runtime never arrives it is dead weight, and that is a real risk this early.
Ask about Bodivo
Answers are drawn from the notes and source behind this case study, and cite what they read.