Kanora
Kanora
All dispatches
Architecture

From Scattered Repos to a Platform

June 27, 20267 min readBy Ben Reed
kanoraarchitectureworkflow

Kanora started as one app: a macOS music manager for people who wanted to own their library instead of renting it. That app grew up well. It has a written constitution, a living wiki the coding agents read before they touch anything, a set of skills that encode how we build, and a trail of feature specs going back well over a year. If you dropped a new contributor, human or AI, into the Apple repo, they could get their bearings quickly because the repo taught them.

Then Kanora became more than one app: a web player for a Raspberry Pi kiosk, a spatial remote for Quest that overflows your record collection into the room, a native Android panel for the headset, and the marketing site. Each one had its own repository, toolchain, and corner of my disk. On paper, it was a suite. In practice, it was a pile of repos that happened to share a name.

The step just taken was to turn that pile into something closer to a platform.

What forced the issue

Two things made the cracks obvious, and they pulled in opposite directions.

The first was the design system. It quietly proved itself. The same tokens, type, and spacing turned up across the apps and held the look together, doing exactly what a design system should do. But it lived inside the Apple repo, in a folder called design_handoff. The thing every app depended on for visual consistency was buried in one of them.

The second was onboarding a new app. This is where it hurt. The Apple repo had so much maturity - constitution, wiki, skills, specs, handover packs - that it set a bar the newer projects came nowhere near. Quest and the Quest panel were real code doing real work, but as projects they were thin: a README, maybe a stub wiki, no shared rules to inherit, no big-picture context to read. Starting work in them was hit and miss. The maturity in the Apple repo did not transfer by osmosis, so every new app started from near-zero and the gap between "the mature one" and "the new ones" kept widening.

The trigger, really, was adding companion apps. One mature app can carry its own context. A suite of five cannot run on the assumption that everyone already knows how the Apple app does things.

BeforeMature appApple repoconstitution, wiki, skills, specsThinWeb kioskclient repoThinQuest XRUnity repoTangledQuest panelinside Quest repoThinWebsitesite repo

Five repositories shared a product name, but only the Apple app carried the full working context.

What changed

The new shape is hub and spoke. A kanora hub repository now sits at the top, and each app is pulled in as a git submodule under apps/. The hub does not contain app source; it holds the shared, overarching knowledge and pins each app at a known commit. Each app stays its own repo, with its own history and CI.

That gives Kanora one place for the product-level material: the constitution, the vision, the repo map, the wiki conventions, the design system, the Companion API overview, and the git workflow for working across submodules. The apps then keep their own constitutions, wikis, skills, verification gates, and platform-specific rules.

Two shared contracts now bind the suite together. The Companion API is the functional contract: the Mac app owns the library and exposes the local API that the other clients consume. The design system is the visual contract: the shared way Kanora looks and feels across Apple, web, Quest, and the site. One explains how the apps talk; the other explains why they still feel like one product.

Hub repokanoraconstitution, vision, wiki, designAppApplehost + APIAppWeb kioskPi clientAppQuest XRspatial clientAppQuest panelnative panelAppWebsitepublic siteCompanion APIgit submodules pin each app at a known commit

The hub holds shared knowledge and pins each app, while the Companion API remains the functional contract between the host and clients.

On top of that skeleton, a few things landed together.

A product constitution and vision now sit at the root. The constitution holds the non-negotiables for the whole suite: the user owns their library, data integrity comes first, security comes first, the Companion API is a shared contract, and meaningful work starts with a plan. Each app keeps a slim constitution that inherits from it and adds only its platform-specific rules.

The wiki structure is now common. We took the Apple app's wiki, which had become the gold standard, and made it the template: index, overview, architecture, decisions, models, roadmap, a running log, plus handover, issues, plans, reports, and the small automation around them. Apps that had a partial wiki were brought up to that shape; the marketing site, which had none, got a full one.

There is also a real entry point for agents. The root now has KANORA.md, AGENTS.md, and CLAUDE.md that route any session: understand the whole product first, then drop into the specific app. There is a documented "where am I working?" table and an authority order, so an agent knows whether it is touching the host, a Companion API client, the Quest Unity app, the native panel, or the site.

The design system moved out of the Apple repo into a root-level design/ directory, peer to apps/ rather than buried inside one application. The workspace also works as an Obsidian vault now. The wikis already used [[wikilinks]]; pointing Obsidian at the root turns hub and spokes into one browsable knowledgebase with a graph across them.

We also did some plain housekeeping along the way. The native Android panel had been living inside the Quest Unity repo, which meant two very different toolchains were tangled together. It is now its own repo, a peer of the others. The decisions behind the restructure are written down as ADRs, so the next person does not have to reverse-engineer why the workspace looks this way.

What this unlocks

The point of this work is not tidiness for its own sake. It changes what is easy.

New apps now onboard against a template instead of a blank page. There is a known structure, a set of rules to inherit, and a context document to read. The capability gap between a brand-new app and the mature one closes because the new one starts with the same scaffolding the old one earned over a year.

The whole product is navigable. An agent or a person can start at the root, understand how the pieces fit, and then go deep in exactly one app without losing the plot. Most changes in a suite like this ripple: a Companion API tweak touches every client; a design token touches every screen. Those ripples are now visible as contracts instead of surprises.

Step 1RootKANORA.mdStep 2Productconstitution + visionStep 3Routechoose the appStep 4Appconstitution + wikiStep 5Updatecode + log

The path is the same for a person or an agent: understand the whole product, then go deep in exactly one app.

The shared things also have homes. The Companion API and the design system are named, documented, and discoverable as product-wide contracts rather than things that happen to live in whichever app created them first.

It is reproducible, too. One recursive clone reconstructs the workspace at a known state, with the hub pinning each app's commit.

What I learned

Maturity does not spread on its own. The Apple repo being excellent did nothing for the new apps until we made the implicit explicit by writing down the constitution, wiki conventions, templates, and entry points. Good practice has to be encoded before it can travel.

A multi-app product is held together by a small number of contracts. For Kanora, that is the Companion API and the design system. Name them, give them homes, and a lot of the chaos organizes itself around them.

The hub should reference, not duplicate. The source of truth stays with the code it documents; the hub links to it. The moment you copy a doc up, it starts drifting.

The knowledgebase is part of the product. Structure matters for the humans working on Kanora and for the agents increasingly doing that work. Treating docs as an afterthought is how you end up with one great repo and four that cannot keep up.

What is next

I am not going to pretend it is finished. The skeleton is in place and the laggards are caught up structurally, but several of the newer wikis are still thin and need filling in with real content. The Unity side of the design system mapping is not documented yet, and there is a backlog of small follow-ups behind these changes.

The hard part was going from a pile of repos to a platform with a spine. That is now in place, and Kanora is easier to understand as the suite it has become.