fatnag

FATNAG

Privacy-first iOS app for the Xiaomi Mi Body Composition Scale 2 (XMTZC05HM; label variant XMTZCOSHM treated the same). Replaces Zapp Lite: BLE weigh-ins on-device only, results into Apple Health, optional Coach via a shared Grok Worker, on-device Apple Intelligence when eligible, and a 0.5B Metal polish sidecar on other compatible iPhones.

Β  Β 
Version 1.0.97 (build 192)
Device iPhone 15 (physical; BLE + HealthKit)
Xcode / SDK Xcode 27, iOS 27 SDK
Deployment iOS 26.0, iPhone only
Bundle id app.thescale.ios
Team Human Analog Limited (XHVW66YM39)

No accounts. No analytics. Weigh-ins never leave the phone except into Apple Health. Users never paste an API key.

App Store release checklist (2.47.0+)


Features

BLE weigh-in

Calibration

History / charts / Trend / projection

Manual entry

Coach (Grok)

Memory / persona

Health monitoring

Foundation Models notifications

Onboarding (1.0.91–1.0.93)

Eight first-launch pages, one instruction each: Language β†’ Units (kg/lb) β†’ Name β†’ Age/sex β†’ Height & weight β†’ Dream weight + date β†’ Food (optional) β†’ Legal. Units are chosen before any mass dial. Food is diet chips + optional avoidances/city (Skip for now if empty). Dream date must pass the safe-pace gate. After Start weighing, a 3-screen send-off (β€œGo weigh yourself. Now.”) then home.

Progress / goals


Architecture

Mi Scale 2 (BLE ads)
        β”‚
        β–Ό
   FATNAG (iPhone)
        β”‚
        β”œβ”€β”€ HealthKit  ←→  Apple Health
        β”œβ”€β”€ UserDefaults (profile, cal, memory, prefs)
        β”œβ”€β”€ Foundation Models (on-device; Apple Intelligence)
        β”‚
        └── HTTPS (opt-in Coach / fitness)
                β”‚
                β–Ό
        Cloudflare Worker (grok-proxy)
                β”‚
                β–Ό
              xAI Grok

Depth: docs/architecture.md Β· docs/coach-and-ai.md Β· docs/health-and-notifications.md


Setup

Mac Mini checkout

cd /Users/alexclaw/Projects/project-zero
git checkout main && git pull origin main
open TheScale/TheScale.xcodeproj

Standing rule: Xcode 27 + latest iOS. Point CLI tools at Xcode if needed:

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

Shared Grok proxy

Preferred: xAI key stays on the Worker (never in the IPA). App authenticates with a separate shared secret.

cd workers/grok-proxy
npx wrangler secret put XAI_API_KEY          # paste at prompt; never commit
npx wrangler secret put APP_SHARED_SECRET    # openssl rand -hex 32; same value β†’ Secrets.xcconfig
npx wrangler deploy

Canonical build config: TheScale/Config/TheScale.xcconfig (Debug + Release).

xcconfig https:// footgun: Xcode treats // as a comment. Never write a bare https:// URL.

# WRONG β†’ becomes https:
GROK_PROXY_URL = https://the-scale-grok.alexhuther.workers.dev

# RIGHT (empty $() splice)
GROK_PROXY_URL = https:/$()/the-scale-grok.alexhuther.workers.dev
GROK_API_KEY =
GROK_APP_SECRET =

Gitignored override: copy Secrets.example.xcconfig β†’ Secrets.xcconfig and set GROK_APP_SECRET. Empty secret β†’ fail closed (offline Coach). Never bake XAI_API_KEY into the IPA.

Worker also rate-limits IP/device and enforces Free/Plus/Pro weekly caps in KV. Details: workers/grok-proxy/README.md.

Health check: curl -s https://the-scale-grok.alexhuther.workers.dev β†’ ok, auth: shared_secret, weekly_limits.

