Engineering note

An environment for sustainable app development

Apps already shipped have to keep working, keep passing review and keep being worth opening — at ten of them and at a hundred.

Updated 2026-09-02 · iOS · macOS · Android · Web

01The system

One workspace holds six domains, and each app uses its own repository. The shared code, the release lanes and the conventions belong to none of them and are kept separately.

Roughly 120 apps are live across the four platforms. iOS releases run from one shared lane; the Android side ships from a Flutter monorepo.

Projects by domain169
Android (Flutter)
114
iOS
30
Web services
13
Games (LÖVE)
9
macOS
3

Project directories in the workspace, counted 2026-09-02. Live store listings are a smaller number — an app can be built and not yet submitted.

How the cost of keeping them grows
copied into every appone shared foundation
cost to keep them →apps shipped →what one person can carry

02Shared and per-app

The parts no app needs to build again — payment, analytics, review prompts, localization, privacy handling — live in shared packages. Fixing one of them fixes it everywhere that uses it.

What people actually look at is not shared. Features, the design system the screens are built from, artwork and the app’s own content are written per app. Backends follow the same split: each app has its own, and takes only the common parts from one shared module.

per appshared with nothing
Features
Design system
Artwork
Content
sharedPaymentAnalyticsReview promptsLocalizationPrivacy

The same code under all of them.

03Releases

A release is a build, screenshots, store metadata in 26 languages, and a submission. All of it is handled through the official store APIs rather than a browser.

There is no deploy script per app; they share one lane. Per-app values are not restated but read from the files that already hold them. Two steps stay with a person: checking the build on a real device, and pressing release.

01
Build
signed, versioned
02
Screenshots
every required size
03
Metadata
26 languages
04
Submit
store APIs, not a browser
you
Release
a person decides
Done by a person
Device check
a simulator confirms the code runs; it does not report a gesture that feels wrong or a layout that collapses on real hardware
Release
store approval is a permission, not a schedule — the build waits until it is released by hand

04Measurement

Keyword rank is collected per app and per country every day and read as a series. Usage events go to a collector of our own, which puts an app’s iOS and Android side by side.

Keyword rank
Can it be found, and for what?
per app and country · snapshotted daily on the server
Acquisition & ads
What do the ads return against what they cost?
collected daily from the stores and AdMob
In-app behaviour
What do people do after installing?
our own collector · aggregated in the in-house SaaS

05Infrastructure

The in-house services all ship as Docker images: keyword ranking, usage analytics, ad metrics, reports, the GPU jobs that generate assets, and the console that operates all of it. One service is one image, so moving or restoring one is the same job as adding a new one.

Builds and deploys are handled by CI, and server state is collected continuously so that anything going wrong raises an alert.

Shared stack
Go 1.26chiReact 19TypeScriptViteTailwind CSSTanStack QueryDocker
Running as Docker images
reverse proxyadmin consoleASO & reportstrend collectorad metricsaffiliate linkscommerce syncLLM gatewaycontent studioGPU asset jobsdatabases

06Agents and conventions

The repetitive work runs on agents: release mechanics, metadata updates across 26 languages, the sweep that checks every app against a policy change.

What an agent follows is written down as a skill. 44 skills and 27 agents are versioned in the same repository as the code they act on, and a convention file per domain carries the rules that hold everywhere in it. Store behaviour that has caught us before ends up here as steps.

work/
CLAUDE.mdone per domain — the rules that outrank any prompt
.claude/skills/a written procedure per job
ios-releaseios-paywallios-testweb-saas-bootstraplove-bootstrap+39 more
.claude/agents/the thing that runs them
pentarab-routermac-appboard-builderweb-infra-admin-backend+24 more