A new Android project,
already wired up.
Multi-module Compose with MVI, Hilt and Ktor. Four build environments, signed release output, a design system with no Material dependency, and a catalog app that shows every component. Pick what you want, get a zip that compiles.
No sign-up, nothing stored, no email. The zip is built when you click and streamed straight back.
This is beta. Every combination is compiled, tested and linted in CI before it ships, but not many people have used it yet. If something breaks, the button in the corner sends a report straight to whoever can fix it — and it attaches what you configured, so you do not have to describe it.
$ ./gradlew :app:assembleDevDebugBUILD SUCCESSFUL in 1m 4s$ ./gradlew buildcompiles 7 variants · unit tests · detekt · android lintBUILD SUCCESSFUL in 7m 14s$ ./gradlew :app:distDevReleaseMyApp-devRelease-arm64-v8a-1.0.0-1-20260904-1048.apkMyApp-devRelease-universal-1.0.0-1-20260904-1048.apkchecksums.sha256
Each removes a module, not just code
An androidx.compose.material import fails the build
dev / staging / prod / playstore × debug / release
Open it and press run
This part is not optional
Everything below arrives whatever you tick. It is the reason the template exists, and the part that would take a fortnight to assemble by hand.
A design system with no Material
verifyComposeUsageBuilt on androidx.compose.foundation and ui alone. Its own ripple, type scale, 80-odd components, date and time pickers, bottom sheet, charts and a hand-drawn icon set. An androidx.compose.material import fails the build, so it cannot drift back in.
One place for the look
AppThemeColour, type, spacing, shape, elevation, motion and haptics are composition locals read through AppTheme. Changing the font is one string, a brand colour is one hex and the ramp around it follows, and how every control answers a finger is one enum.
Navigation nobody has to coordinate on
Navigation 3A feature registers its own screens through Hilt multibinding. Adding one touches no file outside its module — there is no central sealed Route to extend and no when in :app to add a branch to, so two people adding screens in the same week do not conflict.
Per-tab back stacks
AppShellSwitching tabs and coming back returns the user where they were. Re-tapping the active tab pops it to its root — the gesture everyone uses and nobody is told about.
Seven build variants
AppFlavordev, staging, prod and playstore across debug and release, minus playstoreDebug which does not exist. Only the app modules carry flavours, so switching environment rebuilds nothing in core, data or feature.
Release artifacts that are already named
build/outputs/distdistProdRelease gives per-ABI APKs plus a universal one, stamped with variant, ABI, version and build time, with a checksums file beside them. The bundle is a second task, because AGP refuses to build both at once.
Layering the build enforces
verifyModuleDependenciesfeature → feature and data → data fail the build rather than a code review. The rule that keeps a module graph acyclic is the one that stops being followed the week everyone is busy.
MVI that cannot interleave
MviViewModelEvents are queued and drained in order on one coroutine, so two of them cannot land between a read and a write of the state. LoadState is sealed, so there is no way to represent loading and errored at the same time.
Loading the options from the generator…
Questions
Is the project it gives me actually going to build?+
Yes, and that is checked rather than asserted. The template in the repository is a real Gradle project that this repository's own build compiles, tests and lints on every change — and both extremes of the generator, everything on and everything off, are built the same way. If a combination broke, the repository would be red before you got here.
Why no Material?+
Material is a brand as much as a toolkit, and a design system built on it inherits both. Owning the components means the theme is the only thing that decides how anything looks: one hex changes every accent, one string changes every text style, one enum changes how every control answers a finger. An androidx.compose.material import fails the build, so it cannot creep back in.
What if I want a feature I turned off?+
Turning one off deletes its module rather than commenting it out, so adding it back means generating again or copying the module from the repository. Feature modules are different — add_feature.py scaffolds a new :data: and :feature: pair into a project that already exists and makes the three edits people forget, and remove_feature.py takes one back out again, including those same three edits.
Why don't I get signing keys?+
Because they would have been generated on a server you do not control and sent back to you over the wire. That is fine for a throwaway debug key and not fine for a Play upload key, which is the one credential in Android whose loss cannot be undone. The CLI generates all four, on your machine, with keytool.
Do you keep anything I typed?+
The app name, package, and which features you picked, so the popular ones can be made defaults and the unpopular ones deleted. No IP address is stored — visitor counts use a salted hash, and rotating the salt forgets who visited without losing the numbers. No cookies, no third-party analytics, and the generated project is never written anywhere but a temporary directory that is deleted as the download finishes.
Can I run this myself?+
All of it. The generator is a Python script with no dependencies, the API is one Go binary, and this site is a Next.js app. Everything is MIT.
Who made this
Sarthak Tripathi
Android developer. This started as the setup work at the front of every new project — the modules, the variants, the design system — done once properly instead of badly every time. It is all open source; issues, pull requests and arguments about the architecture are welcome.