A self-hosted health coach with a brain, not a dashboard. Cairn reads your labs, lifting, running, food, sleep and life as one picture and suggests the one thing worth doing today. It runs on your own hardware, keeps your data in a SQLite file you own, and never scores or nags you.
The Brief → the whole-picture analysis → the connected brain → progress → recipes → coach chat · made with fictional demo data
Want to look before you install? One click runs a real Cairn, preloaded with fictional demo data, in your browser — nothing on your machine. More cloud options:
docs/SANDBOX.md.
- It reads your day. Cairn opens to a calm Brief — rest, easy, or train, in plain language, with the reasoning shown. A suggestion, never a gate. You drive.
- It connects your labs to your meals and your training. A flagged marker propagates into concrete nutrition, training and watch directives, each with its why and a citation.
- Adaptive nutrition that never blames you. Expenditure is derived from your real weight trend;
a thin logging week lowers confidence instead of scolding.
change: falseis the common answer. - Lifting and running plans that evolve. Earned overloads, deloads where you stalled, a conservative ramp and taper toward a race — adapting to the work you actually did.
- Agent-native. A full MCP server ships alongside the PWA, so any MCP client can read and write everything Cairn knows.
One Node service serves the PWA (/), the REST API (/api/*), the MCP server (/mcp), and a
background scheduler; storage is SQLite via Node's built-in node:sqlite. The north-star is
docs/VISION.md: calm, suggestion-never-gate, no scores, pull-never-push.
The Brief (left) and the connected brain (right), top to bottom.
Every screenshot uses a fictional demo persona — no real health data. Populate the same demo yourself with npm run seed:demo.
You don't need the source. The image is published to GHCR (multi-arch, amd64 + arm64):
docker run -d --name cairn -p 127.0.0.1:8787:8787 \
-v cairn-data:/data -v cairn-home:/home/app \
-v cairn-tools:/home/app/.cairn-tools \
--restart unless-stopped ghcr.io/zilet/cairn:latestOpen http://localhost:8787 — you land on the Brief immediately. Three named volumes keep your
data (cairn-data), your CLI logins (cairn-home), and any tools you install (cairn-tools)
across updates, so rebuilds touch none of them. To update: docker pull ghcr.io/zilet/cairn:latest
and re-run. Add -e TZ=Europe/London for your timezone.
Prefer a compose file, with the env vars and loopback-safe defaults already wired up? Or want the source, to build locally and develop?
curl -LO https://github.com/zilet/cairn/releases/latest/download/docker-compose.yml && docker compose up -d
git clone https://github.com/zilet/cairn.git && cd cairn && ./quickstart.shquickstart.sh detects Docker (preferred, no Node needed on the host) or falls back to local Node
24, starts Cairn, waits for health, and prints the URL. Node 24 is required for a non-Docker
run — that's where node:sqlite is unflagged. The Docker image bundles it.
First paint is real, no agent required. For chat, adaptive coaching, and meal plans, add one
agent: open Settings → Agents, tap Install on the provider you use, then Connect. A
terminal opens in the browser and walks you through that provider's sign-in — no docker exec
needed. An agent you haven't connected stays out of the rotation rather than failing requests. Full
detail, including terminal logins and the Grok API-key path:
Connect your first agent.
Important
Security & where to run it. Cairn ships with no authentication by default — it is a
single-user app built for a network you already trust, not the public internet. Run it on your
own machine, a home server, or a small VM. The simplest setup that is both private and reachable
from your phone: put the host on a Tailscale (or similar) network and open
it by its MagicDNS name — no ports forwarded, no certificates to manage. Never expose port
8787 to the open internet. If any untrusted device can reach it, set CAIRN_AUTH_TOKEN to
require a shared token, and serve it over HTTPS (Tailscale Serve / a private reverse proxy) so the
PWA can install offline. See SECURITY.md and docs/DEPLOYMENT.md.
Cairn is fully usable the moment it boots, with no agent and no API key. A coaching agent adds the conversational and generative layer on top — and the app stays useful while you set one up.
| Works out of the box (no agent) | Needs a logged-in coaching agent |
|---|---|
| The Brief — calm rest/easy/train suggestion | The agentic Brief sentence (the plain-language read on top) |
| Set-by-set logging, history, PRs, est-1RM | Coach chat |
| The plan editor (add/remove/reorder days) | Agent-shaped training and meal adaptations |
| Bodyweight chart, goal feasibility check | Health-review narrative |
| Optimal-zone marker trends & the marker catalog | Lab-document marker extraction (upload → structured markers) & quiet insights / weekly read |
| Recovery view, deterministic TDEE / expenditure | Recipe generation, single-meal swaps |
| Activities, food notes, memory, family, life context | Background enrichment of free-text logs |
| Endurance stats, run compliance, race countdown, PRs | Agent-refined weekly run prescriptions |
A coaching agent means one of the supported CLIs — Claude Code, Codex,
Antigravity, or Grok — installed into Cairn's persistent home volume and logged in with
your own account. There is no shared key and no built-in model: install only providers you use. The
built-in stub agent exercises Cairn's offline agent contract with no key, for smoke testing before
you connect a real coach.
| If you want... | Start here |
|---|---|
| Just run it on your laptop (no clone) | the docker run … ghcr.io/zilet/cairn:latest above |
| Build from source / develop | ./quickstart.sh |
| Keep it always-on at home | ./scripts/quickstart-rpi.sh on a Raspberry Pi or small home box |
| Put it on your phone as an installable PWA | ./scripts/setup-phone.sh (Tailscale Serve, tailnet-only) |
| Give a household member a private profile | Run one isolated released instance per person; see docs/HOUSEHOLDS.md |
| Run it on a cheap VM | Docker + Tailscale; see docs/QUICKSTART.md#small-vm-private-online-box |
| Try it on demand in the cloud | docs/SANDBOX.md for Daytona / Codespaces |
Cairn is agent-native: the same logic the PWA uses is exposed as an MCP server at /mcp
(Streamable HTTP), so a Claude client — or any other MCP client — can read and write everything.
Point Claude Code at it with one command:
claude mcp add --transport http cairn http://localhost:8787/mcp253 MCP tools span the plan, sessions and exercises, the accountable coaching loop, profile and
goal, activities and bodyweight, memory, meal plans and recipes, health records and markers, the
connected-brain directives and insights, recovery, chat, Garmin sync, and settings. A representative
slice: get_plan, log_set, get_day_read, suggest_session, draft_plan_update,
apply_proposal, draft_meal_plan, swap_meal, get_priority_markers, list_directives,
generate_insight, log_activity, log_food_note, set_profile, sync_garmin.
This is where vision and loose natural language belong — snap a plate and say "this was lunch,
estimate it", or "log my ride: 2h in the fells, felt strong". Packaged Claude Code and Codex
skills at .claude/skills/cairn/ and .agents/skills/cairn/ map everyday phrases to these tools.
The same surface is reachable over REST — 307 routes across 107 groups under /api. Both
indexes are generated from source and never hand-edited: docs/MCP-TOOLS.md
and docs/API.md.
MacroFactor? Its adherence-neutral expenditure model is the right way to do adaptive nutrition, and Cairn adopts the same philosophy on purpose. The difference is that here nutrition is one domain rather than the whole product — a meal target can be shaped by a flagged lab or suppressed during a travel week, automatically. MacroFactor wins if you want a refined single-purpose nutrition app maintained for you and you don't want to host anything.
Oura / Garmin / Whoop? Wearables are the best in the world at measurement, and Cairn reads from them rather than replacing them. What it adds is synthesis instead of a metric wall, and the loop your watch leaves open: Garmin records the run you did, Cairn writes the run you should do next. The wearable wins on precise passive measurement — keep it, and let Cairn read from it.
ChatGPT and a spreadsheet? The closest comparison, and genuinely capable. Cairn is what happens when you make that loop durable: every coaching call is already grounded in your profile, plan, sessions, labs and memory, a flagged lab propagates into directives still there next week, and nothing changes your plan without propose → review → apply. ChatGPT wins for a one-off question with zero setup.
Another self-hosted tracker? Most are excellent ledgers — they record what you did, well. Cairn is trying to be the thing that reads across those records and points at one action. A focused tracker wins if you want a stable offline log and no agent in the loop at all.
The longer, fully honest version is docs/WHY-CAIRN.md.
- Not a social app. No feed, no friends, no leaderboards, no sharing.
- Not a multi-user SaaS. Cairn is single-user by design. No account system, no billing, no team management.
- Not medical advice. Health findings are informational. It is a buddy who reads your numbers, not a doctor — anything clinical defers to a clinician.
- Not a wearable. It has no sensors of its own; it reads from the ones you already have.
- Not an engagement machine. No streaks, points, badges, push nags, or upsell. It has nothing to sell and no one to retain. If it ever feels like it's trying to keep you in the app, that's a bug.
- Not zero-setup. It's self-hosted. That's the price of owning your data and your model.
| Doc | What it covers |
|---|---|
docs/QUICKSTART.md |
30-second start, Raspberry Pi, VM, Docker, Node, agent setup |
docs/DEPLOYMENT.md · docs/OPERATIONS.md |
Tailscale, HTTPS PWA, updates, migrations, backup/restore |
docs/HOUSEHOLDS.md · docs/SANDBOX.md |
Private profiles per person; Daytona / Codespaces |
docs/APPLE_HEALTH.md · docs/GARMIN.md |
Bringing sleep, HRV and activities in |
docs/API.md · docs/MCP-TOOLS.md |
Generated REST + MCP reference (npm run docs:index) |
docs/VISION.md · docs/WHY-CAIRN.md |
The product constitution; how Cairn compares, at length |
docs/ARCHITECTURE.md · CHANGELOG.md |
Subsystem depth for contributors; release history |
Schema migrations run automatically on every boot, so an update is docker pull and re-run.
I had the data — years of lifts, a watch on my wrist, bloodwork in a folder — and none of it talked to anything else. Every app was excellent at its one column and blind to the other five. I didn't want another dashboard to interpret; I wanted something that had already read all of it before I opened it, and had one honest thing to say.
So the rules came first. No scores, because a number you must decode is the opposite of calm. No notifications, because a tool that has to interrupt you hasn't earned being opened. Suggestions rather than gates, because it's my body and my day. Self-hosted, because a system that knows this much about you should live on hardware you own.
A cairn is a stack of stones on a trail. It doesn't shout, it doesn't follow you, and it doesn't tell you where to go — it sits at the junction and marks the path, and you consult it when you get there. That's the whole idea.
Contributions welcome — see CONTRIBUTING.md (Node 24, the thin-adapter rule,
the migration + service-worker conventions) and CODE_OF_CONDUCT.md.
Licensed under MIT. Built with Node 24 + TypeScript, Express, node:sqlite,
@modelcontextprotocol/sdk, a vanilla PWA, and Docker.