Stead
Stead is a personal commitment system that turns a person's values into scheduled actions, prices how hard each action is to start in XP and coins, and lets those coins buy rewards only within a real-money monthly budget. It matters because most habit apps lean on streaks and loss framing that punish people at exactly the moments they most need support, such as a hard day or coming back after a break. Stead is built so that nothing is ever taken away for not acting. It is a full-stack Next.js 16 and Supabase web app with a native SwiftUI iPhone client, deployed at stead.sinabolouri.com.
Problem
- Habit and gamification apps (the project's scope review uses Habitica, Finch and Beeminder as reference points) often build on streaks. A streak turns one missed day into a failure state and makes coming back harder.
- Self-rated points inflate. When users type their own points or rate "alignment", the numbers drift upward within weeks.
- In-app reward stores are usually disconnected from real money, so "earning" a reward says nothing about whether the user can actually afford it this month.
- The data is sensitive. Skip reasons, mood and reflections are mental-health-adjacent and need stronger isolation than a typical to-do app gives them.
Solution
- Values as the spine. Every action links to one to three of the user's values. XP is split across those values and drives per-value levels.
- Friction pricing, not self-scoring. The user rates resistance (how hard it is to start) and effort on 1–10 scales, enters minutes and an optional importance (1–5). The economy module computes pay. The user can nudge it by ±20% but can never type points.
- Two currencies with separate jobs.
- XP is evidence. It comes from the action's stable profile and never decreases.
- Coins are reinforcement. They earn a hard-day bonus (up to +30% when today felt harder than the profile), a return bonus (+25% on the first completion after two or more lapses) and are capped at 1.5×.
- Minimum versions. Every action can have a smaller "minimum" version that pays about half, so a hard day still counts.
- Coins anchored to money. Coins per dollar are derived from the user's planned weekly XP at 70% adherence and their monthly reward budget. A purchase costs roughly (price ÷ monthly budget) of a month of planned effort. Prices lock when a reward is created. A budget gate blocks redemption when the month's real money has run out.
- Recovery instead of streaks. Past items show as "Not logged", a gentle catch-up card asks what happened, and unresolved items quietly become missed after 72 hours. Missed is never red and never called a failure.
- Guardrails. Protected needs (sleep, meals, medication, hygiene, rest, time with people) can never be rewards. No streak value affects pay. No confetti, countdowns or red badges.
- Reflection and calibration. A weekly review shows the showed-up rate and return latency. Rule-based recalibration suggestions and a weekly auto-tune adjust ratings from felt difficulty and follow-through, never touching past XP.
- Assistant. An optional Gemini-based assistant proposes new or changed actions and rewards. Each proposal needs the user's confirmation.
User Experience
- Onboarding: pick at least three values (24 suggestions or custom), add first actions from per-value ideas or a calendar (.ics) import, set a monthly reward budget and a first reward, and confirm a baseline of daily free entertainment and protected needs.
- Today: the open action with the highest resistance appears first as "Start with the hard one". Items are grouped by part of day. A check-in sheet offers full, minimum, skipped or move, an optional "How hard did it feel today?" rating, and shows the exact pay before saving.
- Week plan: a routine grid on desktop and a day-by-day agenda on phones, with totals for sessions, planned time, potential XP and coins at 70% follow-through.
- Rewards: each reward is in one of three states (saving with % funded, funded but waiting on budget, or ready). The tab also offers 28 reward ideas and product-link autofill, and redemption takes two taps.
- Review and history: a weekly review with showed-up rate, return latency, hardest thing done, reflection prompts and the guardrail question "Did Stead make you feel worse about yourself this week?".
- Settings: budget, baseline, protected needs, time zone, notifications, auto-tune, JSON/CSV export and account deletion. A pilot switch, "Show XP and coins", hides the economy during a baseline week while logging continues.
- Assistant everywhere: a round button on every app screen opens the assistant. Voice input uses the browser's Web Speech API where supported.
- iPhone app: four tabs (Today, Plan, Rewards, You) plus system search, the same account and data as the website, and local reminders.
- Public site: a home page with a live pay demo and reward price calculator built on the real economy functions, plus About, Pricing, Privacy, Terms and a contact form that feeds an owner inbox with one-click invites.
Current Status
- Deployed at https://stead.sinabolouri.com. On 2026-10-16,
GET /api/healthreported commit3a1c347,economy-3, databaseok. - Invite-only. Sign-up is limited to an allow-list. The pricing page lists a free "Pilot" plan for invited people. Free and Pro plans for a public beta are listed with prices "to be announced".
- Build history: built from 2026-10-12 to 2026-10-14 in 31 merged pull requests. Claude Code acted as the coding agent and followed a written blueprint (
docs/BLUEPRINT.md). Owner decisions and agent choices are logged indocs/DECISIONS.md. - Release flags: the v0.2 (Reflection) and v0.3 (Calibration) features ship behind the
FLAG_REFLECTIONandFLAG_CALIBRATIONrelease flags. Whether these are switched on in production: Unknown. - Pilot: a 6–8 week N-of-1 pilot is designed with pre-registered success criteria. Start date and results: TBD.
- iPhone app: works and runs from Xcode or the Simulator. It is not on TestFlight or the App Store.
Tech Stack
- Frontend: Next.js 16 App Router (React Server Components with small client islands), React 19, TypeScript (strict), Tailwind CSS 4 design tokens, shadcn/ui on Radix, vaul, sonner, lucide-react, Geist fonts.
- Backend: Next.js Server Actions validated with Zod. Privileged writes go through Postgres SQL functions called server-side with the Supabase secret key.
- Database and auth: Supabase Postgres with Row Level Security, Supabase Auth (email magic link plus 6-digit code, optional password, Google sign-in behind a flag).
- Domain logic:
src/lib/economy.ts, a pure, versioned economy module.date-fnsand@date-fns/tzhandle time-zone-correct day boundaries. - AI: Google Gemini API (default model
gemini-3.5-flash-lite) for the assistant and "Ask AI" rating estimates, with function calling and JSON-mode responses. - PWA and notifications: Serwist service worker, an IndexedDB offline queue (
idb-keyval), Web Push (web-push, VAPID) and an hourly Vercel Cron job. - Email: Resend, used both as the Supabase Auth SMTP and through its REST API for contact and invite emails.
- Native: SwiftUI (iOS 26),
supabase-swift, the SteadCore Swift package (economy and reminders), XcodeGen. - Quality: Vitest, Playwright with
@axe-core/playwright, SQL invariant tests on plain Postgres, Supabase integration tests, ESLint module boundaries, custom CI gates. - Infrastructure: Vercel (its own project, separate from the portfolio), GitHub Actions, optional Sentry with PII scrubbing.


