MONOLITH·LOCAL-FIRST COMPETENCE TRACKER
Your work should leave a record, not a streak.
Monolith is a mobile competence tracker. Every focused session, completed task, or manual log deposits a layer into a block of stone. The grid filling up is the reward — no badges, no daily bonus, no “Good morning!” popup.
Role
Sole author
Stack
React Native · Expo SDK 57
Storage
AsyncStorage, JSON export
Status
Pre-release MVP, iOS verified
Screens
01 / 08
Architecture
How the system fits together
Focus session, task, or manual log → recorder → strata geometry → AsyncStorage activity store → grid, profile, and JSON export
The problem
Most productivity apps are engagement machines
Streaks, badges, confetti for opening the app, a dashboard that measures tapping instead of work. The metric a productivity app optimises for is retention, not competence.
Monolith optimises for something else. A focused session should leave a visible mark, and the mark should be proportional to the effort. So the app has no streak to protect and no celebration to fire — just a grid that fills, and a block of stone that grows a layer every time you do the work.
Competitive gap
What existing trackers get wrong
The three existing categories each fail in a way that is hard to patch around. Streaks punish rest. Dashboards measure the wrong thing. Cloud trackers hold your record hostage.
None of them are wrong about wanting engagement. They are wrong about what engagement is for.
Data model
Strata: effort as geometry
The centre of the app is a block of stone. Each identity — Code, Writing, Movement — is its own block. Every recorded session or manual log deposits a layer whose thickness is derived from the effort it took: a 47-minute session is a thick band, a 3-minute log is a hairline.
Layers stack in time. Recent work stays distinct at the top; older work compresses into a base that still accounts for every minute. Tapping a slice opens the layer inspector, so the geometry is never decoration — you can always read it back.
The screens
The loop: focus, record, correct
Opening the app is not the point, so the Grid leads: minutes today against your goal, the block of stone, 26 weeks of history, identity filters, and today’s tasks. Start focus from there.
The Focus screen is a count-up timer. It keeps the screen awake, survives backgrounding, and drafts an unsaved layer into the stone as it goes, so you can see what you are about to bank. Finishing records the session exactly once; the layer then settles into the stack. History lets you inspect any day, edit a duration, change an identity, remove a record, or undo the whole thing — and every edit keeps the original task, date, and completion time.
Privacy and storage
Local-first, with the cloud as an option
Everything is on the device. Activity records live in AsyncStorage, state is persisted with Zustand, and secrets — if any — go to SecureStore. The app is fully functional offline; there is no request to make before the first session.
Supabase is there but off by default. The repo carries a schema, row-level security policies, and an auth-profile trigger migration, and the email sign-in UI is built. What is not built is the sync itself: no mutation queue, no conflict resolution, no realtime. Turning it on is a decision, not a default.
Settings can export every record as JSON and delete all local data behind a confirmation. Both exist because local-first software has to be honest about who owns the data.
Interaction
Calm motion, and how to turn it off
The app animates like stone settling, not like a slot machine. Presses spring. The tab indicator slides. A new layer drops into the block and finds its place. Nothing loops, nothing pulses for attention, and there is no sound.
Every animation respects the system’s Reduce Motion setting: the geometry swaps for fades rather than moving, because a layer that slides into place is the whole point of the model — and a reduced-motion build that still slides is worse than one that does not move at all. Haptics fire on the same layer drop, so the stone lands with weight.
If the reward is the grid filling up, the animation has to get out of the way.
Results
What is verified, and what is not
The local-first loop is implemented end to end and verified on the iOS Simulator through both Expo Go 57 and a Debug development build. Android is verified through a production export, and the web build is used for browser QA. TypeScript and ESLint are clean, and 32 Jest tests across 4 suites cover the date, grid, and XP utilities.
The honest part: this is a pre-release MVP. Nothing is on the App Store, and verification so far covers simulators and exports rather than physical devices.
32
Jest tests
ACROSS 4 SUITES
0
Accounts required
WORKS OFFLINE
3
Exports passing
IOS · ANDROID · WEB
Source · iOS Simulator (Expo Go 57 + Debug build), Android production export, browser QA
Lessons
What building it taught me
Designing a reward you cannot lose took longer than designing a streak. The first attempts kept wanting a celebration, and every celebration turned into a nag. The grid only works because it is quiet.
The second lesson was making effort legible. A layer whose thickness is derived from real minutes is a far better signal than a checkbox, but it means the geometry has to be data-driven rather than decorative — recomputed from the record, not drawn by hand. That decision is what makes edit and undo cheap: change the record and the stone changes shape.
The third was scope. It is much easier to ship a local-first MVP that admits it does not sync than a cloud product that pretends otherwise.
A reward you cannot lose is harder to design than a streak you can.
Still open
What is not built yet
No cloud sync
The Supabase schema, RLS policies, and auth trigger are in the repo, and the sign-in UI is built. The mutation queue, conflict resolution, and realtime layer are not. The app is local-only today.
No widgets, no notifications
Home-screen and lock-screen widgets and local reminders are on the list and not started. The app only speaks to you when you open it.
Physical devices are unverified
Verification covers the iOS Simulator, Android production exports, and browser QA. Haptics on real hardware, Android at runtime, VoiceOver, and enlarged Dynamic Type are all still unverified.
Desktop app is a plan
The repo is a Turborepo monorepo with a shared package for date, grid, and XP utilities, and a Tauri desktop app is planned on that seam. It does not exist yet.
In short
What Monolith came down to
01
Measure effort, not taps
The unit is a focused minute that turned into a layer, not a screen you opened.
02
No account, no hostage
The app works offline and exports to a file you own. Cloud is a switch you flip, never a toll you pay.
03
Quiet is a feature
The reward is the grid filling up. Everything else — motion, sound, badges — stays out of the way.










