Inspiration
Last year I found the Shipaton page, read the whole thing, got to the eligibility rules and stopped. Age of majority. I was fifteen. I closed the tab frustrated and, honestly, angry. The thing I wanted to do was right there, and the only thing between us was a birthday.
This year RevenueCat added the Next Gen Award, open to students from thirteen. That was the door. I decided to walk through it twice: I'm submitting two apps, Stick and Ilo. This page is Stick.
When I got my first phone I didn't install a single game. I installed Duolingo and started learning English that same day. I've lost the streak plenty of times, and I'm on 301 days now. What I learned from that owl is that a notification is easy to swipe away. Nothing an app says to you is hard to ignore, because it isn't you saying it.
I'm not writing this from above. I lose hours to the scroll myself, and I watch people around me do the same every day. I tried blockers and screen-time limits, and I got around every one of them in two taps, because the person who sets the limit and the person who breaks it are the same person, and the one breaking it always wins at the moment that counts.
So I asked a different question. Not "how do I block TikTok", which every app already tries and every user learns to get around, but who is the one person you can't hang up on?
You can ignore a coach. Nobody ignores their own voice.
What it does
Stick is a 75-day program against doom-scrolling. It records sixty seconds of your voice, clones it, and then calls you with it.
- The wake-up call. Every morning your phone rings like a real call, on the Lock Screen and in the Dynamic Island. When you answer, it's you: "Up. Day 12. Give me your first goal for today. A real one." You answer out loud. It takes up to three concrete goals, refuses vague ones ("That's not a goal. What, how much, when?"), asks for an if-then plan, reads the goals back word for word and pushes them to your widgets.
- The interception. The second you open TikTok, your own voice rings: "You just opened TikTok. This morning you promised: run 5 km, finish the chapter. Close it, yes or no?"
- The evening debrief. Goal by goal, yes or no. If no: "Why? One sentence."
The 75 days are five acts of fifteen days, and the coach changes with you: drill sergeant, then a sergeant who builds habits, then someone who asks questions ("Who are you when nobody's watching?"), then a tester who gives you back fifteen minutes a day on your honor, then a mentor who calls once a day and helps you plan life after day 75. Even the ringtone changes: in Act I your voice says "It's you. Pick up.", in Act IV "It's you. Prove it."
Two rules I cared about more than any feature:
- Lapses are not failures. You get three jokers. Two missed days in a row restart the current act, never the whole program. I've lost enough streaks to know that "back to day one" is the moment people quit.
- Day 75 is an ending. On day one you record a message to yourself. On day 75 the Vault opens and plays it.
How I built it
I built Stick in ten days, from September 20 to September 29: 20 commits, about 9,850 lines of Swift and TypeScript. I don't write Swift by hand. I built it with AI (Bitrig and Claude), a few hours a day, and my job was the precision of what I asked for and the shape of the system: what the model is allowed to decide, what it isn't, and what happens when something fails.
The call engine: the code decides, the model only talks. My first version let the model run the whole call. It repeated questions, forgot goals and invented its own. So I rewrote it: each call type (wake-up, debrief, interception, recovery, push, and the first "aha" call) is a script in code. The code decides the next step (goal 1, goal 2, if-then plan, recap). The model gets one instruction per step and only writes the sentence. Some lines are fixed and the model never touches them, like the recap, because your goals have to come back exactly as you said them.
Everything has a fallback. A phone call can't make you wait.
- No voice clone, or the voice service is too slow (15 s budget): the system voice speaks.
- No AI consent, model unreachable, or one failed reply (10 s budget): the rest of the call follows the script, and answers are parsed with keywords.
- No microphone: Stick says one sentence ("write your goals with the + button") and hangs up.
- Store unreachable: the last known access is kept.
Voice. Fish Audio builds a private clone from the sample. Lines whose wording is known in advance, like the first call and the ringtone, are rendered while you're still on the "your phone is about to ring" screen, so the call starts instantly.
The phone call itself. AlarmKit rings on the Lock Screen and breaks through Silent. ActivityKit shows the live call in the Dynamic Island, with Answer and Hang up. The Speech framework listens, Core Haptics vibrates like a real ring, and there are widgets for today's goals, days held and the next call, plus a Control Center button.
No secrets in the app. Fish Audio and OpenRouter keys live in a Supabase Edge Function that forwards only the four calls Stick makes, caps request sizes and stores nothing. It only accepts free models, so even a leaked public key can't run up a bill.
How it makes money (RevenueCat)
The product is the 75 days, so the main product is a ticket, not a subscription.
- 75-Day Pass, $79.99, one-time (about $1.07 a day, computed from the store price in the user's currency). Weekly, $9.99, behind a small "I'd rather try one week first" link for people who aren't ready to commit.
- No free trial, on purpose. The paywall says it plainly: "a trial is a way out, and you're done with those."
- Hard paywall at the moment of proof: after you've heard your own voice call you and signed a contract with yourself, not before.
- One
memberentitlement for both products. Placements (onboarding,locked_out,settings), so offerings and prices can change per moment from the dashboard without an update. customerInfoStreamdrives access live: renewals, expiries, refunds, Ask to Buy approvals and restores on another device lock or unlock Stick without a relaunch. Losing access cancels the scheduled calls, and getting it back reschedules them.- Sign in with Apple, on device only. The Apple user ID becomes the RevenueCat app user ID, so purchases follow the user across devices without me running an account database.
- Subscriber attributes
program_day,program_actandvoice_mode, so I can compare day-3 users with day-60 users in Charts. Never names, goals or answers. - Customer Center in Me › Subscription.
- The Test Store in Debug, so anyone who clones the repo can buy in the simulator with no Apple account.
Challenges I ran into
The model that wouldn't stop talking. Letting a model run a phone call gives you a call that loops. The fix wasn't a better prompt. It was taking the decisions out of the prompt and putting them in code.
Free models are free until they disappear. Halfway through, the free model I used was withdrawn. The replacement has reasoning that can't be turned off, and that reasoning quietly ate the whole token budget, which left empty replies. I now give it hidden reasoning at minimum effort plus a 300-token headroom. The same small model also flagged "I'm done" after the very first goal, which ended goal collection too early. Now only an explicit phrase like "that's all" ends the list.
My keys in the repo. A comment at the end of a line in my .gitignore broke the pattern, and my API keys file was committed. I retired those keys, cleaned the history before making the repo public, and built the relay so no private key ever ships again.
Cutting what I liked to ship what was honest. Stick had a league with other players, and before real users existed it was showing seeded fake ones. It had "invite a friend, get 5 free days", which App Review doesn't allow, and a testimonial I had written myself. I cut the league and the referral reward, and I replaced the testimonial with a sourced fact: a new habit takes a median of 66 days to become automatic (Lally et al., 2010). That's also why 75 days.
The permission I don't have yet. Blocking apps properly needs Apple's Family Controls entitlement, which I haven't been granted. So interception works through a one-minute Shortcuts automation that opens stick://intercept, with a step in onboarding that detects live whether it worked. Nothing in the app promises Screen Time until it's real.
75 dots don't fit on a phone. My first home screen drew one dot per day. It overflowed. Now it's five act bars that always fit, with held days in green and today pulsing.
Accomplishments that I'm proud of
The first time my own cloned voice called me, I laughed. Hearing yourself say "It's you. Pick up." is absurd for about three seconds. Then the voice asks for your first goal, and that's the part that stops being funny: it's hard to lie to yourself out loud.
- A complete 25-step onboarding: quiz, voice recording, the first call in your own voice, a contract you sign with your finger, the ticket.
- Calls that never hang on the network: every dependency has a fallback, measured in seconds.
- A RevenueCat integration where access is live, per placement and tied to Apple identity, with no backend of my own.
- English and French throughout, and privacy by construction: the program lives on the phone, voice and AI each need their own consent, and deleting your account deletes the clone at the provider.
What I learned
- The model phrases, the code decides. Anything that must be true (which step we're on, what your goals are) belongs in code. The model makes it sound human.
- Design for the failure first. A voice call is the least forgiving interface there is: two seconds of silence and it feels broken. Every network call in Stick has a budget and a plan B.
- Honest beats clever in a paywall. No fake urgency, no fake reviews, no trial that exists only to convert. The price is the price, and the buy button stays disabled until the store has given it.
- A streak you can lose in one day is a streak you'll quit. Jokers and act restarts came from my own Duolingo history.
What's next for Stick
- Ask Apple for the Family Controls entitlement and replace the Shortcuts workaround with a real Screen Time shield.
- Ship it on the App Store. The review checklist, privacy manifests, legal pages and account deletion are already in the repo.
- Bring the league back only when it has real players and a real backend behind it.
- Use the
program_dayandprogram_actcohorts to find where people drop, and test offerings per placement.
Built With
- activitykit
- alarmkit
- app-intents
- avfoundation
- bitrig
- claude
- core-haptics
- deno
- fish-audio
- ios
- liquid-glass
- openrouter
- revenuecat
- revenuecatui
- shortcuts
- sign-in-with-apple
- speech-framework
- storekit
- supabase
- supabase-edge-functions
- swift
- swiftui
- typescript
- widgetkit
- xcodegen
Log in or sign up for Devpost to join the conversation.