Skip to content

HarloPulse App Intents: Siri sync, status snippet, honest type toggles (WWDC26 P0)#13

Merged
JosephOIbrahim merged 2 commits into
masterfrom
feature/pulse-app-intents
Jun 10, 2026
Merged

HarloPulse App Intents: Siri sync, status snippet, honest type toggles (WWDC26 P0)#13
JosephOIbrahim merged 2 commits into
masterfrom
feature/pulse-app-intents

Conversation

@JosephOIbrahim

Copy link
Copy Markdown
Owner

What

The buildable-today subset of the WWDC26 advanced App Intents session, applied to HarloPulse — three intents + entity + shortcuts, compiler-verified end-to-end on the iOS 26.5 SDK (zero errors/warnings, App Intents metadata extraction confirmed running).

Intent Session patterns exercised
SyncPulseIntent — "Sync HarloPulse" IntentDialog(full:supporting:) · payload-free donation via IntentDonationManager (Siri learns sync cadence; nothing biometric in the donation)
PulseStatusIntent ShowsSnippetView (SwiftUI status card in Siri results) · ReturnsValue<PulseStatusEntity> · enhanced DisplayRepresentation
TogglePulseTypeIntent $dataType.requestValue("Which data type?") clarification · ForegroundContinuableIntent so first-time enables run the HealthKit sheet honestly in-foreground

Two real catches while building

  1. Metadata extraction was silently skipping — autolinked AppIntents isn't enough; appintentsmetadataprocessor needs the explicit framework dependency or Siri/Shortcuts never see the intents. Fixed in project.yml.
  2. xcodegen's info: block regenerates (overwrites) the named plist — it destroyed the HealthKit usage strings once. Removed; the checked-in Info.plist + INFOPLIST_FILE is now genuinely the source of truth (with a warning comment).

Architecture note

PulseModel → shared singleton (intents run outside the view tree; a second HealthReader would double-register observers), with persisted status mirrors + an awaitable syncNow() over the existing anchor-commit-on-success path. Push semantics unchanged.

Deliberately absent (privacy gates)

No CSSearchableIndex, no IntentValueQuery over memories, no donation payloads. Rationale + the full 12-pattern matrix: companion PR docs/frontier/app-intents-adoption-plan.md.

Test on device

Build & run, then: "Hey Siri, Sync HarloPulse" · "Hey Siri, HarloPulse status" · Shortcuts app → HarloPulse actions.

🤖 Generated with Claude Code

…Pulse (WWDC26 P0)

Applies the buildable subset of "Explore advanced App Intents features
for Siri and Apple Intelligence" to HarloPulse. All compiler-verified
against the iOS 26.5 SDK: zero errors, zero warnings, and
appintentsmetadataprocessor EXTRACTS the metadata (was silently
skipping until AppIntents.framework became an explicit dependency —
without that, Siri/Shortcuts never discover the intents).

Session patterns implemented:
- IntentDialog(full:supporting:) on every intent — voice-first vs
  glance responses (SyncPulseIntent: "Synced 3 data types... Mac said
  accepted=12" / "Synced")
- $param.requestValue() clarification — TogglePulseTypeIntent asks
  "Which data type?" instead of failing when unspecified
- ForegroundContinuableIntent — first-time enable of a type routes
  through needsToContinueInForegroundError so the HealthKit consent
  sheet happens honestly in the foreground app, never silently skipped
- Enhanced DisplayRepresentation — PulseStatusEntity with
  title/subtitle/sf-symbol
- ShowsSnippetView — PulseStatusSnippetView renders pairing state,
  enabled-type count, last push/result inside Siri results
- IntentDonationManager — successful manual syncs are donated
  (payload-free: the intent carries nothing biometric) so Siri learns
  the user's sync cadence
- AppShortcutsProvider — "Sync HarloPulse" / "HarloPulse status"

Architecture: PulseModel became a shared singleton (intents run
outside the view hierarchy; a second HealthReader would have
double-registered HKObserverQuery callbacks), gained persisted
lastPush/lastResult mirrors (cold background launches can report
honestly) and an awaitable syncNow() that resolves when every enabled
type's fetch+push cycle completes (DispatchGroup over the existing
anchor-commit-on-success path — unchanged semantics).

