This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I Built

StoreScribe writing the Japanese App Store listing for AeroTail

StoreScribe writes your App Store and Google Play listings, researched against the apps you're competing with, inside every character limit, in up to six languages.

I build mobile apps, and the part I always put off is the store listing. The code is done, the screenshots are done, and then App Store Connect asks for:

  • an app name in 30 characters
  • a subtitle in 30 characters
  • a keywords field of 100 bytes. Bytes, not characters, so Japanese gets about a third of the room
  • promotional text and a description

Then Google Play wants its own title, short description and full description. Then you do all of it again for every language you want to sell in.

There are tools for this (App Store optimization, or ASO, is a whole industry), but they're built and priced for studios and agencies. An indie developer shipping one app a quarter isn't going to pay for that. They'd pay $6 a month for something that gets the listing right in two minutes.

Who pays: indie app developers and small studios. The free tier covers one app in three languages. The paid plan covers more apps, all 14 languages, competitor research and daily rank tracking.

What it does:

  1. Reads your screenshots with Gemma's vision, so the listing describes what the app actually does.
  2. Researches the category: pulls the top App Store and Google Play results for your search terms and finds the words they all use.
  3. Writes every field for both stores with Gemma 4.
  4. Enforces the rules in code, not in the prompt. Every limit is checked, Apple's keyword field is measured in bytes, banned words in Play titles are caught, and so is keyword stuffing and a short field that repeats a word ("Track planes & planes near you" got caught by this, and rewritten). Anything that doesn't fit goes back to the model to be tightened.
  5. Packs the keywords field: most valuable terms first, nothing already in the name or subtitle (Apple indexes those anyway), no competitor brand names, no wasted spaces.
  6. Localizes for each market, with the keywords people there actually type, not translations of the English ones.
  7. Lets you edit with live counters, keeps every version, exports straight to fastlane, and tracks your rank for each keyword, day by day, once you're live.

Competitor research: the top App Store apps for your search terms and the vocabulary they share

And a CLI that reads your repo

Filling in a form felt wrong for developers, so there's also a CLI. Run it inside your app's repo:

npx github:sbis04/storescribe --langs ja-JP,de-DE 

It reads the project itself: the app name and bundle id from Info.plist, pubspec.yaml or app.json, the README, the names of the screens in your code, your current fastlane listing and any screenshots it can find. Then it writes the finished listing into fastlane/metadata, ready for fastlane deliver. It works with Flutter, React Native, Expo, Swift and Kotlin projects.

Add --local and Gemma runs on your own machine through Ollama. No web searches, no server, nothing leaves your laptop.

The CLI reading the AeroTail repo and writing 24 fastlane files

Demo

Try it: storescribe.souvikbiswas.com (no sign-up)

StoreScribe on a phone Dark mode, keywords packed to 98 of 100 bytes

Code

GitHub logo sbis04 / storescribe

App Store and Google Play listings that fit every limit, use the words your category searches with, and read like a person wrote them.

StoreScribe

App Store and Google Play listings that fit every limit, use the words your category searches with, and read like a person wrote them.
In English and up to five more languages. Written by Gemma 4, an open-weight model

Try it: storescribe.souvikbiswas.com · Demo video · CLI

StoreScribe demo video

Why

Your app is done. Now the App Store wants a 30-character name, a 30-character subtitle, a keywords field of exactly 100 bytes, promotional text and a description, and Google Play wants its own set. Then the same again in every language you sell in. Japanese gets about a third of the keyword room, because Apple counts bytes, not characters.

StoreScribe studies the apps you're up against, then writes both listings inside every limit, in about two minutes.

Screenshots

Your listing, inside every limit. A live App Store preview with your screenshots, and a counter on every field.

The App Store listing for AeroTail with a store preview and live character counters

Each language…




MIT licensed. Everything in the demo is in the repo, including the deploy scripts.

How I Built It

The model is Gemma 4. On the live site it's gemma-4-31B-it on DigitalOcean's serverless inference. Locally, and in the CLI's --local mode, it's gemma4 through Ollama. The same code talks to both: one setting switches between Ollama's API and any OpenAI-compatible endpoint.

