Wemora

React web app → Expo mobile app

Port the app. Prove every screen.

Wemora rewrites a React single-page app as an Expo app, one screen at a time. A screen gets into the app only after the tests written against the web original pass on the phone build, unchanged.

View on GitHub
$ npm run migrate -- examples/recepti
Original · web · 1280×800passes
localhost:5173/kupovina
ReceptiReceptiKategorijeOmiljeniLista za kupovinu

Lista za kupovinu

Dodaj
KupljenoNamirnica
☐Hleb
Kupljeno: 0 od 1Obriši kupljene
tests/shopping-list.jsonadd-item
  1. goto /kupovinaweb ✓app ✓
  2. fill "Namirnica" = "Hleb"✓✓
  3. tap button "Dodaj"✓✓
  4. expect "Kupljeno: 0 od 1"✓✓
  5. expectNot "…je prazna"✓✓
written by the tester on the web5/5 on both
Expo · phone · 390×844passes

Lista za kupovinu

Namirnica
Hleb
accessibilityLabel
Dodaj
☐Hleb
Kupljeno: 0 od 1
ReceptiKategorijeOmiljeniKupovina

Layout is free to change: the sidebar becomes a bottom bar and the table becomes a card. Field labels, button names and visible text stay the same, so the web test finds everything on the phone.

A real run

The same steps on the original and on the app Wemora built.

TodoMVC, recorded in a browser. Three todos are added with Enter, one is completed, the filters switch and completed todos are cleared, using the same field label, link names and button text on both.

Original · web
localhost:7002/#/
Wemora appproven

From npm run migrate:mock -- examples/todomvc: builder answers are recorded, while the Gatekeeper, the tests and the app are real. todo-list: proven in round 2, 5 of 5 tests on the phone build. Fonts, sizes and colors come from the web CSS through the shared theme.

How a run works

Agents write the code. Tests decide what stays.

Each step is a Mozaik participant. Agents get a fresh context per task, events carry only IDs, and the shared board holds the plan, tests and results.

  1. Analyze

    Parse routes, imports and web-only APIs, then describe every screen with its exact texts.

    analyzer · haiku-4-5
  2. Plan

    Split the app into screens and shared units, with obligations each screen must still meet.

    architect · sonnet-4-6
  3. Scaffold

    Create an empty Expo app with one route per screen and blank placeholder screens.

    scaffold
  4. Test

    Write scenarios on the original. A test is kept only if it passes there and fails on the blank screen.

    tester · haiku-4-5
  5. Build

    Rewrite each screen in React Native, in its own staging folder. Builders never see the tests.

    builder · haiku-4-5 → sonnet-4-6
  6. Gatekeeper

    Check every draft, promote it into the app, and roll it back if an older screen breaks.

    deterministic · no model

The Gatekeeper

Five gates, in order. The first failure goes back to the builder.

Every message names the file, the line and what is missing, so the next round fixes that one thing instead of starting over.

  1. 1parseThe draft is valid TypeScript. One syntax error would take down every screen.
  2. 2forbiddenApisNo div, window, localStorage or react-router-dom, with the React Native replacement for each.
  3. 3tscThe draft type-checks against the rest of the app.
  4. 4labelsEvery label and button name the tests use is in the code, copied from the original.
  5. 5scenariosThe tests pass on the phone build, then the tests of every promoted screen run again.
output/…-todomvc/run.jsonlTodoMVC · todo-list
builder-1   draft.submitted   todo-list  round 1
gatekeeper  gate.failed       todo-list  round 1
forbiddenApis
screens/todo-list/index.tsx:19: <div> ne postoji u React Native, koristi <View>.conductor   same builder, round 2, with the message above
builder-1   draft.submitted   todo-list  round 2
gatekeeper  parse ✓ forbiddenApis ✓ tsc ✓ labels ✓
gatekeeper  scenarios ✓  5/5 at 390×844
gatekeeper  unit.promoted     todo-list  status proven

From a TodoMVC run. Gate messages are written for the builder; the team wrote them in Serbian.

What the report claims

Every screen gets one of four statuses.

proven

All tests pass on the phone, every obligation is covered, and every interactive element is tested or marked as not portable.

partial

All existing tests pass, but some obligation or element has no test yet. The report lists which.

unproven

The screen is in the app, but no validated test exists for it.

failed

Tests exist and the screen still fails them after its last round.

A screen with zero tests is never proven.

Check it yourself

Rerun the proof without a model or an API key.

$ npm run migrate:mock -- examples/todomvc

The whole flow with recorded model answers. Costs $0.

$ npm run verify -- output/<run-id>

Runs every saved test against the finished app again. Same result every time.

$ npm run sabotage -- output/<run-id> recipe-list

Breaks one screen on purpose, so you can watch verify catch it.

Built on Mozaik

Many small agents, one shared board.

  • Builders write only to their staging folder. An OwnershipGuard intercepts every write outside it before it happens.

  • Only the Gatekeeper writes to the app. Promotion is a copy, and rollback restores the exact previous files.

  • One loop per agent, fresh context per task. Parallel work comes from more builders and testers, scaled to the size of the app.

  • Events carry IDs. Plans, tests and results live on the board and on disk, so every run can be replayed and reported.

Team

Four people, four layers.

A

Luka Javorić

Contracts, runtime and the Conductor that hands out work and scales the team.

B

Nebojša Vujić

The test language, the tester agent, verify and sabotage.

C

Milica Antić

The Expo template, scaffold, the builder agent and the Gatekeeper.

D

Milomir Kuzmić

App analysis, the architect agent and the report.