xcodegen footgun fixed: an `info:` block makes xcodegen REGENERATE the
named plist on every generate — it silently destroyed the HealthKit
usage strings once. The block is gone; INFOPLIST_FILE points at the
checked-in plist, which now genuinely is the source of truth (comment
in project.yml so nobody re-adds it).

Not in this PR by design (privacy gates per the adoption plan):
no CSSearchableIndex of anything, no IntentValueQuery over Harlo
memories, no assistant-schema domains (none exists for coaching;
plain AppIntents get Siri/Shortcuts/Spotlight regardless).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@JosephOIbrahim, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 24 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 79b06c42-6090-40ba-9f77-4a146449c5dd

📥 Commits

Reviewing files that changed from the base of the PR and between 9c0d48b and 5af9fc5.

📒 Files selected for processing (4)
  • ios/HarloPulse/Sources/HarloPulse/HarloPulseApp.swift
  • ios/HarloPulse/Sources/HarloPulse/HealthReader.swift
  • ios/HarloPulse/Sources/HarloPulse/PulseIntents.swift
  • ios/HarloPulse/project.yml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/pulse-app-intents

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…st path, stale-result guard

Independent pre-merge review found one real blocker: Siri re-enabling
an already-on type (or the foreground-continuation racing the
@AppStorage onChange) overwrote the activeQueries dict entry, orphaning
a still-executing HKObserverQuery that store.stop() could never reach —
duplicate pushes, and after a later toggle-off the orphan kept firing
with a deleted anchor, re-pushing FULL history for a disabled type
(D65 violation). installObserver now stops any existing query before
replacing (fixes every caller path), and the toggle intent gains an
"already on/off" fast path. Also: syncNow no longer reports yesterday's
Mac ack when an empty-delta run pushed nothing ("no new samples since
last push").

Verified: zero diagnostics, BUILD SUCCEEDED, metadata extraction runs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@JosephOIbrahim JosephOIbrahim merged commit 1ab2ba8 into master Jun 10, 2026
2 of 3 checks passed
@JosephOIbrahim JosephOIbrahim deleted the feature/pulse-app-intents branch June 10, 2026 16:22
JosephOIbrahim added a commit that referenced this pull request Jun 10, 2026
…lary, privacy gates, P0-P3

Decision surface for the WWDC26 App Intents session: per-pattern
verdicts (ADOPT-NOW / ADOPT-NEXT / GATED / REJECT with rationale —
notably: NO CSSearchableIndex of traces, IntentValueQuery over
memories gated behind architect+counsel, OwnershipProvidingEntity
rejected by design since cognitive state is never shared), the shared
intent vocabulary across Pulse/HarloGlance/OTTO, the py2app-can't-host-
App-Intents constraint and the HarloGlance menu-bar answer, binding
privacy gates, and the phased P0-P3 roadmap. P0 ships in PR #13.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
JosephOIbrahim added a commit that referenced this pull request Jun 10, 2026
…lary, privacy gates, P0-P3

Decision surface for the WWDC26 App Intents session: per-pattern
verdicts (ADOPT-NOW / ADOPT-NEXT / GATED / REJECT with rationale —
notably: NO CSSearchableIndex of traces, IntentValueQuery over
memories gated behind architect+counsel, OwnershipProvidingEntity
rejected by design since cognitive state is never shared), the shared
intent vocabulary across Pulse/HarloGlance/OTTO, the py2app-can't-host-
App-Intents constraint and the HarloGlance menu-bar answer, binding
privacy gates, and the phased P0-P3 roadmap. P0 ships in PR #13.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant