Self-hosted wellness OS for training, nutrition and longevity. Connects labs, lifting, running, food and sleep into one agentic brain that suggests the one thing worth doing today. PWA + REST + MCP server.
Cairn presents a well-designed domain-specific tool suite for a fitness/wellness coaching system. All 9 tools have explicit definitions in src/brain/read-tool-runtime.ts with consistent naming (read_* verb prefix), comprehensive descriptions (160-260 chars each), and documented input schemas with type definitions and parameter descriptions. Tools follow single-responsibility principle and are clearly distinguished (e.g., read_exercise_history vs read_training_window vs read_recovery_window). Descriptions explicitly state WHEN to use each tool, preventing LLM confusion. All parameters have types and descriptions. However, output schemas are not documented in the source code, tool responses are not formally specified. Error handling is not visible in the provided code. Tool descriptions lack specific constraints (ranges, enums) for numeric parameters like 'limit' and 'weeks', though parameter bounds are mentioned. No evidence of batch operations or idempotency guarantees. The server is READ-ONLY, which reduces composition complexity but limits practical utility for agents that need to take action.
Weigh-ins, tape measurements, and DEXA results as one date-ordered event list, most recent first. Use it when composition or the rate of change over months matters. It does not include the current target or intake; read_nutrition_window carries those.
The exact stored prescription for ONE training day (by day number) or ONE meal-plan day (by day name): every item with its targets and notes. Use it when the DATA snapshot summarizes a day and the full items are needed before proposing a change. It returns the plan only, never logged work or adherence, and found:false when no such day exists.
Prior brain decisions of one kind (day_read, session_suggestion, training_target, meal_plan, recovery_adjustment, and the other kinds in the args contract) or about one subject key, each with the expectations it set and the latest evaluation of each. Use it before repeating a call the system has already made, to see what was tried and whether it held. Either kind or subject_key is required; it returns no raw training or health data.
Logged sets, current plan targets, and best capacity (est-1RM or longest hold) for ONE canonical exercise over a bounded date window, with per-set feedback where it was rated. Use it when the question is a single movement's trajectory — a stall, a regression, the last full-load session. It returns nothing about other exercises from the same sessions and no day-level load; read_training_window covers the whole training picture.
Output schemas not documented. Tool descriptions state WHAT is returned (e.g., 'date-ordered event stream', 'every recorded value of ONE lab marker'), but formal output schema definitions (JSON Schema objects with typed fields) are not visible in the source code. LLMs cannot reliably plan downstream tool chains or extract structured fields without documented return types.
Numeric parameter constraints not formally specified as enums or ranges in schema. Parameters like 'limit' (bounded 1-200), 'weeks' (bounded 1-12), 'days' (bounded 1-90) have described constraints in text but no JSON Schema minValue/maxValue or enum declarations. LLMs cannot validate input without formal constraints.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 66 | 2026-07-28+ | v2 |
Life-timeline events that overlap a date range — trips, injuries, illness, family and life events — each with its dates, expected recovery, and whether it has been resolved. Use it to explain a disrupted stretch or to check for a constraint still in force before proposing load. It does not include same-day context tags or free-text symptom reports.
Every recorded value of ONE lab marker in date order, plus the directives, supplements, and active medications related to it. Use it when a health question hinges on how a single marker has moved between draws. It returns only the marker named — no full-panel view — and reports found:false when the name resolves to nothing.
Daily logged intake for the last N days with coverage (how many of the requested days were logged at all), estimated expenditure, the nutrition targets in force, and the weight trend over the same span. Use it for fueling questions and target adjustments. A day that was not logged is reported as missing, never as low intake.
One row per day for the last N days: sleep, HRV, resting heart rate, stress, body battery, steps, acute load, and Garmin training status, with the source of each day named. Use it when physiology, not behavior, is the question. It carries no training or nutrition data; pair it with read_training_window or read_nutrition_window when load or fuel is part of the question.
A date-ordered event stream for the last N weeks: every session with its dose and feedback, every cardio activity, and skipped days, so consistency, volume trend, and missed work can be judged as a whole. Use it for the shape of recent training. It does not detail one exercise's sets (read_exercise_history) or the athlete's physiology (read_recovery_window).
No error handling guidance documented. Tool descriptions do not explain what happens on failures (e.g., when a marker name resolves to nothing, when no plan exists for a requested day, when date ranges are invalid). Recovery paths and retryability are not stated.
All tools are read-only, limiting agent agency. A production coaching agent needs tools to create training plans, adjust nutrition targets, log sessions, and record recovery metrics. Current tool set is purely informational and cannot execute decisions.
read_decision_history has ambiguous parameter semantics. Either 'kind' or 'subject_key' is required, but descriptions do not clarify what each represents or provide examples. A coaching agent cannot reliably construct queries without concrete guidance on valid 'kind' values (e.g., 'day_read', 'session_suggestion').
read_current_plan_detail has mutually exclusive parameters but does not formally document the dependency: when scope='training', day_number is required and day is ignored; when scope='meal', day is required and day_number is ignored. LLMs may pass both or neither, causing failures.