Privacy-first iOS productivity app. Zero-knowledge, end-to-end encrypted, offline-first. This directory began as the Phase 5 deliverable (project setup, data model, encryption layer, local storage, sync engine, notifications, search, background tasks) and now also contains the complete Phase 6 product UI (Dailies, Dial, Sequences, Search, Settings, onboarding, paywall — all 6.x tasks ✅ as of 2026-06-09).
Detailed design and encryption-architecture documents are maintained separately by Considus.
A public overview of the security model is in SECURITY.md.
CatchlightApp/
├── Package.swift # SwiftPM: CatchlightCore + coreverify
├── project.yml # XcodeGen spec for the iOS app (run: xcodegen generate)
├── Sources/
│ ├── CatchlightCore/ # PLATFORM-AGNOSTIC core — pure Swift + CryptoKit
│ │ ├── Model/ # Take, Sequence, reminders, attachments, seed Takes
│ │ ├── Serialization/ # ISO-8601 + platform-agnostic JSON codec
│ │ ├── Crypto/ # HKDF master key + key hierarchy, Take crypto
│ │ │ # (AES-256-GCM), manifest HMAC, X25519 handshake
│ │ │ # + SAS code, BIP-39, hard-failing RNG
│ │ ├── Sync/ # cloud blob, manifest v2 (tombstones), sync engine,
│ │ │ # conflicts, lock, folder protocol
│ │ └── Storage/ # TakeStore protocol + in-memory impl
│ └── coreverify/ # dependency-free runtime verifier (runs under CLT)
├── Tests/ # XCTest suites (Core + iOS + UI)
└── Catchlight/ # iOS APP TARGET — platform-specific layers
├── App/ # entry point, composition root, scene lifecycle
├── Security/ # Keychain (SE-wrapped master key), PIN (PBKDF2,
│ # persisted lockout), jailbreak, session
├── Database/ # EncryptedTakeStore — SQLite3, per-item AES-256-GCM
│ # sealed payload columns + NSFileProtection on the
│ # Database/ dir (no plaintext FTS; in-memory search)
├── Sync/ # Files-API cloud folder, BGTaskScheduler
├── Notifications/ # UNUserNotificationCenter reminders
├── UI/ # Phase 6 product UI (SwiftUI)
└── Resources/ # Info.plist, entitlements, wordlist, PrivacyInfo.xcprivacy
CatchlightCore contains everything that must run identically on every future
platform (Roadmap §4): the data model, the platform-agnostic JSON file format, and
the full crypto chain (CryptoKit HKDF + AES-256-GCM). Every platform-specific
dependency — Keychain, NSFileProtection, SQLite3, UNUserNotificationCenter,
BGTaskScheduler, the Files API — is injected through a protocol and implemented in
the Catchlight/ app target. This is what makes "platform-agnostic from day one" a
structural fact rather than a promise: the iOS app depends on the core, never the
reverse, and the future Web/Android/Mac clients re-implement only the thin app layer.
Write build products to a local directory outside the repo. This avoids sync churn and path-length/locking issues if your checkout lives on a cloud-synced folder:
BUILD_DIR="$HOME/CatchlightBuild"
swift build --scratch-path "$BUILD_DIR/spm"
swift test --scratch-path "$BUILD_DIR/spm"
xcodebuild … -derivedDataPath "$BUILD_DIR/DerivedData"swift build # builds CatchlightCore (pure Swift + CryptoKit)
swift run coreverify # runs the runtime verification harness — 52 checkscoreverify exists because XCTest is not bundled with the Command Line Tools. It
re-runs the same scenarios as the XCTest suite with a tiny assert harness so the
core can be proven green without full Xcode. Current status: 52/52 passing.
swift test # the canonical Tests/ suite, under a full Xcode toolchain
brew install xcodegen
xcodegen generate # produces Catchlight.xcodeproj from project.yml
open Catchlight.xcodeproj # set DEVELOPMENT_TEAM, then build/run on a device- Confirm database file protection on a real device — the
Database/directory carriesNSFileProtectionCompleteUntilFirstUserAuthentication(inherited by the db and its -wal/-shm sidecars).FileProtectionTestsverifies the attribute is set, but iOS enforces the protection class only on real hardware (it is observable but inert on the simulator). Verified 2026-06-06 on iPhone 17 Pro for the previous store; re-confirm after theEncryptedTakeStoremove. - Verify the Secure-Enclave master-key path on a real device — on SE hardware
the master key is ECIES-wrapped under a permanent SE P-256 key (format prefix
0x02); the simulator exercises only the raw 0x01 path (2026-06-10 redesign in
Catchlight/Security/Keychain.swift). - Set
DEVELOPMENT_TEAMinproject.ymlfor App Group / Keychain entitlements.
- Zero knowledge — no backend, no analytics, no off-device transmission anywhere.
kSecAttrSynchronizable: falseon every Keychain item (Keychain.swift,PINService.swift).- Encryption always on — never optional, never toggleable.
- Offline-first — full functionality with no network; sync is additive (local-only mode).
- Cloud folder holds only platform-agnostic JSON envelopes + one plaintext metadata file.