The model writes, the code decides. This was the most important design choice. Language models are bad at counting characters, and worse at counting UTF-8 bytes. So I never ask Gemma to "stay under 30 characters" and hope. Each draft goes through limits.js, which measures every field the way the store does (grapheme clusters for names, bytes for Apple's keywords), lints it against store policy, and sends anything over the limit back to Gemma with the exact count. If two rewrites still don't fit, it trims cleanly at a word boundary. In the demo you can see this happen live: "Subtitle is 34/30, tightening it".

Keywords are packed by code, too. Gemma suggests 20 candidate terms in priority order. Code then builds the 100-byte field: it drops anything already in the name or subtitle, plurals of words already used, and competitor brand names (taken from the research), and stops before the byte limit. In Japanese that's only about 33 characters; AeroTail's Japanese keywords use 91 of the 100 bytes.

Research comes from SerpApi. The App Store and Google Play engines return the top apps for each search term. StoreScribe shows them, works out the words that recur across them (the category's search vocabulary) and gives that to Gemma as context. The page then shows which of those words made it into your listing. Searches are cached for a day, because the free plan is 250 searches a month.

Tiger Data holds everything that changes over time. It's TimescaleDB on Tiger Cloud:

  • listing_versions: every draft and every hand edit, per store and language, so you can go back to any version.
  • keyword_ranks: one row per keyword per daily check. The rank chart reads a time_bucket over this.
  • usage: every model call and search, with its cost. A usage_daily continuous aggregate powers the "this month" meter, and it's what a subscription would be billed from.

All three are hypertables.

DigitalOcean runs it. A $6 Droplet with Caddy (automatic HTTPS) and the Node app, created and deployed by one script (deploy/up.sh). Gemma runs on DigitalOcean's serverless inference, so the Droplet needs no GPU.

The front end is plain HTML, CSS and JavaScript. I tested it at wide desktop, laptop, tablet and phone sizes, in light and dark. On a phone, once a listing exists, the listing comes first and the form folds away.

The CLI (src/repo.js) is a scanner, not a model: it reads files and finds bundle ids, display names, feature folders, screen files, README sections and screenshots (portrait images first, so it picks real screens over marketing art). Only then does Gemma turn that into a brief.

Why Does Open Innovation Matter?

Because the business only works if a listing costs almost nothing to write. A full listing for both stores in six languages is about 13,000 tokens in and 10,000 out. At DigitalOcean's Gemma 4 price ($0.18 per million input tokens, $0.50 per million output), that's less than one cent. A listing isn't written once: you rewrite it for every update, every season and every new market. At under a cent each, a $6 subscription has plenty of margin even for heavy users. On a frontier closed API the same job costs many times more, and the price is set by someone else.

Because developers don't want their unreleased app on someone else's server. Screenshots of an app that isn't out yet are sensitive. StoreScribe never stores them, and with --local Gemma runs on your own laptop: no API key, no account, no network. The same model that powers the hosted version runs offline, which is only possible because the weights are open.

Because the model is one setting. I developed and tested everything against Gemma on my Mac, for free, and deployed against Gemma on DigitalOcean without changing a line of the writing pipeline. If a better open model comes out, it's an environment variable. If I collect listings that convert well, I can fine-tune on them. None of that depends on one vendor's roadmap or pricing.

Where open didn't win: small local models are weaker at hitting exact lengths and at not repeating themselves. That's why the rules live in code, and why there are automatic rewrites. Once the code owns the rules, an open model is more than good enough for the writing.

My Agent Session

I built StoreScribe with Claude Code in one evening. Here's the session, from reading the challenge and picking the idea, through the CLI and the UI passes, to recording the demo video:

Building StoreScribe: App Store listings with Gemma 4, DigitalOcean, Tiger Data and SerpApi
You

ok fine keep it offline

now, a new week hackathon is happening: https://dev.to/challenges/hacktoberfest-week2-2026-10-12

let's participate in this with a competely new project

read all the details from tje webpage

I think the prizes and the categories are the same

let me know what ideas are you thinking of?

Agent
▸ ToolSearch select:mcp__devrelay-gateway__get_challenges,mcp__devrelay-gateway__get_chall...
select:mcp__devrelay-gateway__get_challenges,mcp__devrelay-gateway__get_challenge_details
You

Tool loaded.

Agent
▸ mcp__devrelay-gateway__get_challenges {"per_page": 10}
{ "per_page": 10 }
{"Ok":[{"id":82,"title":"Hacktoberfest Open-Source AI Challenge: Week 4","slug":"hacktoberfest-week4

I read the full details through DEV's challenge API. First, the timing:

Week 2 closes tonight at 11:59 PM PDT (06:59 UTC Oct 19). Assuming you're on India time, that's about 17 hours from now. It's doable, but only with a tight, small project. Week 3 starts tomorrow (Oct 19, 16:00 UTC) and gives a full week, but its theme isn't announced yet.

Week 2 in short. The theme is Side Hustle: build something with open-weight models or open-source AI that someone would actually pay for. The open part has to be what makes it work. The post should explain why open matters here: cost, privacy, fine-tuning for a niche, or avoiding lock-in. There are bonus points for landing a first user and telling them whether that person paid, would pay, or what they asked for next.
- Judging: writing counts most, then fit with the theme, creativity, technical execution, and use of a partner's tech.
- Prizes: the same as last week. $250 overall, six featured categories at $200 (Gemma, DigitalOcean, Render, TabPFN, Tinker, Arduino), and eleven partner categories at $100, now including a .tech domain. One win per person per challenge.
- To enter: use the Side Hustle submission temp …

Show more
You

her's the post template:

<pasted_content id="dd41">
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle

What I Built

<!-- What does it do, and who would pay for it? What problem does it solve for them? -->

Demo

<!-- Share a deployed link or a video demo. -->

Code

<!-- Show us the code! You can embed a GitHub repo directly into your post. -->

How I Built It

<!-- Which open-source AI did you use (open-weight models, agent harnesses, frameworks, local inference), and how is your project built around it? -->

Why Does Open Innovation Matter?

<!-- Why does open innovation matter for what you built? What did it make possible that a closed API wouldn't? -->

My Agent Session

<!-- Optional, but judges love it. Save your session with DevRelay and embed it with the agent_s …

Show more
Agent
▸ AskUserQuestion {"questions": [{"question": "Which idea should we build for tonight's Week 2 ...
{"questions": [{"question": "Which idea should we build for tonight's Week 2 deadline (11:59 PM PDT)?", "header": "Project", "multiSelect": 
Your questions have been answered: "Which idea should we build for tonight's Week 2 deadline (11:59 

Going with the shoot culler, and you'll be the first user. I'll check the local setup first.

▸ Bash Check Ollama models, Node, time, and folders
$ Check Ollama models, Node, time, and folders
(directory listing omitted)

I'll build it as Keeper, a local app you start with a folder of photos. Everything runs on the laptop with Gemma 4 through Ollama.

▸ Bash Scaffold the Keeper project and install deps
$ Scaffold the Keeper project and install deps
found 0 vulnerabilities repo name free
You

The user sent a new message while you were working:
what categories would this qualify in>

This is how Claude Code surfaces messages the user sends mid-turn — within the running turn, often alongside the next tool result, rather than as a separate conversation turn. Address the message above as you continue this turn.

[Request interrupted by user]

first allow do an assessment of which categories would be the easiest to win based on all th submission yet and from the last few weeks ones

based on that we might decide to change the prject idea

The user sent a new message while you were working:
what categories would this qualify in>

This is how Claude Code surfaces messages the user sends mid-turn — within the running turn, often alongside the next tool result, rather than as a separate conversation turn. Address the message above as you continue this turn.

[Request interrupted by user]

first allow do an assessment of which categories would be the easiest to win based on all th submission yet and from the last few weeks ones

based on that we might decide to change the prject idea

Agent
▸ ToolSearch select:mcp__devrelay-gateway__get_articles,mcp__devrelay-gateway__execute_dev...
select:mcp__devrelay-gateway__get_articles,mcp__devrelay-gateway__execute_dev_api_request,mcp__devrelay-gateway__get_article_content
You

Tool loaded.

Agent
▸ ToolSearch select:mcp__devrelay-gateway__get_articles,mcp__devrelay-gateway__execute_dev...
select:mcp__devrelay-gateway__get_articles,mcp__devrelay-gateway__execute_dev_api_request,mcp__devrelay-gateway__get_article_content
▸ Bash Fetch all #hf26challenge posts from the DEV API
$ Fetch all #hf26challenge posts from the DEV API
page 1: 100 page 2: 100 page 3: 100 page 4: 100 page 5: 100 page 6: 100 600 [{"d":"2026-10-15","n":1
▸ Bash Fetch remaining pages and count posts by date
$ Fetch remaining pages and count posts by date
2904 2026-10-01 2 2026-10-02 40 2026-10-03 122 2026-10-04 429 2026-10-05 337 2026-10-06 82 2026-10-0
▸ Bash Download bodies of recent posts and list devteam announcements
$ Download bodies of recent posts and list devteam announcements
The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file
You

[Request interrupted by user for tool use]

have youn stared the assessment yet??

[Request interrupted by user for tool use]

have youn stared the assessment yet??

Agent
▸ Bash Count partner mentions per week from tags and titles
$ Count partner mentions per week from tags and titles
week1: 1210 posts week2: 852 posts weekend: 842 posts category 

I counted mentions of each partner in the tags, titles and summaries of all 2,904 #hf26challenge posts:

Category (prize) Weekend Week 1 Week 2 so far
Gemma ($200) 107 194 151
TabPFN ($200) 9 16 19
GitHub Copilot ($100) 6 2 18
Render ($200) 4 5 10
Sentry ($100) 2 0 6
ElevenLabs, Entire ($100) 6 / 2 4 / 4 4 / 4
Tinker ($200) 1 2 3
DigitalOcean ($200) 0 1 2
Tiger Data ($100) 0 0 2
Temporal, MongoDB, SerpApi, .tech ($100) 1 / 3 / 0 / 0 5 / 3 / 1 / 0 2 / 2 / 2 / 2
Arduino ($200) 0 1 1

Week 2 has 852 posts so far, against 1,210 for Week 1.

Caveat: this undercounts, because most people list categories only in the post body, which I didn't download. The proportions are what matter, and they're very lopsided.

What this means:
- Gemma is crowded. About one in six posts mentions it, so it's the hardest category to win despite paying $200.
- DigitalOcean, Tinker and Arduino pay $200 and have almost no competition. Last week you won DigitalOcean against probably one or two other entries, likely inc …

Show more
You

prioritize the ones those qualify for this week first

Agent

Here are the Week 2 categories ranked by how winnable they are tonight. That weighs how many entries mention each so far, the prize, and whether we can use it properly in about 16 hours.

# Category Prize Week 2 entries so far Can we do it tonight?
1 DigitalOcean $200 2 ✅ Yes. Same setup as your win: Gemma on DigitalOcean's inference plus a Droplet
2 Tiger Data $100 2 ✅ Yes. Reuse the Leaf Peep account and setup
3 .tech domain $100 2 ⚠️ Possibly. It needs a .tech domain, which may come free through hacktoberfest.com/my. Worth checking
4 SerpApi $100 2 ⚠️ Only if search fits the idea. A listing writer could use it to look up competing apps' keywords
5 Arduino $200 1 ❌ Only if you have a board at home
6 Tinker $200 3 ❌ Fine-tuning takes too long for tonight
7 Temporal / MongoDB / Mastra / Backboard $100 1–2 each ⚠️ Possible, but each adds new setup work
8 ElevenLabs / Entire $100 4 each ⚠️ Moderate competition
9 Sentry / Render $100 / $200 6 / 10 ⚠️ More crowded
10 GitHub Copilot / TabPFN $100 / $200 18 / 19 ❌ …
Show more
You

can you actually check all the project body for the category they are participating for the ones those qualify for this week>

Agent

I'll download the full text of the 852 Week 2 posts, fairly slowly so DEV doesn't block us. Then I'll read each post's "Prize Categories" section.

▸ Bash Download full text of Week 2 posts with rate limiting
$ Download full text of Week 2 posts with rate limiting
 852 xargs: command line cannot be assembled, too long 0s 476 0 Shell cwd was reset 
▸ Bash Download remaining Week 2 post bodies with retry
$ Download remaining Week 2 post bodies with retry
The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file
You

[Request interrupted by user for tool use]

also I do have an ardunoi UNO q board at home

and what about these?

[Request interrupted by user for tool use]

also I do have an ardunoi UNO q board at home

and what about these?

Agent

You stopped the download, so I'll use only what's already on disk: 476 Week 2 posts whose full text was saved by the earlier attempt. No more requests to DEV.

▸ Bash Count claimed prize categories in cached Week 2 posts
$ Count claimed prize categories in cached Week 2 posts
bodies read 207; week2 submissions 163; with a filled Prize Categories section 80; none matched 31 D

I worked only from posts already saved on disk, with no new downloads. That gave 207 posts, of which 163 are Week 2 submissions and 80 list prize categories:

Category Prize Entries in sample Estimated across all Week 2 (×5)
DigitalOcean $200 0 ~0–5
MongoDB, SerpApi $100 0 ~0–5
Arduino $200 1 ~5
Tiger Data, Sentry, Temporal, Mastra, Backboard $100 1 each ~5
ElevenLabs, Entire $100 2–3 ~10–15
.tech domain $100 4 ~20
TabPFN $200 5 ~25
Tinker $200 5 ~25
GitHub Copilot $100 5 ~25
Render $200 7 ~35
Gemma $200 36 ~190

Arduino UNO Q is your best shot. It's a $200 featured category with almost no competition, and you have the board. Hardware also makes the post and demo memorable, which helps with writing quality and creativity, the criteria judges weight most. The UNO Q runs Linux next to its microcontroller, so it can run a small open model on the board itself. That's a strong "why open" story: no cloud, no monthly fee and private by default, which is exactly what this week's prompt asks about.

The othe …

Show more
You

let's just start with withoit wasting time:

The idea that fits these best: the App Store listing writer. It's a hosted subscription tool, so DigitalOcean is central rather than bolted on. Tiger Data keeps each app's listing history, SerpApi pulls competing apps' keywords, and it could live on a .tech domain. The culler is mainly a laptop app, so it only meaningfully uses Gemma, the crowded category.

let's just start with withoit wasting time:

The idea that fits these best: the App Store listing writer. It's a hosted subscription tool, so DigitalOcean is central rather than bolted on. Tiger Data keeps each app's listing history, SerpApi pulls competing apps' keywords, and it could live on a .tech domain. The culler is mainly a laptop app, so it only meaningfully uses Gemma, the crowded category.

Agent

Starting the build. It's called StoreScribe for now, and we can rename it later. I'll reuse the parts of Leaf Peep that worked: Gemma through DigitalOcean (with Ollama locally), Tiger Cloud and the deploy scripts.

▸ Bash Review Leaf Peep model and DB code to reuse
$ Review Leaf Peep model and DB code to reuse
// Scores a foliage photo with an open-weight vision model. // MODEL_API=ollama -> Ollama's native 
▸ Bash Create StoreScribe project and check deploy config
$ Create StoreScribe project and check deploy config
node_modules/ uploads/ .env .DS_Store .model_key .drafts/ backups/ 3:# ./deploy/up.sh G
▸ Bash Read Leaf Peep deploy scripts
$ Read Leaf Peep deploy scripts
#!/usr/bin/env bash # Creates (or reuses) the leaf-peep Droplet and deploys the app to it. # ./dep

I have what I need. Writing the backend now.

▸ Bash Set up package, Dockerfile, and .env without printing secrets
$ Set up package, Dockerfile, and .env without printing secrets
found 0 vulnerabilities FROM node:24-slim WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev C
You

The user sent a new message while you were working:
what quick ideas do you have for Ardunio Q which you think might win?

This is how Claude Code surfaces messages the user sends mid-turn — within the running turn, often alongside the next tool result, rather than as a separate conversation turn. Address the message above as you continue this turn.

Agent

I've paused StoreScribe. The setup is done but no app code is written yet, so switching now costs nothing.

The UNO Q is an Arduino and a small Linux computer in one: it has an 8×13 LED matrix, runs Debian and can run a small open model (Gemma 3 1B or 270M) on the board itself. Here are ideas that only need the board, plus your laptop or phone for setup:

  1. Billable hours box for freelancers (my pick). A little desk clock for side-hustlers who bill by the hour.
    • You pick a client in a tiny web page served from the board and start a timer. The LED matrix shows the client and running time, so you don't need another browser tab.
    • When you stop, you jot a quick note like "fixed login bug, call with Priya". The open model on the board turns the notes into clean invoice lines, then makes the week's invoice as a PDF or CSV.
    • Who pays: freelancers already pay $9–12/month for tools like Toggl and Harvest. This is a one-off device with no subscription.
    • Why open: client names and rates never leave the desk, and it keeps working with the Wi-Fi off. That's an exact match for the prompt's "keep your customers' data private" and "avoid lock-in".
    • **Feasibilit …
Show more
You

I think doing a hardware project in limited time qwould be a hazzle, continue with the one we started

Agent

Continuing with StoreScribe. I'll write the model layer first: one wrapper that works with both Ollama locally and DigitalOcean's inference in production.

▸ Write ~/MobileDev/storescribe/src/model.js
~/MobileDev/storescribe/src/model.js
File created successfully at: ~/MobileDev/storescribe/src/model.js (file state is current in your co
Source:https://dev.to/sbis04/storescribe-an-open-model-writes-your-app-store-listing-inside-every-limit-1lck

Related posts