StoreScribe: an open model writes your App Store listing, inside every limit Developer Souvik Biswas built StoreScribe, an MIT-licensed open-source tool that generates App Store and Google Play listings using the open-weight Gemma 4 model, enforcing store character and byte limits in code rather than relying on the model to count. The tool reads a project's Info.plist, pubspec.yaml or app.json, README, screen names and fastlane metadata via a CLI, then writes finished listings into fastlane/metadata in up to six languages, with a --local mode running Gemma through Ollama so nothing leaves the machine. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle https://dev.to/challenges/hacktoberfest-week2-2026-10-12 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: 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: 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. Try it: storescribe.souvikbiswas.com https://storescribe.souvikbiswas.com no sign-up 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 https://storescribe.souvikbiswas.com · Demo video https://youtu.be/tMNuL2SRbiA · CLI https://github.com/sbis04/storescribe cli 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. Your listing, inside every limit. A live App Store preview with your screenshots, and a counter on every field. Each language … MIT licensed. Everything in the demo is in the repo, including the deploy scripts. 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. 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. 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: The first user is me, with AeroTail , the plane-spotting iOS app I'm building. I ran the CLI inside a copy of the AeroTail repo. It found the display name and bundle id in the Xcode project, read the feature list in the README, picked up 21 screens from the Swift code capture flight, collection, flight search, watch map and more and the onboarding screenshots, all without me typing a word. Two minutes later, on my laptop with no internet calls, it had written 24 fastlane files: App Store and Google Play listings in English, Japanese and German. In the web app, the research found exactly the apps I'm up against: Flightradar24, FlightAware, Flighty and Plane Finder. Did it beat the listing I'd have written myself? Yes, definitely. Would I pay $6 a month for it? Yes, it's definitely worth it. deploy/up.sh , and every listing on the live site is written by Gemma 4 on DigitalOcean serverless inference.