Mirror

July 5, 2026 · View on GitHub

Mirror is a local-first, privacy-first iOS journaling app. All AI runs on-device — no cloud AI backend, no journal data ever leaves the device. No account or sign-in required.

Features

  • Write daily journal entries (typed or voice)
  • Browse entries grouped by month with full-text search
  • Calendar heatmap view of writing streaks
  • Daily Nudge — on-device AI reflection after 3+ entries (Core tier)
  • Ask Mirror — freeform questions answered by local AI (Core: 15/mo, Deep: unlimited)
  • Weekly Digest — AI summary of the week, delivered Sunday 7AM (Core tier)
  • Monthly Deep Report — long-form monthly reflection (Deep tier)
  • Mood Timeline — mood analytics, range selector, distribution chart (Deep tier)
  • Mood Alerts — notification if 3 consecutive entries show negative mood (Deep tier)
  • Home screen and lock screen widgets
  • iCloud backup via CloudKit (free, automatic, no account required)
  • Localized UI in 10 languages (see Localization)

Subscription Tiers

Everything is free right now. All Core/Deep-tier features below (Ask, Daily Nudge, Weekly Digest, Monthly Deep Report, Mood Timeline, Mood Alerts, widgets) are unlocked for every user while mirror grows — no subscription required. The tier structure and RevenueCat/IAP integration stay in the codebase so paid tiers can be re-enabled later; the free-for-everyone behavior is a single flag (SubscriptionService.allFeaturesFree).

FeatureFreeCore ($2.99/mo)Deep ($4.99/mo)
Unlimited entries, forever
Full history + search
iCloud backup
Daily Nudge
Ask (15×/month)
Ask (unlimited)
Weekly Digest
Widgets
Monthly Deep Report
Mood Timeline + analytics
Mood Alerts

Annual plans: Core $29.99/yr, Deep $49.99/yr (~16–17% savings, 7-day free trial on all plans) — pricing kept for when tiers are reactivated.

Subscriptions managed via RevenueCat + Apple IAP. No external account needed.

Localization

mirror's UI is localized into 10 languages: English (base), Spanish, Japanese, Simplified Chinese, German, French, Brazilian Portuguese, Korean, Italian, and Russian. The app follows the device's language setting automatically — no in-app language switcher.

  • Implemented via native String Catalogs (Localizable.xcstrings) — one for the main app target (mirror/Localizable.xcstrings), one for the widget extension (MirrorWidgetExtension/Localizable.xcstrings).
  • Covers onboarding, paywall, settings, entries, write, all insight screens (Nudge/Digest/Report/Mood Timeline), Ask, and all home-screen widgets.
  • Journal entry text, AI-generated insight content, and mood-vocabulary values are intentionally left untranslated — they're either the user's own words or persisted data whose raw form must stay stable.

Local AI

All AI features use Gemma 3 1B IT running on-device via llama.cpp (swift-llama-cpp).

  • Model file: gemma-3-1b-it-Q4_K_M.gguf (GGUF, Q4_K_M quantization)
  • Context window: 4096 tokens, GPU acceleration enabled
  • Mirror creates a fresh llama.cpp context per request and streams output
  • System prompts live in mirror/Core/Services/InsightService.swift

The model is not bundled in git. Deliver it as an on-demand resource or in-app download. See LOCAL_AI.md for full model lookup path and generation behavior.

Privacy

Journal entry text never leaves the device. No cloud AI, no server-side logging of journal content. The local model receives decrypted text only inside the app process.

Entries and insights are encrypted before SwiftData/CloudKit persistence. The content key lives in the local Keychain. Multi-device sync requires a recovery-key import flow (not yet implemented).

Architecture

iOS (SwiftUI + SwiftData)
├── Local storage: SwiftData (iOS 17+)
├── Cloud sync: CloudKit (automatic, private — no account needed beyond iCloud)
├── Subscriptions: RevenueCat → Apple IAP
└── AI: LocalLLMService (swift-llama-cpp) → Gemma 3 1B IT on-device

No backend server. No sign-in. No user data on any server.

Requirements

  • Xcode 17 or later
  • iOS 17.6 or later
  • Swift Package Manager (swift-llama-cpp, purchases-ios)

Project Structure

mirror/
├── App/                     # @main entry, SwiftData container + CloudKit config
├── Features/
│   ├── Write/               # WriteView, WriteViewModel, VoiceInputManager
│   ├── Entries/             # EntryListView (calendar heatmap), EntryDetailView
│   ├── Insights/            # InsightView, AskView, MonthlyReportView, MoodTimelineView
│   ├── Onboarding/          # OnboardingFlow (Day 0-7 staged), PaywallView
│   └── Settings/            # SettingsView, SubscriptionView
├── Core/
│   ├── Models/              # Entry, Insight, UserProfile (SwiftData @Model)
│   └── Services/            # InsightService, LocalLLMService, SearchService,
│                            # SubscriptionService, NotificationService,
│                            # InsightGenerationCoordinator, LLMGenerationQueue
└── MirrorWidgetExtension/   # WriteWidget + NudgeWidget

Local Development

open mirror.xcodeproj

For subscription testing, use mirror/Products.storekit in Xcode's StoreKit configuration.

Build from command line:

xcodebuild -scheme mirror -project mirror.xcodeproj \
  -destination 'generic/platform=iOS Simulator' build

License

Copyright (C) 2026 Pudari Lokesh

Mirror is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

This means: you can use, study, and modify the source freely — but any modified version you distribute or run as a service must also be released under AGPL-3.0. Commercial forks must open-source their entire modified codebase.

See LICENSE for full terms.