Rosewood is built in Kotlin with Compose Multiplatform: the UI, the domain logic and the tests are written once and ship to both stores. Product research, PRDs, the design system, store copy and manual test plans are produced through agentic workflows and live in the repository next to the code they describe. The agents plan and execute; I gate releases and fix what breaks.
A single module. Everything new goes into commonMain; platform APIs sit behind expect/actual seams only where they must: Play Billing and StoreKit, notification scheduling, the audio device, DataStore. The domain layer knows nothing about either platform, which is why most of the tests live there.
An architect agent writes each feature as a PRD and an execution plan. An executor works the plan task by task on a feature branch, appending to an append-only ledger after every task; the ledger is the only status. Compile is a hard gate, tests a soft one, two fix attempts maximum. Market research, the monetization PRD, the analytics metric dictionary, store copy in 26 locales and the manual test plans came out of the same flows. Tooling: Claude Code, Gemini CLI, custom agents, Fastlane, an own analytics backend and crash reporting.
The note you hear is synthesised, not sampled: a plucked-string model rendered per note in a few milliseconds, one voice, the same sound on a hit and a miss. The board's light tracks a ten-answer window with hysteresis, so one miss never takes back a level you earned. Contrast tests fail the build when an ink drops under its floor. Fret spacing follows 1 − 2−n/12.
Compose Multiplatform carries the UI and the logic; StoreKit, notifications and the audio device sit behind expect/actual. The parts that were new to me, Xcode, App Store Connect, the review process, were a matter of asking the right questions of the agents. For a team building the same product for two platforms, I think this is the right bet.
One release shipped with no Next button in landscape. A customer email found it before I did, and the fix went out the same day, but retention took the hit. The rule that came out of it is now the second line of the repository's instructions: a change to landscape is not done until portrait is checked, and the reverse.