Apple Intelligence + on-device polish sidecar (2.51.0)

  1. Apple Intelligence phones (15 Pro / 16+): Settings β†’ Apple Intelligence & Siri β†’ on; wait for model. App Settings shows FM ready. Sidecar is never downloaded.
  2. Other compatible iPhones (including base iPhone 15): after onboarding, auto-install Qwen2.5 0.5B (~470 MB, Wi-Fi preferred) via Packages/ScaleOnDevicePolish. Settings shows download / Polish ready.
  3. Trigger a bad-trend alert or Coach wake reminder; copy should use your name and Coach voice (FM or sidecar).
  4. If neither path is ready, algorithmic strings still fire.

Run on iPhone 15 (required for BLE)

Simulator does not replace on-device BLE + HealthKit verification.

  1. Open TheScale/TheScale.xcodeproj
  2. Signing: team Human Analog Limited, bundle app.thescale.ios
  3. Destination: iPhone 15 β†’ Product β†’ Run
  4. Allow Bluetooth; allow Health on first Confirm / Manual save

Unit tests (math only; not a BLE substitute):

cd TheScale
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
xcodebuild test -scheme TheScale -destination 'platform=iOS Simulator,name=iPhone 17'

Smoke-build without a phone:

cd TheScale
xcodebuild build -scheme TheScale -sdk iphoneos -configuration Debug -destination 'generic/platform=iOS'

Privacy model

Data Where
Scale weight / impedance In memory on iPhone
Profile, persona, calibration, Coach memory, prefs UserDefaults on device
Health reads / writes HealthKit on device
Foundation Models On-device only
Grok requests Opt-in; short digest + memory β†’ Worker (or build-time key)
Network None by default

HealthKit write: bodyMass, bodyMassIndex, bodyFatPercentage, leanBodyMass
HealthKit read: those plus fitness digest types for monitoring / Coach context

Muscle, bone, water %, visceral index, raw ohms: in-app only.

Shown once in onboarding and again under Settings β†’ Legal only. Never in Coach chat, Progress roast, or notification copy.


Protocol (scale)

Mi Scale 2 broadcasts; no pairing required for a live reading.

Bytes (0x181B service data) Meaning
0 Unit (bit0 lbs; else kg)
1 Flags: impedance / stabilized / weight removed
2-8 Timestamp
9-10 Impedance ohms (LE uint16)
11-12 Weight raw (LE uint16): Γ·200 β†’ kg

Composition numbers are reverse-engineered estimates, not clinical lab values. Not medical advice.

Quirks: name usually MIBFS; ignore unstabilized / weight-removed frames; impedance 0 or β‰₯ 3000 invalid; socks / wet feet β†’ weight-only.

Sources: ESPHome xiaomi_miscale, Theengs XMTZC05HM, openScale / MIBCS reverse-engineering.


Project layout

TheScale/
  TheScale.xcodeproj/
  Config/                 # TheScale.xcconfig, Secrets.example.xcconfig
  TheScale/               # SwiftUI app (BLE, HealthKit, Coach, FM, UI)
  TheScaleTests/
workers/grok-proxy/       # Cloudflare Worker (XAI_API_KEY secret)
scripts/validate_decode.py
docs/                     # Architecture, Coach/AI, Health/notifications

Docs

Doc Contents
docs/architecture.md Planes, data flow, layout
docs/coach-and-ai.md Grok Worker, streaming, FM hybrid, memory
docs/health-and-notifications.md HealthKit, Progress, alerts, FM polish
TheScale/docs/operations/app-store-metadata.md ASC listing copy, keywords, review notes
TheScale/docs/operations/asc-screenshots/README.md Promo mocks sized per iPhone slot

Version

Current: 1.0.97 (build 192).

Bump marketing + build together when shipping code:

scripts/bump_version.sh           # patch +1, build +1
scripts/bump_version.sh 1.1.0     # set marketing, build +1
scripts/bump_version.sh 1.1.0 120 # set both explicitly

Docs-only commits may leave the number unchanged.