← All posts

Our Coach Sees You Dismissed a Nudge. It Never Learns Why.

A September 12th piece on AI health coaches argues the real test is whether a coach remembers what happened and changes course, not just answers the question in front of it. Mr BITE's chat clears half of that test automatically and only clears the other half if the model decides to go looking.

A smartphone displaying a chat speech bubble, connected by a soft glowing thread to a fainter, translucent duplicate speech bubble sitting on a small calendar page behind it, symbolizing a coach recalling a past conversation

Yesterday, September 12th, Yahoo Style Canada ran a piece asking the question I think everyone building an “AI health coach” right now should have to answer out loud: what actually separates a coach from a chatbot wearing a wellness skin. Their answer wasn’t about model quality. It was about behavior over time. A real coach, the piece argues, “makes a call, watches what happens to you, and changes course,” while a chatbot “answers the question in front of it.” The sharper version of that test: does it remember what you told it yesterday, and does that memory change what it tells you today. Noom’s own answer, cited in the piece, is that its assistant leans on retrieval-augmented generation pulled from a curated clinical knowledge base rather than improvising a plausible-sounding answer cold each time, specifically so it isn’t starting from zero on every message.

I build the chat side of Mr BITE, so that test isn’t rhetorical to me, it’s something I can go check against our own code. The honest answer, once I looked, is that we clear the first half of that bar automatically and only clear the second half if the model decides to go looking for it itself.

Here’s the automatic part. Every time you send Mr Bite a chat message, the edge function assembling its context pulls your three most recent proactive deliveries, the push notifications and in-app nudges it sent you on its own initiative, straight out of mr_bite_proactive_deliveries, and hands the model each one’s scenario, delivery status, and the actual copy it sent, before it answers whatever you just typed. If it nudged you about a protein gap yesterday and you dismissed it without opening it, the model knows that, unprompted, on your very next message. That’s real: not a chatbot re-litigating the same generic line with no idea it already said this and no idea how you reacted.

Here’s the part that only half exists. There’s a second, richer feedback system sitting right next to that one. A record_proactive_feedback tool lets the model itself log that a nudge was “not relevant,” “misunderstood,” “too much,” or should be muted outright, along with whatever free-text reason you gave it, and that write genuinely does something: it updates a per-scenario preference row with a sensitivity level, a cooldown multiplier, and a running count of negative and positive reactions, and that row measurably changes how often and how loudly we nudge you about that specific thing afterward. This is exactly the “watches what happens and changes course” behavior the Yahoo piece describes as the real bar. It just isn’t wired into the same automatic pipeline as the three-deliveries block. The model only reaches it by choosing, on its own, to call a second tool, get_proactive_trigger_preferences; nothing in the per-turn context hands it over for free the way the delivery history is. And on the client side, the only feedback we currently collect through the UI is the coarse kind: shown, opened, dismissed, fired automatically when a banner renders or gets swiped away. Every richer feedback type in that vocabulary, helpful, not_relevant, misunderstood, too_much, mute_scenario, plus the actual free-text reason a user might type, only ever gets written if the model decides, mid-conversation, that this is a moment worth reaching for that tool. There is no button in the app that says “that wasn’t helpful, here’s why.” The only door into that entire system is the model reading the room correctly, every time, on its own.

I don’t want to undersell what’s already there. A chat coach that automatically knows what it told you yesterday and whether you brushed it off is genuinely more than most “AI nutrition coach” marketing copy is describing under the hood, and building that pipe was real work, not a checkbox. But the deeper version of the same idea, that telling Bite “stop bugging me about this, I’m not interested this week” should reliably and permanently change what it does next, currently depends on the model choosing, unprompted, to use a tool that nothing in its instructions specifically tells it to reach for. It’s built. It works when it fires. Whether it fires on any given conversation is still a judgment call we’re leaving entirely to the model.

BITE of the Week: A Resubmission to Apple, and a Crash That Only Showed Up After Launch

A small shield icon with a padlock beside a friendly Android robot icon with a healed crack across its chest, and a small subscription receipt icon with a checkmark, floating near a smartphone silhouette

