# Curio — iOS MVP Document

**Company:** Curio Cabinet Co. (`screenshot-memory`)
**Status:** pre-pilot, no App Store listing. This document scopes the first build.
**Date:** 2026-10-01

---

## 1. What Curio is

An iPhone app that turns the screenshots you already take into a private, searchable
memory — with every answer citing the actual screenshot it came from, and every
suggested action gated behind explicit user approval.

Job to be done: *"Find that thing I saw on my phone — and remember why I saved it."*

Explicit non-goals for v1: no silent access to other apps, no iMessage/email archives,
no ambient screen recording, no social features, no AI that acts without approval.

## 2. Audience

First segment (detailed in `gtm.md`): screenshot-heavy savers — travelers, shoppers,
planners — who file 30+ screenshots/month and currently lose them in the camera roll.
Behavioral pilot criterion, not demographic.

## 3. Screens & golden path

### Screens (7)

| Screen | Purpose |
|---|---|
| Drawer (home) | Grid of specimen cards; search bar; collections rail |
| Specimen detail | Image, extracted fields, OCR text, provenance, edit/delete |
| Results | Source-backed answer cards; confidence + provenance line |
| Action review | Proposed reminder/calendar card — Approve or Dismiss |
| Capture | Photos picker, Share-extension inbox, camera-scan hint |
| Collections | Named groups (e.g. "Japan trip"), auto + manual |
| Settings | Indexing scope, hosted-assist toggle, export, delete-all |

### Golden path

1. User screenshots a listing/menu/confirmation as usual (existing habit — zero
   behavior change).
2. Share sheet → "File to Curio" (Share Extension) **or** later Photos-picker import.
3. On-device Vision OCR + entity extraction runs immediately (~1s on A15+).
4. Card lands in Drawer, auto-tagged into a collection.
5. User searches "that ramen place in Kyoto" → ranked result cards, each with
   provenance strip (save date, confidence, and origin labeled as user-tagged,
   inferred-with-uncertainty, or unknown).
6. Curio proposes "Dinner at Menya Hikari — Fri 19:30?" → user taps **Approve**
   → EventKit writes a reminder/calendar entry. Nothing writes without Approve.

## 4. Feature acceptance criteria (MVP)

| # | Feature | Acceptance |
|---|---|---|
| F1 | Photos-picker import | User selects 1–50 screenshots via `PHPicker`; only picked items are read. Partial-library ("Limited") access fully supported. |
| F2 | Share extension | "File to Curio" appears in share sheet for images; saves image + any origin hint the OS provides (often none) into an App Group container without opening the main app. |
| F3 | Local OCR | Vision `VNRecognizeTextRequest` (accurate tier, on-device) extracts text ≤ ~2s/screenshot on iPhone 12-class hardware; Japanese + English recognized. |
| F4 | Search | Token + entity + date retrieval over local index returns results in < 200ms for a 5k-item drawer; every result shows its source thumbnail + save date + origin label. |
| F5 | Specimen detail | Shows image, full OCR text, extracted fields (dates, prices, codes, URLs, addresses); fields are editable (corrections feed ranking). |
| F6 | Suggested actions | When extraction yields a date+event, an approve/dismiss suggestion card appears. Approve → EventKit write. Rate-limited to ≤1 pending per specimen. |
| F7 | Collections | Auto-collections by inferred kind (travel/food/shopping/housing/events); manual collections; drag-to-move (context menu on iOS). |
| F8 | Delete | Deleting a specimen removes image, OCR text, index entries, and any pending suggestion — verified by inspection of App Group container + index. |
| F9 | Export | Whole drawer exports as a folder of images + JSON manifest via Share sheet / Files. |
| F10 | Honest settings | Toggles: hosted-assist (default OFF), background indexing (default ON, described accurately), analytics (default OFF). |

## 5. Architecture

**Stack:** SwiftUI + SwiftData, iOS 17+, Swift 6 strict concurrency.

```
┌─────────────┐   ┌──────────────┐   ┌─────────────┐
│ PhotosPicker │   │ Share ext.   │   │ Search/UI    │
└──────┬──────┘   └──────┬───────┘   └──────┬──────┘
       │                 │                  │
       ▼                 ▼                  ▼
┌─────────────────────────────────────────────────┐
│  Ingest pipeline (async)                         │
│  image → Vision OCR → entity parse → index      │
└──────┬──────────────────────────────┬───────────┘
       ▼                              ▼
┌─────────────┐              ┌────────────────────┐
│ App Group    │              │ SQLite FTS5 index  │
│ store (img)  │              │ (text + entities)  │
└─────────────┘              └────────────────────┘
       │                              │
       ▼                              ▼
┌─────────────────────────────────────────────────┐
│  Decision layer (typed, abstain-aware)           │
│  local rules → optional hosted assist (opt-in)  │
└─────────────────────────────────────────────────┘
       │
       ▼
 EventKit · UserNotifications (on Approve only)
```

