From Brain to App
Until now, Pepper was something only I used.
My account, my chat rooms, my Vault. As a test bed, that was fine. But for the family to use it, each of them has to log in and come inside. From that moment on, a completely different kind of work began.
Deciding the order of onboarding was the design
It wasn't just throwing up a login screen. Every step in the order was a decision.
The flow I finally settled on:
Welcome (Log In / Sign Up) → enter family_code (which family) → Google OAuth (who you are) → pick role (head / member / child) → connect Calendar · Gmail → set up FaceID
Every step is there for a reason.
Why family_code comes first. In EP 02, worrying that "it might not just be our family," I laid down family-level data isolation from day one. That design becomes real here. You have to know which family a person belongs to before their Vault and chat rooms can land inside the correct isolation. Right now there's only one family — ours — but the code is ready for many.
Why role is captured during onboarding. The Family Graph from EP 01 — who can do what to whom. head/member/child permissions get set here. For example, toss.transfer (a money-transfer deep link) is allowed for head and member only, never child.
Why OAuth runs on the server
This was the technical decision I agonized over most.
Google login can be finished on the client (the app). But Pepper doesn't just log you in — it has to keep reading my calendar and Gmail. For that, you need to store not just the access token but the refresh token securely, and have the server renew it automatically whenever it expires.
So I built OAuth server-side. /api/google/auth + /api/google/callback on Vercel, tokens stored in the DB (oauth_tokens). Since one person needs to be able to attach multiple accounts (something EP 02 already anticipated), I added an is_primary / secondary distinction.
This decision comes back to bite in EP 17. A single token dying silently turns an entire briefing into a half-briefing — but that's later.
Why the FaceID gate. The Vault holds the family's financial records and legal documents. It can't just open for anyone who picks up the phone. So I put local biometric auth in front of the app.
The five tabs
What the family sees when they open it.
Chat — talk to @Pepper, family room, 1:1 Action — to-dos (mine / Pepper's) Brief — morning briefing (weather · calendar · mail) Vault — the family's memory (wine · recipes · restaurants · docs) Shelf — what Pepper can do (capabilities on/off)
Chat/Action/Brief/Vault split EP 01's two promises — looking out for us, and doing what we ask — into screens. Shelf is a little different: it's where the family turns Pepper's abilities on and off. Only head/member can toggle, and it's shared across the family.
The Attention Gate — deciding when Pepper chimes in
Here I made a small but important decision.
In the family room, Pepper can't react to every message. If Eunsoo and Eunje are chatting with each other and Pepper keeps butting in, it's noisy — and the cost I worried about in EP 01 blows up. You can't fire an LLM at every bit of kids' banter.
So I put up an Attention Gate. In family rooms and DMs, Pepper only responds — and shows a typing indicator — when it's mentioned with @Pepper. This check happens first, at the API layer, so if there's no mention, it never even reaches Pepper Core. The personal Pepper room has no gate; it always responds.
The cost philosophy from EP 01 — "light decisions on cheap models, the expensive model only when a real brain is needed" — came down here as a rule that skips the call entirely. The cheapest LLM call is the one you don't make.
Building a brain, and wrapping that brain so a family can hold it, turned out to be completely different kinds of work. Login order, token refresh, biometrics, when to chime in — none of it has anything to do with how smart Pepper is. It's just the work of an app becoming an app.
Now it's time to fill it in. Starting with the most visible thing.