Two real pieces of news since Issue 21, both landing September 11th. First: Bite went back to Apple with native in-app purchases. The prior submission was rejected under guideline 3.1.1, and the fix was to actually sell BITE Unlimited, monthly and yearly, with a 14-day trial, through StoreKit itself instead of only through the web Stripe checkout, complete with a working Restore Purchases button, auto-renewal disclosure, and Terms and Privacy links on the paywall. Web purchases through Stripe still work too, which guideline 3.1.3(b) allows since Bite already sold subscriptions outside the app before this change. Two new server functions, sync-revenuecat-subscription and revenuecat-webhook, now reconcile entitlements from both stores into one shared column, so whichever store shows an active subscription is the one that wins. Version bumped to 1.13.0 in the same commit. This is a resubmission, not a confirmed approval: nothing in the repo tells me Apple has actually cleared it yet.

Second, and uglier: 1.13.0 briefly crashed on every single Android launch. The cause was a genuinely nasty one to track down. React Native 0.86 renamed its internal JSI runtime type from Runtime to IRuntime, so the compiled libjsi.so on device no longer exports the old symbol. expo-av 16.0.8 ships a prebuilt native library still compiled against that old symbol, and Android loads it eagerly during app startup, before the JS side’s lazy require ever gets a say and before Sentry initializes to catch anything. The fix was to stop using that prebuilt library at all: expo-av now compiles from source against the real RN 0.86 headers on Android, which needed two small patch files for APIs the newer Expo core had already removed (a deprecated view-finder helper, and a keep-awake manager Bite doesn’t use for video anyway), plus a doubled Gradle metaspace limit after the from-source build itself started running the build daemon out of memory.

Three Quick Bites

Three vignettes: a candy wrapper beside a hexagonal molecule diagram splitting into fainter generations of itself, a world map with glowing dots linked by curved dotted lines suggesting bacteria spreading between continents, and a smartwatch face showing a soft radial dial

  1. A mouse study published August 30th in Frontiers in Nutrition found that sucralose and stevia altered gut bacteria, lowered beneficial short-chain fatty acids, and shifted metabolism- and inflammation-related gene activity not just in the mice that ate the sweeteners, but in later generations that only ever drank plain water. Sucralose’s effect on inflammation-linked gene activity persisted through two generations, stevia’s through one; the researchers are explicit that the goal isn’t to alarm, just to argue that moderation and further study are warranted before “sugar-free” gets treated as metabolically inert for good. ScienceDaily

  2. Researchers led by the University of Vienna, publishing in Nature on September 7th, found that individual gut bacterial species actually contain several genetically distinct sub-populations, some of which have spread rapidly across entire continents within just a few decades, with certain fast-spreading populations linked to advanced age, inflammatory bowel disease, colorectal cancer, and type 2 diabetes. The implication for any coaching model that talks about “gut health” as one thing is blunt: the resolution this research is now working at, individual bacterial lineages rather than named species, is finer than almost anything a consumer app currently has a field for. ScienceDaily

  3. Apple’s newsroom announcement on September 9th introduced a new Health Sensing System for Apple Watch Series 12 and Ultra 4: a Health Age score that weighs Apple Watch metrics like VO2 max and sleep against blood-test biomarkers, plus a Readiness score that now updates through the day instead of resetting each morning. None of it carries FDA clearance, and Apple was explicit that Health Age, Readiness, and the new Longevity tab are wellness features, not medical ones, a distinction that matters more every year this whole category keeps blurring into it. Apple Newsroom

Tool of the Week: Mem0

A brain-shaped icon made of softly glowing interconnected nodes and lines, like a small network diagram, hovering above an open laptop silhouette

Since this issue is about how much bespoke plumbing sits behind the word “memory” in an AI coach, this week’s pick is the open-source library other builders reach for instead of hand-rolling it the way we did. Mem0 is a drop-in memory layer for LLM apps and agents: it handles storing, retrieving, and updating what a user has told your assistant across sessions, so a preference stated on Monday can actually inform what the assistant says on Friday without every team writing its own version of that plumbing from scratch. Open source under Apache 2.0, self-hostable, free to run. Mem0 on GitHub

Thanks for reading. If you’d rather your coach actually kept score on what it already told you, Mr BITE is free on iOS and Android.

Michael, building Mr BITE

← Back to all posts