Inspiration

Every productivity app we tried solved a problem we didn't have.

We knew what the task was. We knew it mattered. We had the time. And we still sat there, not starting — then organised the list again, because organising feels like progress and starting feels like a cliff.

That gap between knowing and beginning is where the day goes. No app addresses it. They all assume the hard part is deciding what to do, so they give you better ways to sort, tag, prioritise and schedule. Then they hand the sorted list back and the cliff is still there.

start/ish only cares about the first two minutes.

What it does

You type or speak whatever's in your head. Messy is the point — no categories, no priorities, no setup.

start/ish reads it and hands back one concrete action small enough to begin right now. Not a plan, not a breakdown, not a list. One step.

Then a two-minute timer, and an honest question afterwards: did you keep going, make a dent, get set up, or do you need something smaller? Every one of those is a real answer. "I need something smaller" produces a smaller step instead of a guilt trip.

Underneath that:

  • Reflective Intelligence — every Sunday, a short reflection on the week you actually had, generated strictly from your real starts and read aloud in one of ten voices. It invents nothing. It's the one part of the app that asks nothing of you.
  • Time Mirror — notices the gap between when you plan to start and when you actually do, then offers to shift your start windows earlier. Only when there's a real pattern, never as a nag.
  • Calm buffer — "finish by 3pm" becomes a start window that accounts for how long the task takes plus breathing room, so you arrive steady instead of sprinting.
  • A technique each week with the research behind it, screenshot-to-tasks, Apple Reminders import, a Live Activity while a start is running, a momentum widget, Siri and Shortcuts, Genmoji check-ins, and two whole personalities (Calm and Playful) that change the app's voice.

What you write stays on your device. No feed, no streaks to break, no social pressure.

How we built it

Native SwiftUI, iOS 26, with SwiftData as an offline-first local store — no cloud sync, deliberately. The thing people dump their unfiltered thoughts into shouldn't be syncing anywhere.

The AI layer runs through Supabase Edge Functions in Deno rather than calling a model from the client. That keeps the key off-device and gave us one place to enforce rate limits, request shape and timeouts. The suggestion endpoint uses OpenAI's Responses API with a strict JSON schema, so a malformed response is a parse failure we can handle rather than garbage rendered in the UI.

Monetisation is RevenueCat end to end: one pro entitlement, a default offering with $rc_annual and $rc_monthly, and a 7-day trial. We'd originally built directly on StoreKit 2 and moved across mid-project — the win wasn't the purchase call, it was no longer owning entitlement state, cross-device restore, or the subscriber lifecycle. Feature gating became one question (hasEntitlement("pro")) instead of receipt logic scattered across the app.

Rounding it out: Sentry for crash reporting with dSYMs uploaded per build, TelemetryDeck for privacy-respecting analytics, Rive and Lottie for the illustrations, custom Metal shaders for the aura and falling-cube backgrounds, App Intents for Siri, ActivityKit for the Live Activity, and on-device speech transcription so voice capture never leaves the phone.

Challenges we ran into

The paywall that failed open. When the product list came back empty, our offeringState landed on .notConfigured and the gate let everyone straight through. In testing that looks like success — the app works! In production it would have meant Pro was free for every user, silently, with no error anywhere. We found it by reading the gate rather than testing it, because the test passes either way. Entitlement checks have to fail closed, and we'd written the one case that doesn't.

Purchases that silently did nothing. The RevenueCat path guards on a signed-in user ID and returns early without one. A guest reaching the paywall would tap Subscribe and get back... nothing. No error, no sheet. We had to trace the full route to confirm guests hit authentication first, then exercise it end to end rather than trust the read.

64 notifications. iOS caps pending local notification requests at 64 per app. Our Start Support schedules up to two per task — a heads-up and the window itself — and with recurring reminders on top, a heavy week blows the budget and iOS silently drops the overflow. The limit isn't the problem; thinking we had infinite slots was.

Notification copy that ate itself. A generated suggestion title can run to 180 characters. Dropped into a banner, it pushed "Two minutes is enough" off the edge — leaving the user with only the task they were already avoiding and none of the reassurance that makes the reminder worth tapping. We added a shared clamp that cuts on word boundaries, used by both the planner and the return nudge so the two can't drift.

A model regression that wasn't. We changed the OpenAI model, decided the output had got worse, and spent real time tuning reasoning effort and token limits to fix it. The output never moved. The test prompt we kept using happened to match a worked example sitting verbatim in the system prompt, so the model was reciting, not reasoning — identical before and after, by construction. The lesson was cheap and embarrassing: if your benchmark input is in your prompt, you aren't benchmarking anything.

Keyboards, as always. ignoresSafeArea as a ZStack child instead of a background modifier, and the primary action vanished behind the keyboard on two different screens.

Accomplishments that we're proud of

It never invents your week. The Sunday reflection is built only from starts that actually happened. It would be trivially easy — and much more impressive-sounding — to let the model embellish. For an app aimed at people who already don't trust their own follow-through, a reflection that praises a week you didn't have is worse than no reflection.

"I need something smaller" is a real button. Not a failure state, not a sad animation. It produces a smaller step. Shipping an app about starting that doesn't punish you for not starting took more restraint in the copy than in the code.

The voice holds everywhere. Two personalities, three reminder tones, and every string — notifications, empty states, errors, the paywall — written in them. No stray "Oops! Something went wrong."

Depth that doesn't demand attention. Live Activities, widgets, Siri, Genmoji, Image Playground, Metal shaders, Apple Reminders import. All of it optional, none of it in the way of typing a thought and getting a step.

What we learned

Grounding beats capability. Our best AI work was constraining the model — strict schemas, real user data only, one output not five. Every time we gave it more room, the output got more impressive and less useful.

Local-first is a product decision, not an infrastructure one. We could have synced. Choosing not to meant being honest in the App Store listing that a new phone starts empty. That's a real cost. It's the right one for a notebook you dump unfiltered thoughts into.

Platform limits are design constraints. The 64-slot cap forced us to ask which notifications actually earn a slot — which is a better question than "how many can we send."

Monetisation infrastructure is worth outsourcing early. Moving to RevenueCat mid-build cost a day. Had we started there, feature gating would have been one line from the beginning instead of something we refactored into shape.

Read the failure path, not just the happy one. Both of our worst bugs — the open paywall, the silent purchase — were invisible to testing. They only showed up by reading the code and asking what happens when this returns nothing.

What's next for start/ish

Make Time Mirror earn its name. Right now it learns the gap between planned and actual start for mornings. Next it learns which days carry you, which task shapes stall, and what time of day your two minutes actually turn into twenty.

Reflections you can keep. The Sunday audio is ephemeral. It should be a library you can scroll back through — a year of honest weeks is a different object from one good Sunday.

An opt-in encrypted backup. Local-first stays the default. But losing your history to a lost phone is a real cost, and it should be the user's call.

Shared starts. Not social, not a feed. One person, one task, same two minutes. The smallest useful form of body-doubling.

Widen the capture surface. Share sheet, Apple Watch, and a keyboard extension — so the thought gets caught wherever it shows up, which is rarely inside the app.

Built With

Share this project:

Updates

Submission history