This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend
What I Built
My friend is growing his 4C hair back toward shoulder length, and for a long time his routine has basically been absolute chaos.
He would ask questions like how many times to shampoo, or apply conditioner and immediately wash it off, slept without a bonnet or durag, so every night his hair rubbed against a cotton pillowcase (which is bad for that kind of hair). Between wash days, he didn't bother with anything else such as moisturizing, etc. He just winged it and complained about his hair a lot so I decided to do something about it.
I thought about it and decided that we don't need a miracle product or complex solution, a plan for the days between wash days, a nudge to actually follow it, and something that could notice how his hair was responding and adjust without overreacting would do just fine.
So I built Super Stylist: a small local-first web app with an AI hair stylist at its core, powered by Google’s Gemma 4 E2B running on my laptop through Ollama.
I didn’t want another chatbot with a hair-care prompt attached to it. The main screen is a daily hair-care kit: a few things to do today, like moisturizing, covering his hair at night, and checking his scalp on certain days. It’s more or less the opposite of his old routine.
Every Sunday he does a one-minute review: he rates dryness, breakage and scalp comfort, and can add a length measurement, progress photos, and a note. Super Stylist reads that, along with his past reviews and how much of his kit he actually completed, and decides what happens next week: continue, modify, or simplify.
There’s also an extra review for when something feels off mid-week, a photo journal for his progress, and a chat for questions. The chat is deliberately secondary. The app is supposed to help him take care of his hair, not spend all day talking to an AI about it.
His notes, measurements and photos live on his phone, and only travel to my laptop when Super Stylist reviews them. They never go to an AI company.
A minute after he first opened it, his verdict was:
“It’s very dope.”
Demo
I'd suggest watching this at the end of the blog post.
Super Stylist runs on my laptop by design, so there’s no public link: the video shows the real thing, with Gemma running locally. It walks through a Sunday review with a photo and a question, the plan it produces for next week, a chat about hair growth, and the progress journal.
Code
philip-edekobi
/
super-stylist
AI Haircare Helper
Super Stylist
A local-first hair-care coach I built for a friend who's growing his 4C hair back toward shoulder length. It gives him a short daily routine, a one-minute weekly check-in, a photo journal, and an AI stylist he can ask questions. The AI is Gemma 4 E2B, running on my own laptop through Ollama.
Built for the Hacktoberfest Weekend Challenge: Build for a Friend on DEV (October 2–5, 2026).
Write-up: [link to the DEV post] Demo video: YouTube
What it does
- Today: a short daily kit (moisturize, protect your hair at night, check your scalp on some days). Tick tasks off as you go; a new kit appears each day.
- Sunday review: rate dryness, breakage and scalp comfort, and optionally add a length measurement, photos and a note. Super Stylist decides whether next week's routine continues, changes slightly, or gets simpler, and answers anything you asked in the…
The stack: Next.js 16 and TypeScript, Dexie (IndexedDB) for local storage on the phone, Zod for validating everything the model returns, and Ollama serving Gemma 4 E2B on the laptop. The app talks to Ollama through a small proxy route, so his phone can reach the laptop’s model through an ngrok tunnel.
How I Built It
My laptop specs are: 11th-generation Intel i5, 16 GB RAM, and no discrete graphics card. My first test with Gemma 4 took more than three minutes to produce a short answer, and I assumed local AI on my laptop was simply going to be too slow.
Then I looked more closely. Gemma 4 thinks before it answers by default, and most of those three minutes was thinking. I wasn’t building a research assistant. I was building a hair-care companion.
So I tested Gemma 4 E2B with thinking disabled:
| Setup | Writing speed | Time for a short answer |
|---|---|---|
| Gemma 4, default size, thinking on | 2.8 tokens/s | 4 min 3 s |
| Gemma 4 E2B, thinking on | 3.8 tokens/s | 3 min 11 s |
| Gemma 4 E2B, thinking off | 14.4 tokens/s | 4.8 s |
This made me realize that the real important question I should be asking was: “What’s the smallest amount of intelligence I actually need for this job?”
With thinking off, an average weekly review, with his history in the prompt, now takes about 45 seconds to a minute. A chat reply takes about 15. This is assuming the model is warm. If it isn't, after the model sits idle for a while, the first request takes about a minute on average while the laptop loads it back into memory.
Giving the thinking back, but only to reviews
Once everything worked, I revisited that trade-off. A weekly review happens once a week, so a few minutes of waiting is fine if the decision is better. So reviews can think again: a Think it through switch in Settings, on by default, lets Gemma reason before it decides next week’s plan. With the model warm, a review with thinking on takes about 90 to 100 seconds, against 45 seconds to a minute without it.
Two safeguards come with it. The review waits up to ten minutes before giving up, and if thinking ever breaks the structured answer, the app quietly retries once without thinking instead of leaving him stuck. His review is saved before any of this starts, so a failure only ever costs a retry.
Chat never thinks. A conversation can’t wait three minutes.
Making chat fast
Chat had the opposite problem, and my friend spotted it immediately (more on that below). When I looked at where the 15 seconds went, most of it wasn’t Gemma writing. It was Gemma reading: the rules, his context and the earlier messages were re-read on every single message, at about 95 tokens per second.
So I changed four things:
- Stop re-reading the same text. The rules and his context now come first in the prompt and stay identical between messages, so Ollama can reuse its work on that part and only read the new message.
- Shorter answers. Chat replies are 1 to 3 sentences, with a hard cap on length.
- Less history. Only the last two exchanges go with each message, which is enough for a follow-up like “what about biotin?”.
- Show the reply as it’s written. The safety check works sentence by sentence, so each sentence appears the moment it’s complete and has passed the check. Nothing unsafe ever reaches the screen, even for a moment.
The first message is still about 15 seconds, because there’s nothing to reuse yet. After that, replies take 3 to 5 seconds.
Valid JSON is not good judgment
I used Ollama’s structured output to force the model’s answers into the exact shape my app expected. It worked: the JSON was valid every time.
The problem was the decision inside the JSON. In one test, the model saw that 80% of the routine had been completed, decided that wasn’t consistent enough, and recommended simplifying it. This implied that the model was inventing arbitrary parameters to judge consistency which ended up being terrible for my recommendations.
The fix was to move responsibility into the application. The app already knows how many tasks were completed, so it calculates adherence itself and labels it (70% or more is good). The prompt then gives the model rules instead of asking it to invent them:
- good adherence and no clear problem → continue
- a clear problem → at most a couple of targeted adjustments
- poor adherence → simplify before adding anything
Small models are much more useful when the application gives them the rules instead of asking them to invent the rules.
Let the application own the rules
The more I tested, the more responsibility moved out of the prompt and into code. That sounds less “AI-powered”. It actually made the AI more useful.
Photos only go to models that can actually see. A model claiming “vision” isn’t enough, so the app shows it a red circle, then a blue square, and asks what it sees. Only a model that gets both right receives my friend’s photos. Otherwise the review tells him visual analysis isn’t available and works from his notes and measurements. I’d rather say “I couldn’t analyze this photo” than have a model confidently describe an image it never saw, especially when the image is someone’s body.
A note always gets an answer. In one of my own tests, I asked in my weekly note whether I should buy the hair-growth boosters I kept seeing in ads. The model reviewed everything else and ignored the question completely. Now, when he writes a note, a reply is a required field in the output schema, and the app rejects any answer that skips it. Don’t rely on a model to remember a requirement your application can enforce.
Safety happens before the answer reaches him. Every answer is checked sentence by sentence for diagnoses, medication, growth promises (amounts, dates, guarantees) and brand names. Offending sentences are removed, and if too little is left, the answer is replaced with a safe one or rejected. “No product can guarantee hair growth” is useful. “This will grow your hair 2 cm a month” isn’t.
The AI suggests changes; the app applies them. It can’t remove the weekly review, can’t rewrite a whole week from one bad day, and a malformed suggestion is dropped instead of breaking his routine.
Why I made the AI swappable
It would have been easier to hard-code one model. Instead, the app talks to an interface, and every provider says what it can do:
Super Stylist
|
AI Provider
|
+-----------+-----------+
| | |
Gemma Other Mock
Ollama Provider Provider
capabilities: { text: true, vision: true }
If I swap Gemma for another model tomorrow, nothing else changes, and if the new model can’t see images, the app adapts instead of breaking. The mock provider also let me build and test every screen, including broken and offline answers, before Gemma was even connected.
Test like the real user
The bugs that would have hurt most only appeared when I used the app the way my friend would:
- His first review would have scored him 21%. The completion count included days before he’d even signed up. An AI system is only as good as the context you give it.
- His phone couldn’t have opened the app. Over a home-network address, browsers treat the site as insecure and remove an API I relied on, and Next.js blocks other devices from its dev server by default. It worked perfectly on my laptop and failed the only test that mattered: could my friend open it?
- One wipe could have lost everything. Local-first means his data lives in his phone’s browser, so I added a backup file he can save and restore, even on a new phone. You own the data, which also means you own the responsibility of backing it up.
Why Does Open Innovation Matter?
Hair photos are personal. So are notes about your body, your routine, and the things you’re trying to improve. I didn’t want my friend’s progress history sitting in some company’s database just because I wanted an AI feature.
An open-weight model running locally changed what I could promise him:
- His data stays with us. Everything lives in his phone’s browser. When Super Stylist reviews his week, it goes to my laptop and nowhere else. No account, no remote database, no AI provider seeing his photos.
- It costs nothing to run. No API bill, no free-tier limits, no card on file. That matters when you’re building for one friend, not a business.
- I could change how the model behaves. Turning off Gemma’s thinking took a short answer from three minutes to under five seconds, and I could switch it back on just for weekly reviews, where a better decision is worth an extra minute or so. Constraining its output to my schema, keeping it loaded between requests, and picking the smallest model that does the job were all my decisions, not a provider’s.
- I can swap the model. The app depends on an interface, not a vendor. If a better open model comes out, I pull it and run the photo test.
I could have built this around a closed API in an afternoon, and it would probably have been faster. But one of the most interesting questions would have disappeared:
Can a personal AI actually belong to the person using it?
With local inference, the answer gets much closer to yes. Open innovation isn’t just about getting a model for free. It’s the freedom to decide where the intelligence runs, what data it sees, which model powers it, and what the application allows it to do.
The honest trade-off is speed. My friend noticed a 15-second chat reply straight away, and making chat feel fast on a laptop CPU took real work. After the first message, it’s now 3 to 5 seconds.
Handing It Over: What They Said
I gave the app to the person I built it for, gave him a few things to do, and stayed quiet. Beyond “very dope”, his feedback was more useful than the compliment.
The app didn’t explain itself. Right after setup he hesitated, then tapped through every tab to work out what it actually did. Nothing told him: here’s your daily kit, Sunday is review day, here’s where you talk to Super Stylist. He figured it out, but I was watching someone use the product without the context in my head.
Local AI has a cost you can feel. After asking a question, his first reaction was:
“Why is the chat response very slow?”
I have to agree that fifteen seconds is indeed slow, so I reworked chat until replies after the first message took 3 to 5 seconds (see “Making chat fast” above).
My friend is sharp and figured things out by exploring, so I also tested with someone less like me. D isn’t a programmer, has 4C hair, and cares a lot about it. He hit the same wall first: he didn’t know what to do with the daily kit, or that it changes by itself each day. The weekly review felt like setting up the app all over again, and he had to ask out loud whether photos were optional. When I asked if he’d keep using it, he said:
“Yes… as long as the onboarding process isn’t repeated weekly.”
D also wanted more specific advice (which kind of oil, and why), suggested asking about scalp injuries at setup, and raised the hardest question in the project: with 4C shrinkage, how would you know when you’ve reached shoulder length? He wondered whether measuring “might just be a gimmick”. The progress page was his favourite part.
What I changed
- Today now explains itself: a short card after setup covers the daily kit, Sunday reviews, and where to ask questions.
- The review feels quick: it promises three quick ratings, with everything else under “Optional extras”.
- Setup asks about scalp pain, sores or injuries: a yes recommends seeing a doctor first and tells Super Stylist to keep things gentle.
- Advice can name ingredients and why they help, like a leave-in with glycerin to hold moisture, while still never naming brands.
Testing that last change exposed a bug in my own safety filter: one hair brand is called “As I Am”, so a normal sentence like “as I am not a doctor” would have been deleted. This taught me that safety rules need testing too.
My friend’s complaint about chat speed led to two more changes: chat was rebuilt for speed, and reviews were allowed to think again. Both are in “How I Built It” above.
What’s next
- Keep tuning speed with real use: time chat and thinking-on reviews on his phone over a few weeks, and switch review thinking off if the better answers aren’t worth the wait.
- A hosted option, for speed and for when my laptop is off, while keeping local as the private choice. Thanks to the provider interface, only the provider changes.
- Better progress photos, and goal pictures, as D suggested. 4C hair can shrink dramatically, and lighting and angles change, so standardized photos plus a stretched measurement beat a model’s visual guess.
Super Stylist isn’t going to prove that AI can grow someone’s hair. I built a small system to help one person be more consistent with something he already wanted to do. His hair will take months to grow, and if the app makes those days a little easier and adapts without turning every bad day into a crisis, it has done its job.
And if it stops being useful, he’ll tell me since we are friends and generally have no filter with each other.
Prize Categories
Best Use of Gemma. Gemma 4 E2B is the core of Super Stylist: it runs locally on my laptop through Ollama, with thinking turned off for speed and structured output for reliability. It writes every weekly review, decides each next week’s plan within the app’s rules, answers my friend’s questions, and reads his progress photos once it has passed the app’s vision test.


Top comments (0)