Ctrl+C for real life.
A cross-platform, offline-first capture app. One gesture captures anything from the physical world — photos with OCR, audio with speech-to-text, or plain text. Everything is stored locally and searchable forever. Pro users get cloud sync.
- Flutter (Dart) — Android, iOS, macOS, Windows, Web
- Drift (SQLite) — Local-first storage with FTS5 full-text search
- Supabase — Auth, Postgres, Storage, Edge Functions
- PowerSync — Offline-to-cloud sync for Pro users
- Google ML Kit — On-device OCR
- WhisperKit — On-device speech-to-text
- BLoC/Cubit — State management (sealed class states, Dart 3 patterns)
- RevenueCat — Subscriptions (iOS + Android)
UI (Screens/Widgets)
↓ BlocBuilder / BlocListener
Cubits (Business Logic)
↓ calls repository methods
Repositories (Data Access Layer)
↓ calls database methods
Drift Database (SQLite + FTS5)
- RepositoryProvider at app root — all routes read repo from context
- Sealed class states with exhaustive Dart 3 switch expressions
- GoRouter with async onboarding redirect
- Capture — Tap the button or press the hotkey. Camera snaps + OCR, or audio records + transcribes, or just type.
- Store — Saves to local SQLite instantly. No network needed.
- Search — FTS5 full-text search finds anything you've ever captured in milliseconds.
No folders. No tags. No notebooks. Just capture, store, search.
- Flutter SDK 3.41+
- Dart 3.2+
git clone https://github.com/SamDev1303/cltc.git
cd cltc
flutter pub get
dart run build_runner build --delete-conflicting-outputsTests run at three levels — local verification, then dual-CLI review after every wave.
flutter analyze # Zero issues required
dart format --set-exit-if-changed . # Consistent formatting
flutter test # All tests must passCodex reviews code for bugs, unused imports, anti-patterns, missing error handling, and simpler alternatives.
codex exec --json --model gpt-5.3-codex --skip-git-repo-check \
--ephemeral -s read-only -C . - <<'PROMPT'
Review ALL Dart files in lib/ and test/. Run flutter analyze + flutter test.
For each issue: file:line, category (bug/unused/simplification/anti-pattern/
missing-error-handling), severity (critical/medium/low), fix.
Sort by severity.
PROMPTGemini tests the app as a real user would — walking through every flow, finding edge cases, navigation dead-ends, and missing error states.
gemini -p "You are a human UX tester reviewing the CLT/C app.
Read ALL files in lib/. Walk through every user flow:
first launch → onboarding → capture text → capture photo + OCR →
audio recording (back press, cancel, stop & save) →
search → clip detail (copy, delete) → settings (sync).
Also test: PopScope on audio screen, delete confirmation dialog,
platform abstraction fallbacks (web with no camera/OCR/STT),
cross-platform readiness. For each: what breaks? Edge cases?
Report: FINDING [n]: [severity] — [description] — [fix]" -yApply fixes from both reviews, then re-run Step 1. Commit as a separate review-fix commit.
Rule: Steps 2 and 3 always run together (parallel) — never one without the other.
| Module | Tests | Status |
|---|---|---|
| Drift Database (insert, FTS5 search, soft delete) | 3 | Passing |
| CaptureCubit (save text, empty guard, DB verify) | 3 | Passing |
| SearchCubit (FTS5 match, no results, empty query, clear) | 4 | Passing |
| AudioCaptureCubit (start, stop, cancel, timeout) | — | Planned |
| TimelineCubit | — | Planned |
| SyncService | — | Planned |
| Widget tests (PopScope, delete dialog, onboarding) | — | Planned |
| Flow | Steps | What to verify |
|---|---|---|
| Audio safety | Start recording → tap back | PopScope intercepts, shows 3-option dialog |
| Audio cancel | Start recording → tap Cancel | Recording discarded, returns to idle |
| Audio save | Start recording → Stop & Save | Clip saved with transcript, navigates home |
| Delete capture | Open clip → tap delete → confirm | Soft-deleted, returns to timeline, clip gone |
| Camera OCR | Open camera → take photo → save | OCR runs via platform service, text extracted |
| Search | Type query → results appear | Debounced (300ms), FTS5 match, tap opens detail |
| Onboarding | First launch → see onboarding → dismiss | SharedPreferences flag set, never shows again |
| Cloud sync | Settings → Sync Now (unauthenticated) | Shows "Sign in to sync" message |
| Web fallback | Run on web (no camera/OCR/STT) | NoOp services return gracefully, no crash |
GitHub Actions runs on every push:
dart format --set-exit-if-changed .flutter analyzeflutter test- Concurrency: cancels in-progress runs on same branch
| Wave | Name | Status | Tasks |
|---|---|---|---|
| W0 | Foundation | Complete | 8/8 |
| W1 | Core Capture | Complete | 5/5 |
| W2 | Search + Polish | Complete | 3/4 (Sentry pending DSN) |
| W3 | Audio + Sync | Complete | 4/4 + UX fixes |
| W4 | iOS + Desktop | In Progress | 1/5 (platform abstraction done) |
| W5 | Monetization | Blocked | 0/5 |
| W6 | Launch | Blocked | 0/6 |
- Free — Unlimited local captures, 1 device
- Pro ($4/mo) — Cloud sync, audio capture, up to 5 devices
- Power ($9/mo) — Export (JSON/CSV/MD), unlimited devices, API access
MIT
Built by Claudeking.org