Sheaf iOS App Privacy Policy
Effective: 2026-08-02.
This policy covers the Sheaf iOS app binary published by Lupine Systems LLC on the App Store. It describes what the app does on your device and what third parties the app interacts with as part of running.
It does not cover:
- The Sheaf instance you connect to. That's a separate piece of software run by an operator (which may or may not be Lupine Systems). When you sign in, the app surfaces that instance's privacy policy and terms inside the login screen and in Settings → Server. You should read your chosen instance's policy before signing up; that's where most of the data you enter lives.
- The marketing site at
sheaf.sh: see /privacy/. - Lupine Systems' own hosted instances (
test.sheaf.sh,app.sheaf.sh): see /service/privacy/. The mobile app is one of the ways you can connect to those instances, in which case both this policy and the hosted-service policy apply. - The Android app: see /mobile/android-privacy/ (separate, because the third-party processors involved differ).
1. Data controller
For everything in this policy, the data controller is Lupine Systems LLC. See /legal/ for full company identification and contact details.
For data sent to a Sheaf instance via the app, the controller is the operator of that instance (which, for the hosted tier, happens to be Lupine Systems too).
2. What the app stores on your device
The app keeps the following on the device's local storage. None of it leaves the device unless you explicitly send it to your chosen Sheaf instance.
| Data | Purpose | Where |
|---|---|---|
| API base URL of your chosen instance | Knowing where to send requests | App Group container (group.systems.lupine.sheaf) |
| Access token + refresh token | Keeping you signed in | iOS Keychain (kSecClassGenericPassword) |
| Watch session tokens | Keeping a paired Apple Watch signed in | iOS Keychain |
| APNs device token | Letting your instance address notifications to this device | iOS Keychain |
| Install identifier | Distinguishing this install when registering for push | iOS Keychain |
| Cloudflare Access service credentials, if you use them | Reaching an instance behind Cloudflare Access | iOS Keychain |
| UI preferences (theme mode, notification toggle, app-lock toggle) | UX state | App Group container |
| Cached members, groups, journals, fronts | Faster screen loads, offline read | App Group container (in-process) |
| Avatar / image cache | Faster image loads | App's Library/Caches |
Most of the Keychain items above are stored as synchronizable, so they participate in iCloud Keychain if you have it enabled. See §4.1 for what that means and how to opt out.
The App Group container (group.systems.lupine.sheaf) is shared between the main app, the iOS home-screen widget, the watchOS app, and the watchOS complication, so that the widget and complication can render fronting state without launching the main app. It's still entirely on your device — App Groups are a local IPC mechanism, not a sync mechanism.
Tokens and cached content are wiped on sign-out and on app uninstall.
3. Data the app sends to your chosen Sheaf instance
When you use the app, it makes HTTPS requests to whatever Sheaf instance you've configured (https://...). The contents of those requests are whatever you do in-app: members you create, fronting switches you log, journals you write, files you upload, your account details, etc.
The processing of that data is governed by the operator of your chosen instance, under their own privacy policy. The Sheaf protocol does not bake any analytics or telemetry into client-server traffic; only data you create is transmitted.
If you run a self-hosted instance (your own or someone else's), the operator of that instance is the controller of that data — not Lupine Systems.
4. Third-party services the app talks to
The iOS app interacts with the following third parties as part of running on iOS. These are separate from any third parties used by your chosen Sheaf instance (which will be listed in that instance's own privacy policy).
4.1 Apple (platform services)
The app is distributed through the App Store and uses standard Apple platform frameworks. As a result:
- App Store distribution. Apple records downloads, installs, and update events per its own privacy policy.
- No CloudKit, and no iCloud entitlement. The app does not declare an iCloud entitlement and does not use CloudKit. Your members, fronting history, journals and other content are never written to iCloud by this app; the cached copies described in §2 stay in the on-device App Group container.
- iCloud Keychain, for the Keychain items in §2. One exception to the above, and worth stating plainly: most of the Keychain items the app stores are saved as synchronizable, which means that if you have iCloud Keychain switched on, iOS syncs them across your Apple devices as it does any other synchronizable Keychain item. That covers your session and watch tokens, your instance URL, the push device token, the install identifier, and any Cloudflare Access service credentials you have configured. Tokens minted for a single device session are the exception and are explicitly marked non-synchronizable. Apple end-to-end encrypts iCloud Keychain and cannot read the contents, but the encrypted items do leave the device. If you would rather none of it syncs, turn off iCloud Keychain in iOS Settings.
- WatchConnectivity (if the Apple Watch companion app is installed and paired). Used to sync app credentials and small UI-state messages between the iPhone and the paired Apple Watch. WatchConnectivity is a device-to-device IPC channel between paired Apple devices; messages do not transit Apple's cloud servers as part of the WatchConnectivity transport. Apple Push and other Apple services are not involved unless one of those features is independently used.
- Siri / App Intents. The app exposes App Intents for fronting actions (
Switch front to,Add member to front,Get current front,Remove member from front,Purge front). When you invoke one of these via Siri, the Shortcuts app, or a Focus filter, Apple's voice-recognition and intent-resolution stack is involved per Apple's Siri privacy practices. The intent payload — the names of members you want to add or remove from the front — is processed locally by the app and forwarded to your chosen Sheaf instance over the same HTTPS channel as anything else you do in-app. If you never invoke a Siri shortcut, this surface is not used. - Universal-app / extension framework usage. The app's iOS home-screen widget, watchOS complication, and watchOS app run in their own sandboxed extensions, sharing data with the main app via the App Group container described in §2.
4.2 Push notifications (Apple)
The app uses Apple Push Notification service (APNs) to deliver push notifications, and declares the aps-environment entitlement.
Push is opt-in. Nothing happens until you enable notifications, at which point iOS shows its standard permission prompt (alert, sound, badge). If you grant it, the app registers with APNs, receives a device-specific token, and sends that token to your chosen Sheaf instance so the instance can address notifications to this device. The token is stored in the Keychain (see §2).
Apple sees notification metadata as part of delivering it: the target device token, timing, and the payload the instance sends. Apple's handling of that is covered by their privacy policy. How much detail ends up in a notification payload is a setting on the instance side, per notification channel, so if you would rather Apple never see member names in a payload, use the lower payload-sensitivity setting when you configure the channel.
You can revoke notification permission at any time in iOS Settings. To also remove the token from the instance, remove the device from the app's notification settings, or sign out (which clears it).
4.3 Build verification
Each iOS release is signed by Apple's standard signing process for App Store distribution; Apple controls the install flow and the user does not need to verify a separate signature out-of-band.
(For comparison, the Sheaf Android app additionally publishes Sigstore keyless-OIDC signatures alongside its sideloadable APKs, since GitHub-distributed APKs don't have an equivalent platform-level guarantee of build provenance. iOS App Store distribution makes that an Apple-mediated trust statement instead.)
This does not involve user data.
5. Permissions the app requests
The app uses Apple's per-purpose permission model. At first launch and on first use of relevant features, iOS prompts for:
| Permission | Why |
|---|---|
| Face ID / Touch ID / device passcode | For the optional app-lock feature |
| Notifications (alert, sound, badge) | Only if you turn on push notifications, per §4.2 |
| Siri / App Intents authorization | Only on first invocation of a Sheaf shortcut, per Apple's standard prompt |
Photo library access is not requested. Avatar and banner upload uses SwiftUI's PhotosPicker, which runs out-of-process in Apple's own picker UI and hands the app only the single image you chose. The app never gets access to your photo library, which is why there is no NSPhotoLibraryUsageDescription and no permission prompt.
The app does not request, and never uses:
- Location
- Contacts
- Calendar / Reminders
- Microphone
- Camera
- Bluetooth (beyond what WatchConnectivity uses transparently for paired-watch sync)
- IDFA / advertising tracking. The app does not call
requestTrackingAuthorization()andNSUserTrackingUsageDescriptionis not declared.
6. What the app does not do
- No analytics. No Firebase Analytics, no Mixpanel, no Sentry, no third-party SDK collecting in-app events.
- No crash reporting. No Crashlytics, no Sentry, no Bugsnag. iOS may submit crash reports to Apple at the OS level if you have "Share With App Developers" enabled in Settings → Privacy & Security → Analytics & Improvements; that's an Apple-controlled flow that ships aggregated crash traces to us via App Store Connect, with no per-user identifiers.
- No advertising or ad-tech. No ad SDKs, no IDFA usage.
- No fingerprinting.
- No telemetry of any kind that isn't explicitly under your control.
- No background data collection. The app does register for iOS background refresh, so it can occasionally sync fronting state while backgrounded and keep the widget and complication current, and it makes network requests when handling a push. Those requests carry the same data as any other request you make, to your chosen instance and nowhere else. What the app does not do is collect or transmit anything about you in the background: no telemetry, no analytics, no beacons.
7. App Store Privacy "Nutrition Labels"
The App Store requires us to declare data practices in a structured form. The disclosure there mirrors this policy and should declare:
- Data Linked to You: none, by us. (Apple's App Store independently collects standard install/usage data per their own policy.)
- Data Used to Track You: none.
- Data Not Linked to You: none, by us.
When you log in to a Sheaf instance, that instance will be processing data about you, and the App Store labels do not (and cannot) describe that — they describe what the binary does. Your chosen instance's privacy policy is what covers server-side processing.
The binary itself still collects nothing for us. The one thing worth naming explicitly is the APNs device token and install identifier described in §4.2: those are generated on your device and sent to your chosen instance so it can address notifications to you. Where that instance is one of ours, the hosted-service policy at /service/privacy/ covers what we do with them.
8. Children
The Sheaf hosted service is not intended for users under 16. The app itself doesn't enforce that — your chosen instance does — but in practice the app is most useful when used with an instance, so the same age guidance applies. See the hosted Terms.
9. Your rights
For data the app stores locally on your device, you control it directly: uninstalling the app removes everything; deleting the app via iOS removes its sandbox.
For data sent to your chosen Sheaf instance, your rights (access, rectification, erasure, etc. under GDPR / UK GDPR / CCPA / equivalents) are exercised against the operator of that instance, per their privacy policy. If your chosen instance is one of Lupine Systems' hosted instances, see /service/privacy/ §7 — including the universal-policy extension that means we honour those rights for anyone, regardless of jurisdiction.
10. Security
- Tokens are stored in the iOS Keychain as
kSecClassGenericPassworditems, scoped to the app's keychain access group. The Keychain is encrypted at rest by iOS using the device's hardware-backed key. - Those items use the
kSecAttrAccessibleAfterFirstUnlockprotection class. In plain terms: after you unlock the device once following a reboot, the app can read them again even while the device is subsequently locked. This is deliberate, because background refreshes and pushes need to be able to persist a rotated token while the phone is in your pocket, and the stricter class made those writes fail silently and strand a stale token. The trade-off is that the items are not protected by the lock screen once the device has been unlocked once since boot. They remain encrypted at rest whenever the device is off or has not yet been unlocked. - Most Keychain items are synchronizable and therefore participate in iCloud Keychain if you have it enabled, as described in §4.1.
- All network traffic is TLS-encrypted via
URLSession. App Transport Security is enabled and the app does not whitelist plaintext HTTP for arbitrary domains. - The optional app-lock feature gates access to the running app behind Face ID, Touch ID, or device-passcode auth (via
LocalAuthentication). - App releases are signed by Apple as part of App Store distribution; signature verification happens in the install flow controlled by iOS.
Responsible disclosure of security issues: [email protected], GitHub Security Advisories, or the project's SECURITY.md.
11. Changes
When this policy changes we'll update the Effective date at the top.
For material changes (a new permission requested, a new third party involved, new data collected or sent off the device) we'll also call it out in the App Store release notes for the version that makes the change, and flag it in the app's About section so it's visible to someone who installed before the revision. This policy covers the app binary rather than any particular instance, so it reaches you through the app itself rather than through any instance's mailing list.
If you use one of the Lupine-hosted instances, changes to that service are notified separately, per Terms §14.
12. Contact
Privacy questions, data requests, or complaints: [email protected]. See /legal/ for company details.