A standalone Apple Watch hydration tracker - no iPhone companion app required. Built for Kiro BuildFest 2026 Singapore.
I keep forgetting to drink water. Not because I don't care - because nothing around me ever nudges me at the right moment. My phone sits in my pocket or on a desk, easy to ignore. But my watch is always on my wrist, and it already knows things about my day: what time it is, how far behind I am on my goal, whether I've had anything to drink in the last few hours. It has everything it needs to know when to say something - it just never did.
Most "watch" hydration apps don't actually fix this - they're a phone app with a tiny watch-face widget bolted on. Logging a drink still means finding your phone, and reminders still depend on it being nearby. WaterTracker puts the entire loop - logging, goals, reminders, voice control, even an on-wrist motion detector - directly on the watch, with no iPhone companion app at all. And the reminders aren't on a dumb fixed timer: they're pace-aware, computed from how far behind your goal you actually are right now, so the nudge shows up when it matters, not on a schedule that ignores you.
- Home: a continuously animated liquid-fill visualization of today's water intake vs. your goal, plus a pace status line ("320 mL behind pace" / "On track"), and a small animated water-drop character whose fill level and mood (happy/worried/celebrating) reflect your progress - glanceable, no interaction needed.
- Log (swipe left): dial an amount with the Digital Crown (0-1000 mL, 25 mL steps), pick a beverage type (Water, Coffee, Tea, Sports Drink, Alcohol), tap Log - the app automatically returns you to Home so you see your progress rise immediately.
- History (swipe left again): every drink logged today, timestamped with its beverage icon, most recent first - swipe to delete, or tap to edit the amount/beverage type (both correctly adjust your running total by the entry's net, multiplier-applied contribution, not just its raw amount).
- Settings (swipe left once more): manually set your daily goal with the Digital Crown, or revert to the automatic HealthKit-derived goal. Shows exactly where your current goal came from (a real HealthKit average, the default fallback, or your manual override) so a denied/unavailable HealthKit state reads as intentional, not broken.
- Sip Detection (swipe left once more): an experimental, opt-in CoreMotion wrist-gesture classifier that suggests logging a sip after detecting a raise-dwell-return motion - always requires user confirmation, never auto-logs.
- Goal reached: a one-shot sparkle animation + success haptic when you cross your daily goal.
- Complication: a WidgetKit complication on your watch face showing live progress, with an ambient urgency signal (tint + icon swap) when you're behind pace, and a simplified static appearance on Always-On Display (frozen animation, flat contrast-safe color) to stay legible and battery-friendly. Tap to open the app.
- Reminders: pace-aware local notifications, pre-scheduled for the rest of the day so the chain survives even if you never reopen the app, with actionable buttons (Log 250 mL / Snooze 30 min / Not now) so you can respond without opening the app.
- Voice: "Hey Siri, log water in WaterTracker" or "check hydration progress in WaterTracker" - via native App Intents, no phone required.
- Net hydration: beverage types apply an evidence-based hydration multiplier (water/coffee/tea/sports drinks all count fully - the old "caffeine dehydrates you" claim is outdated for moderate intake; alcohol counts at a conservative 0.5x given its dose-dependent diuretic effect). History shows what you actually drank; your daily total reflects net hydration.
- Accessible: full VoiceOver labels, Dynamic Type support, and a Reduce Motion mode that freezes animation and simplifies the visuals.
Requires Xcode 15+ and XcodeGen (brew install xcodegen).
xcodegen generate
xcodebuild -project WaterTracker.xcodeproj -scheme "WaterTracker Watch App" \
-destination "platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)" buildOpen WaterTracker.xcodeproj in Xcode and run the WaterTracker Watch App scheme on a watchOS Simulator - no iPhone Simulator pairing needed, since this is a WKWatchOnly app.
.xcodeproj is intentionally not committed - it's fully generated from project.yml by XcodeGen, which keeps the repo diff-friendly for an agent-driven workflow.
xcodebuild -project WaterTracker.xcodeproj -scheme "WaterTracker Watch App" \
-destination "platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)" test171 unit tests covering the data/persistence layer, HealthKit goal-approximation math, pace-aware reminder scheduling, midnight-reset logic, manual goal overrides, the goal-crossing celebration state, the sip-gesture classifier's state machine (valid sips, and rejection of eating/waving/walking/brushing-teeth false positives via synthetic sensor sequences), beverage-type hydration multipliers, goal-source tracking, and History edit/delete accounting - all pure/side-effect-free logic extracted specifically to be testable in an unhosted XCTest bundle (WidgetKit, UserNotifications, and CoreMotion calls crash outside a real app host, so framework plumbing is kept thin and untested while the actual decision logic is fully covered).
Shared/ # Used by all 3 targets (app, widget extension, tests)
WatchAppCore/ # Used by the app + tests, NOT the widget extension
WaterTracker Watch App/ # App-only UI (SwiftUI views, app entry point)
WaterTrackerComplication/ # WidgetKit complication extension
WaterTrackerTests/ # XCTest unit tests
.kiro/ # Spec-driven development artifacts (see below)
Shared/ and WatchAppCore/ exist because of a real XcodeGen bug discovered mid-build: sharing a source file across targets with mismatched reference styles (a natural directory scan in one target, an explicit path in another) silently corrupts the build path. The fix - every target references shared code the same way, as a plain directory sources: entry - is documented in .kiro/agents/watertracker-engineer.json so it's never rediscovered the hard way again.
This project was built with Kiro's spec-driven workflow, orchestrated end-to-end via kiro-cli, with independent code review passes at key checkpoints:
.kiro/specs/watertracker-watch-app/-requirements.md(EARS-format requirements),design.md(technical design),tasks.md(implementation checklist) - kept in sync with actual behavior through every product pivot, not just the original plan..kiro/steering/- persistent product/tech/structure context loaded into every session..kiro/agents/watertracker-engineer.json- a custom project-local Kiro agent with hard-won conventions and gotchas baked into its system prompt, set as the workspace default. It also wires anagentSpawnhook that runsgit log/git statusautomatically at session start, so every invocation opens already knowing the real repo state instead of guessing.- Two features (pace-aware reminders, experimental sip detection) were built by two
kiro-cliagents running concurrently with disjoint file ownership, to avoid the concurrent-edit collision risk this project hit once already - then manually integrated and re-verified with a full test run. - Later features (the sip-detection classifier upgrade, Siri/App Intents voice logging, beverage-type net hydration) followed a strict spec-first loop: requirements and design were written in
.kiro/specs/before any implementation code, then an independent code review pass ran against the actual diff, catching real bugs - e.g. the sip classifier's stillness check would have falsely rejected nearly every genuine sip, since lifting the wrist to drink naturally produces rotation the naive check misread as "not still."
See DEVPOST_WRITEUP.md for the full "how we used Kiro" write-up.