**Apple frameworks:**
- `PhotosUI` — `PHPickerViewController` (no `PHPhotoLibrary` full access needed)
- `Vision` — `VNRecognizeTextRequest`, `VNDetectBarcodesRequest` (QR/confirmation codes)
- `NaturalLanguage` — `NLTagger` for entities, language detection
- `SQLite FTS5` (via GRDB or raw) — full-text + field index; SwiftData for object graph
- `EventKit` — reminders/calendar writes, only on explicit Approve
- `UserNotifications` — reminder delivery
- `BGTaskScheduler` (`BGProcessingTask`) — opportunistic catch-up indexing; real cadence is iOS's, not ours
- `CoreSpotlight` — optional: donate drawer entries to system Spotlight (off by default)
- `CryptoKit` — encrypt extraction cache keys if hosted assist enabled

**App Group** (`group.app.getcurio.drawer`) shares the store between main app and
share extension.

**Provenance honesty rule:** an imported screenshot's image + file timestamp are
reliable. Its originating app is *not* reliably knowable — PhotosPicker reveals
nothing, and share-sheet metadata is best-effort. Every specimen therefore stores
`origin: user-tagged | inferred | unknown`. Inference (icon/watermark/URL heuristics)
is displayed only with an "inferred — unverified" marker and can be corrected by
the user; unknown is shown plainly rather than guessed.

## 6. Permission UX (accurate by design)

| Permission | When asked | UX note |
|---|---|---|
| Photos | First import — via `PHPicker` (no permission prompt at all when using picker) | We never request "all photos"; picker = per-item consent |
| Notifications | When the user first approves a reminder action | Explained as "so approved reminders can notify you" |
| Calendar/Reminders (EventKit) | First Approve tap on a calendar/reminder card | iOS sheet; denial falls back to a copyable card |
| Background refresh | Settings toggle; described as "iOS chooses when indexing runs — usually while charging" | No silent claims |

iCloud sync is **planned, not in MVP** (see §10).

## 7. Local vs. hosted processing

**Local (default, required path):** OCR, entity extraction, indexing, retrieval,
rule-based suggestions. Everything in §4 works fully offline.

**Hosted assist (opt-in, off by default):** a typed decision layer that receives
*extracted text + structured fields* — never images — to rank answers and draft
suggestions when local confidence is low.

**TypeSafe AI Jev evaluation (decision layer, not image reader):**
- Role: consume a typed `SpecimenExtraction` (fields, entities, OCR text) and
  return a typed `Suggestion` or explicit `Abstain { reason }`.
- Why a typed layer: suggestions must be auditable — schema-checked output,
  confidence field, and a first-class abstention state map directly to our
  "show provenance + require approval" contract.
- Risks to record honestly: hosted text leaves the device (disclosed in Settings
  + Privacy Nutrition Label); abstention coverage must be measured on a labeled
  set before enabling by default; latency budget ≤1.5s or fall back to local rules.
- Verdict: evaluate in pilot behind a flag. Local rules remain the default path.

## 8. Monetization (hypotheses — to be validated)

- Free: 500 filed specimens, all core features.
- **Curio Plus (~$4.99/mo or $39/yr, planned):** unlimited drawer, hosted-assist
  ranking, iCloud sync, bulk export.
- No ads, no data sale — the entire pitch is "private memory." Pricing is a
  hypothesis to be tested in pilot interviews, not a commitment.

## 9. Build sequence (dependency-ordered)

Stages gate the next; no duration estimates — sequencing is the commitment.

1. **Foundation** — App skeleton, App Group, PhotosPicker + share-extension ingest,
   Vision OCR pipeline, SQLite FTS index. *Everything else depends on this.*
2. **Core loop** — Drawer grid, specimen detail, search + ranked results w/ provenance
   (incl. the origin-label rule), delete/export. *Shippable as an internal alpha.*
3. **Organization** — Auto + manual collections, field editing (feeds ranking).
4. **Actions** — Local-rules suggestion engine + EventKit approve/dismiss flow,
   notification permission UX. *Depends on extraction accuracy from stage 1.*
5. **Trust layer** — Settings (hosted-assist toggle, indexing controls, analytics
   opt-in), Jev typed-decision eval harness behind a flag, onboarding for the
   file → ask → approve loop.
6. **Pilot hardening** — Perf on 5k-item drawers, TestFlight distribution,
   App Review prep. *Gates external pilot invites.*

## 10. Key unresolved decisions

- **iCloud sync** — CloudKit private DB vs. export-only. Sync is the #1 expected
  ask and the top scope risk; decide after pilot week 2.
- **Hosted assist default** — stays opt-in unless abstention rate on labeled set
  < 5% AND pilot cohort accepts disclosure.
- **ReplayKit capture** — explicit, user-started sessions for "scrollback memory"
  are feasibility work, not MVP; only to be evaluated later with full
  disclosure (iOS requires an active recording banner — a feature, not a bug).
- **Mac companion** — a Catalyst/swiftui port for "type at your desk, search your
  pocket" is attractive but out of scope; reassess post-pilot.
- **Languages** — English + Japanese shipped in MVP (travel segment); adding
  German/French/Korean affects entity parsing more than OCR.

## 11. Existing vs. planned

**Exists today:** brand, landing page + working retrieval/approval demo (sample
data), this scope.

**Planned:** everything in §4–§9. Nothing on this list is shipped software yet.
