Releases: zilet/cairn
Release list
v1.8.0 — strength travels both ways
Added
- Your strength sessions now show up on Garmin — finish a session in Cairn and its exercises and
sets are added to that day on Garmin Connect. When the watch recorded the workout too, the sets go
onto that recording in place, so heart rate, duration and calories stay exactly as they are and the
day never shows two activities; when you lifted with your phone alone, Cairn creates the strength
activity for you. A day Garmin logged by itself is left alone, and if the watch's own recording
turns up after Cairn already created one, the work moves onto the watch's and the placeholder goes
away. A Garmin sync only looks back a week for sessions to send, so flipping the switch on does
not dump a month of old workouts into Garmin. Runs, sleep and recovery still come in from Garmin
exactly as before. On by default, with a switch in Settings → Sources → Garmin Connect. - You can send your whole training history to Garmin, once you've seen what it would do — a
sync only ever looks back a week, so older sessions stay put unless you ask. Asking shows you the
list first: every finished session, oldest first, what would happen to it, and which lifts Garmin
wouldn't recognise — with nothing sent. Say go and the sessions are sent in small batches, oldest
first, so Garmin's calendar fills in the order you actually trained. You can also ask a coaching
pass to tidy up the movements in that history first — both the ones Garmin's catalog couldn't
place and the ones that were logged before Cairn started cleaning names up, which on a long-lived
log is most of the messy ones. - Cairn speaks the watch's exercise vocabulary — a lift is matched against Garmin's own exercise
catalog (1527 movements) before anything is sent, so a bench press reads as a bench press on the
watch rather than an unnamed set. The match is offline and needs no agent; the harder names are
offered to a coaching agent as a shortlist to choose from, and a movement neither can place is
quietly left out instead of guessed at. Logging a new movement from a session or from chat can
spend a coaching pass to tidy the name so the catalog stays consistent. - A movement can be renamed to the name you'd actually write — "db incline press" becomes
"Incline Dumbbell Press" even after you've logged sets against it. Your numbers and history stay
exactly where they are, and a rename across a real difference (barbell vs dumbbell, incline vs
flat) is still refused.
Fixed
- Chat can read a pasted link without a headless CLI — Antigravity's print mode auto-denies
browse/shell tools it cannot prompt for, and exits with no answer. Cairn now fetches the page
itself (the same pattern as listing a health-export folder so the agent never needsls), drops
the readable text into the prompt, and grants agy the scopedread_url(*)rule Google documents
for headless fetching. A pasted study URL is also routed as current research, so a web-capable
agent is preferred when one is actually available.
Full Changelog: v1.7.6...v1.8.0
v1.7.6 — the coach believes the log
A week can hold a real rest day. A worse lab panel is news. A goal you locked in chat stays locked.
The theme of this patch is a coach that believes the log. What you actually lifted, ran, and ate outranks the calendar, a felt rating, and the plan's own bookkeeping.
- The week can rest, and the long run ramps. A plan day can be Rest — the morning read honors it as a suggestion, never a gate, and no drive setting quietly turns it back into training. The long-run distance is a destination, stepped from your actual longest recent run; interval work no longer steals that slot.
- Work you did counts. A rest day you trained through, or a travel day you still hit your numbers on, is real evidence. Capped sets at the top of the range are the strength signal — you don't need to log a felt rating. A soft "ease off calories" no longer blocks a lift you've earned; at goal the answer is food, not a smaller session.
- The Brief reads the body, not the calendar. A recovery week is earned by loaded weeks plus a log-confirmed shortfall, not by "it's been N weeks." A string of hard days is a note, not an automatic rest. After a hard or longest run, the next easy day is not another run. A rest-grade readiness reading is rest.
- A worse panel is an event. Duplicate draws fold into one record. A marker that moved further off-optimal resurfaces as a fresh card instead of a silent edit. Lab imports still complete when a coaching assistant is out of quota.
- Chat means what it says. A negotiated goal actually saves; if the write can't land, the reply says so. Usual meals draft in the composer for you to edit. "I'll flag that to your coach" leaves a real proposal. Streaming session-suggest copy stays in its card.
- Logging feels instant. Sets, skips, and added exercises paint before the network; the rest timer survives a locked phone; an optional wake lock keeps the screen on while you train. Six anchor lifts track in parallel on Progress. The Back button finally returns from Stand and Changes.
Upgrading: schema migrations 93–99 run automatically on boot (including a repair of 60 days of mislabeled recovery outcomes). Back up first, as always. Installed PWAs self-update on next open (cairn-v562).
Full details in CHANGELOG.md.
Full Changelog: v1.7.5...v1.7.6
v1.7.5 — the calendar can hold today
A small patch finishing what 1.7.4's look-ahead started: the calendar can now hold today, not just tomorrow — and a lab draw knows which half of the day it owns.
Added
- The Brief reads today's calendar, not just tomorrow's — an appointment you've explicitly marked as taking the day now reads as the rest you asked for on that very day, instead of only being honored one day out. A plain errand or trip still just compresses the window; your word is what makes a day yours.
- A blood-draw morning is sequenced, not just softened — a lab draw on today's calendar leans the day easy and says the draw comes first: movement belongs after the needle, because exercise beforehand can nudge the very numbers being measured. A rest earned by your own signals — a short night, a run-down check-in, a low reading — always keeps its own reasons.
Fixed
- A progression sentence stopped contradicting itself — one rotating phrasing of the push-earned load step mentioned "every set" on a day whose whole point was that not every set had to cap; it now says what it means.
No schema change; no client change.
Full Changelog: v1.7.4...v1.7.5
v1.7.4 — progress judged lift by lift, and the Brief reads tomorrow
A patch about grain and horizon: progress is judged at the level where the evidence actually lives, and the day read learns to look at tomorrow before spending today.
- Progress is judged lift by lift, not day by day. A confounder on one exercise — a skipped accessory, a day shared with endurance work — no longer keeps every other lift that day from counting toward progression. Under a "push" training preference, a day pushed at your own request can earn a real overload step; every safety check applies exactly as before.
- The Brief looks one day ahead. A trip, event, or appointment on tomorrow's calendar can gently re-time an already-planned rest day into an easy session, so today doesn't lose ground to a rest that was only ever going to move by a day anyway. A rest called for your safety is never touched.
- An optional how-to layer behind every exercise. A step-by-step guide, primary and secondary muscles, equipment, and demonstration photos behind a quiet "How to" row. Nothing is fetched until you ask for it from Settings → Data, and a movement that can't be confidently matched asks a single yes/no instead of guessing.
- Art generation recovers on its own. A failing image model backs off and retries automatically instead of needing a restart, with a calm status line in Settings. The optional art model and cost overrides in
.envnow actually reach a Docker install (docker-compose.ymlpreviously never forwarded them). - Smaller calm fixes: a day you opened on purpose stays open when you return to the app, and a session's adjustments are explained once, quietly, instead of repeated on every affected exercise.
Upgrading: no new migration number — the how-to layer's table is created automatically on boot. public/ assets changed, so installed PWAs self-update on next open. Back up first, as always.
Full details in CHANGELOG.md.
Full Changelog: v1.7.3...v1.7.4
v1.7.3 — protection buys maintenance, never a surplus
A quality patch about trust in both directions: the coach earns the right to act on its own by holding itself to a harder standard of evidence.
Under lead mode the coach now gives you a heads-up with a one-tap undo instead of asking permission for goal-date and structural changes it can safely own (clinical findings, locked exercises, and anything irreversible still ask). In exchange, its evidence discipline got a full round of tightening:
- Protection buys maintenance, never a surplus. A protective calorie raise during a cut is capped at maintenance measured from your own complete logged days — a formula estimate can hold your target, but never lift it. This closes a ratchet where a chronically-open protective escape could raise the target check-in after check-in, past anything the record supported.
- An unlogged day is not a small one. Logged intake counts as evidence only when the day reads complete (a morning-to-evening span with real calories, or a whole day declared at once). A partial or missing day is absent, never "low" — so thin logging can't read as under-eating, and "you're behind on fuel" nudges are withheld when the log can't support them. The coach also recognizes your logging mode — full, occasional, or quiet — and adjusts what it treats as evidence.
- A pending change is judged against the day it applies. A queued nutrition change is re-derived at its boundary; if the evidence in force that morning no longer supports the number, it's trimmed or set aside with a receipt instead of applied on faith.
- Your own number outranks the queue. Set your calorie target directly (
POST /api/nutrition/target, MCPset_nutrition_target) and any queued machine adjustment is set aside with a receipt saying exactly that. - The cut is grounded in the log. The cut target derives from a safe pace band (0.5–0.75% of bodyweight per week) and a bounded deficit against measured maintenance — when the numbers say the date, the date moves; the calories stop inflating to defend an optimistic deadline.
- The brake needs a second opinion. A single watch-state dimension no longer holds back a training day by itself, and an HRV dip registers on a meaningful band of your baseline rather than a bare sign flip. Safety vetoes are untouched.
- Smaller honesty fixes: a goal date adapts only on material, cooled-down evidence instead of being renegotiated weekly; a change parked by the change budget stays parked; draft proposals with future evidence dates no longer jam adoption (repair migration included); the week-ahead read is served from a background-warmed cache; and the coach quietly asks for a stale weigh-in or waist measurement — a few times, one card at a time, then lets go.
Upgrading: schema migration 92 runs automatically on boot. Back up first, as always. No public/ changes — installed PWAs need no update.
Full details in CHANGELOG.md.
Full Changelog: v1.7.2...v1.7.3
v1.7.2
v1.7.1 — every cut is owed back
- A set the brain takes away now steps down one at a time, is announced instead of applied silently, and is proposed back once fuelling settles — your own edits always win.
- New "Waiting on you" surface: every decision still holding for your call, in plain language, until you resolve it — no more holds aging off the feed.
- Calorie targets arrive with their arithmetic: 3-week logged intake, weight trend, and the maintenance they imply.
- Plan rewrites record before/after per movement, so you can see exactly what changed.
- Lab markers age by kind — genetic results never go stale, fast-moving ones are doubted sooner — and findings re-derive daily.
- A stale readiness reading behaves as absent instead of steering today.
- The learning ledger reaches conclusions again; interpretation stays inside its evidence.
- The signed Apple Health Shortcut ships in the repo — zero-config install.
Full details in CHANGELOG.md. No schema migration; upgrading is a pull + restart.
Full Changelog: v1.7.0...v1.7.1
Cairn 1.7.0 — a coaching brain that's harder to fool and easier to trust
Cairn 1.7.0 — a coaching brain that's harder to fool and easier to trust
This release hardens the adaptive training system and deepens the coach's ability to read what's really happening.
Key changes:
- Rest-read stability: eliminated phantom overrides and fixed the 50% false-positive rate via 2-layer credibility gates (wearable freshness, cross-day memory, soft-cutoff recovery momentum)
- Push progression: bounded acceleration (1.05 base × 1.12 cap), safety floors never earn gains, and predictions live on decisions that outlive their windows
- Adaptive autonomy: clinical decisions route to the clinician floor; material structural changes announce; bounded reversible wins apply quietly
- Brain determinism: step-back revision loops follow falsifiable rules instead of magic numbers; all material decisions record their expected outcome in the ledger
- Signal voice: the Brief and coaching focus now speak in athlete language separate from the machine evidence layer (recovered yesterday → "you felt recovered yesterday")
- Day-read grammar: agent headlines and reasoning are validated against deterministic vocabulary — leaked engineering, numeric scores, and gate language all fail validation
- Nutrition pattern detection: meals now record eaten_at; all time inference is one-way (time → label, never reverse)
- Marker grouping: display order matches clinical lab-review sequence, with doctor export honoring the same taxonomy
Deploy & verify:
docker pull ghcr.io/zilet/cairn:v1.7.0
docker compose up
# Health check: curl http://localhost:8787/api/healthDatabase migrations: 80 → 87 (applied automatically on boot). Back up before deploying.
Breaking changes: None. Schema is forward-compatible; existing plans and logs migrate transparently.
Testing: 462 green test files (offline, deterministic). Multi-arch image (amd64 + arm64) verified in CI.
Cairn v1.5.1 — honest nutrition progress
What is new
A real multi-week nutrition read
- Progress → Fuel → Intake adds a calm 35-day view across Energy, Protein, Carbs, Fat, and Fiber.
- Daily timelines keep unlogged and unknown days visible as gaps instead of silently counting them as zero.
- Open-day intake stays visible but is excluded from completed-day averages and trends.
- Historical target markers follow the reference that was actually active on each date, with honest per-nutrient provenance.
- Macro balance, observation density, sampled food-quality context, and relevant health context help turn logging into one useful next move rather than another score.
Better food and fat estimates
- Food enrichment can now estimate saturated and unsaturated fat when the food, total fat, cooking method, and cooking oil support a defensible split.
- Explicit preparation details such as grilling with olive oil take precedence over generic assumptions.
- Estimates are clearly labeled, internally checked against total fat, and left unknown when the evidence is too weak.
- Older food history remains categorical where gram-level estimates were not captured.
- Durable memory is reduced locally to canonical cooking-method and cooking-fat tokens before a food prompt is sent; unrelated health, family, medication, address, or free-text memory is not forwarded.
Fuel is clearer without becoming primary navigation
- Today and the editable day-fuel view now show Energy, Protein, Carbs, Fat, and Fiber.
- Unknown or pending nutrients render as unknown rather than fabricated zeroes.
- The primary Today fuel action still opens Plan → Food; the detailed read lives under Progress → Fuel → Intake.
- REST
GET /api/nutrition/progressand MCPget_nutrition_progressexpose the same deterministic analysis.
Reliability and compatibility
- Existing
/api/nutrition/dayand MCPget_day_intakenumeric totals remain backward compatible; additiveknownflags let newer clients render incomplete data honestly. - Nutrition progress describes record observation density, not claimed meal completeness, and target comparisons remain conditional unless the records reflect most of the day.
- Health-context intake data is memory-only in the browser cache.
- Background enrichment refreshes an open Intake read when estimates settle.
- No database migration is required. PWA cache:
cairn-v518.
Install or update
Download the attached docker-compose.yml, which is pinned to:
ghcr.io/zilet/cairn:v1.5.1
Images are published for linux/amd64 and linux/arm64.
Full changelog: v1.5.0...v1.5.1
Cairn v1.5.0 — the learning brain
Cairn v1.5.0 — the learning brain
This release makes the coaching brain reactive and accountable: every read stays truthful as your data changes, the brain checks whether its own cross-domain moves actually worked, and the coaching agents can look up your live data mid-thought.
The brain closes its loops
- Lab loop: a meal-plan or training change applied while a lab-marker directive is active now records a falsifiable "this marker should move toward optimal by the next draw" expectation. Your next lab ingest verdicts it, and decisive outcomes become a humbly-worded learned per-marker response ("last time, the fiber-forward tilt coincided with ApoB falling"). One lab draw counts as exactly one evidence unit, however many plan re-drafts anchored it.
- Felt signals: recurring Brief overrides (your "rough night" Mondays), persistent check-in patterns, and how the last calorie-target change actually felt all become quiet learned context. A thumbs-downed insight theme never resurfaces.
- Learned cross-domain models: body-measurement trends feed the intake step (capped to hold-or-ease — measurement evidence can never deepen a deficit); a personal endurance↔strength interference read learns whether your bigger run weeks flatten your leg days; short-sleep nights get a calm fueling context line, in a learned voice once your own correlation is derivable.
Nothing asserts a stale story
- The Brief's fuel line is now pace-aware — "protein's light" only appears when you're genuinely behind for the hour, and a meal logged after the read heals the prose in place. Food and meal-plan writes invalidate the cached Brief like every other signal.
- The weekly read carries a drift signature: when your week moves underneath it, it defangs itself ("Moved on") and offers a one-tap re-read instead of asserting last Sunday's advice.
- A new material nutrition directive proposes a meal-plan regeneration through the autonomy tiers instead of waiting for the weekly slot.
Depth on demand
- The bounded coach-read loop (server-owned, read-only, budget-capped) now serves every interactive coaching op — day read, session suggest, nutrition check-in, health review, insights, health synthesis — and is streaming-aware: agents can query your data mid-reasoning and still stream their final answer token-by-token.
- Chat gained the same depth: the coach quietly checks your history before answering ("Reviewing your history…"), with malformed protocol turns cleanly re-asked, never leaked into the bubble.
Daily session composition (Stages 2–4)
- A deterministic, reason-coded decision envelope for each training day (what's due, what's excluded, caps) with a stable policy version and input fingerprint.
- Bounded agent composition inside that envelope — at most one novel movement, refused entirely when injury exclusions are active.
- Outcome reconciliation: suggested-vs-actual after each session, adherence-neutral with life-context confounders, feeding the progression brain.
Capture feels alive
- Chat food logs now show live enrichment progress and upgrade in place with the computed calories and protein, refreshing the fuel strip — including after a reload.
Also
- Adaptive chat lane routing with per-run model/reasoning bindings, identity-keyed directive engine with whole-panel correlation and scheduled rechecks, persistent adaptive daily sessions, a timed-set stopwatch, and a calmer Today.
- Schema migrations apply automatically on first boot after the update — back up first (
/api/export), as always. Update is otherwise a pull-and-restart.