inkrecall
An iPadOS-only AI error-notebook - an AI grades your Apple Pencil handwriting step by step, analyzes weaknesses, generates similar problems, and schedules spaced-repetition (FSRS) review. A thin SwiftUI client on a thick FastAPI backend.
- SwiftUI (iPadOS)
- PencilKit
- FastAPI / Python
- Multimodal LLM
- FSRS (SRS)
Setup
- Problem
The core asset of exam study is "the problems you got wrong and why," but today it scatters across paper error-notebooks or never gets made at all - because building the notebook is the tedious part. Grading is binary too (right/wrong only), so you have to figure out "which step, and why" yourself, and you keep missing the same problem types without ever seeing the pattern.
- Context
For iPad + Apple Pencil users, the most natural study behavior is solving by hand. inkrecall takes that handwritten solution as first-class input and automates the whole arc - build the error-notebook, analyze, re-learn, review. The first cohort is certification and civil-service exam takers, who have clear willingness to pay. Everything runs "docs -> Figma -> code": the PRD, architecture, and feature IA are fixed first, and design and build follow them.
Build
- What I did
- Fixed the product spec as a single source first - a PRD (vision, target, problem, MVP scope, KPIs, revenue model, risks), a feature IA (user flows, 9 screens), and a technical architecture, with build and design following the docs
- Completed the Figma design system - 42 primitive + 22 semantic colors (light/dark), type-ramp/spacing/radius/shadow tokens, components (Button, Chip, VerdictBadge), and 9 screens
- Split into a thin client / thick backend - SwiftUI (iPadOS, PencilKit) does only capture, handwriting, display, and cache; grading, generation, SRS, and billing verification all live in FastAPI. The shared logic (InkrecallKit) is SwiftUI/Foundation-only so it's CI-verifiable with swift test, kept separate from the Xcode app target
- Got the core error loop working as scaffolding - register -> submit handwritten solution -> step-by-step grading (structured-output schema + Claude/mock) -> accumulate weakness tags -> generate similar problems -> FSRS review queue. With no API key it runs the whole loop locally on a mock grader
- Exam-agnostic data model - exams/subjects/types are master data, so adding a new exam is a data insert, not a code change
- Product decisions
- Handwriting as the core, not a side input - not keyboard entry or multiple-choice ticks but the handwritten solution process itself. It productizes the most natural behavior for iPad+Pencil users, and I wrote into the risk table from day one that handwriting-read accuracy is therefore the biggest risk
- Diagnosis, not grading - not "#3 is wrong" but "you flipped a sign on line 2, and that's the same slip 4 times in two weeks." So grading output is forced into a step-by-step structure (verdict, error type, evidence)
- Multi-exam in the architecture only, launch content focused on 1-2 exam groups - treating "multi-exam support" as a scope risk that could widen content endlessly, and bounding it to expand via data, not code
- A single monthly subscription, with the free-tier limit set only after measuring grading cost - per-grade/generation LLM cost is the core of unit economics, so subscription price and free limit get set on measured cost, not a guess
- Carry a finished cohort over to the next goal - after an exam ends, hand the error assets and SRS schedule over to the next exam or a higher certification, turning churn into retention
- QA considerations
- Grading output always conforms to the structured schema (per-step verdict, error type, evidence) - evidence-free verdicts are caught at the parsing layer
- When handwriting-read confidence (
transcription_confidence) is low, the attempt goes to a user-confirm state instead of grading straight away - The mis-grade report -> prompt/eval-set improvement feedback loop actually closes
- With no API key, the core loop (register -> solve -> grade -> weakness -> similar -> review) runs end to end on a mock grader
- Unit tests pin InkrecallKit's DTO decoding and models so backend-schema changes get caught as regressions
Outcome
- Metrics
- Spec docs (PRD, feature IA, architecture) + Figma design (9 screens, design system) complete
- Backend (FastAPI) and client (SwiftUI) scaffolding complete - the core error loop runs locally on a mock grader
- Not shipped - production LLM integration, real device, and store submission are planned
- North Star: weekly graded solutions. Activation, conversion, and retention targets are hypotheses (not measured yet)
Process (planning → build)
The same template from problem and hypothesis through scope, spec (SSOT), build, the QA gate, and release - how this was planned and driven.
Process (planning → build)
Problem & hypothesis
Started from the problem that a test-taker's core asset - the wrong problems and why - scatters or never gets made because building an error-notebook is the tedious part. The hypothesis: "just solve by hand and the app does the rest," narrowed to iPadOS-only with the handwritten solution as first-class input.
Skills · Problem framing · hypothesis
Scope & priority
Defined the MVP as "complete the core error loop on top of a multi-exam architecture." Cut iPhone/Mac/web, social/ranking, B2B dashboards, full offline, and a marketplace as explicit non-goals, and focused launch content on 1-2 exam groups (certification, civil-service) with clear willingness to pay.
Skills · Scoping · prioritization
Spec-first (SSOT)
Kept the PRD, feature IA, and architecture as the single source for both build and Figma, fixing a "docs -> Figma -> code" order as a rule. The grading-output schema, data model (ERD), and API were all fixed in the docs first.
Skills · Spec · documentation
Build & iteration
Split into a thin SwiftUI client (capture, PencilKit handwriting, display, cache) and a thick FastAPI backend (grading orchestration, generation, SRS, billing verification). Pulled the shared logic into InkrecallKit (SwiftUI/Foundation only) so it verifies with swift test without Xcode, leaving only the PencilKit-dependent parts in the app target.
Skills · Execution · delivery
Verification (QA gate)
Ran the core error loop end-to-end locally on a mock grader to verify the scaffolding (register -> solve -> grade -> weakness -> similar -> review). Unit-tested InkrecallKit's DTO decoding and models, and forced grading output into a structured schema to create a place to catch parsing and regressions.
Skills · Quality · risk
Release
Not shipped. Next is handwriting-image upload and real LLM grading, real Sign in with Apple and StoreKit 2, and the remaining screens. The order is to validate grading accuracy and willingness to pay before production.
Skills · Release
- Tech stack
- SwiftUI (iPadOS 17+)
- PencilKit / SwiftData
- StoreKit 2 · Sign in with Apple
- FastAPI + Pydantic v2
- SQLAlchemy 2.x / Alembic
- Celery/RQ + Redis
- PostgreSQL
- Multimodal LLM (Claude tiering)
- FSRS
- Docker