Writing / Article
A Year Building UMA Companion: Why I Sunset the Project
A project that grew from a card manager into a full application, and the decision to stop maintaining it.
On this page
UMA Companion is now archived. I want the reasons written down while they are fresh, because ending a project deliberately is as much a part of the work as starting one.
The problem
It began as a support-card manager for Uma Musume: Pretty Derby. Cards, skills and scenarios interact, so choosing a deck got hard to do from memory. Showing the cards was the easy part. Choosing the best six under real constraints was the hard part.
Version one
A local-first Python desktop app. It started on CustomTkinter and moved to PySide6 for better rendering and drag-and-drop deck building, with SQLite holding the catalogue and the user’s own data.
Version two
A rewrite with a Rust core and a TypeScript/TSX interface. It split application code, catalogue data and user data apart, shared one local collection across views, and added a web platform.
The optimiser
This was the most demanding feature: a beam search over six-slot decks, weighing owned and borrowed cards, scenario requirements and interacting effects. The lesson was that a convincing-looking answer is not the same as a correct one. Scoring had to be explainable and results validated.
OCR and live capture
Screen capture and OCR were an attempt to bring game state in without typing it. Recognition output is uncertain, so it was treated as data needing validation, never as clean input.
Data and releases
An early bug could wipe local saves when the SQLite database was replaced. The fix was structural: the executable and a catalogue data pack became separate, and the merge keeps user tables. Scraping moved out of the app into maintainer-side Playwright jobs on GitHub Actions, because shipping a scraper to users was unwieldy.
Why I stopped
In 2026 the official Japanese version added more in-game guidance. The optimiser stayed distinct, but the maintenance across the frontend, backend, OCR, data pipeline, website and releases no longer matched what was left to gain.
What I’m taking from it
- Architecture emerges through use, so a rewrite that captures earlier lessons can be worth it.
- Optimiser results need evidence, not just a convincing look.
- Messy inputs such as OCR and shifting game data push designs toward explicit boundaries.
- Ending a project can be the sound product decision.
The archive stays up as a record. It is a deliberate outcome, not a failure.