UEMA
How it works

Six stages, one of which needs you

Crawl, approve, compile, run, verify, ship. Only the second is interactive — and it is the one where a model touches your content at all.

The loop, in full

The model is used for judgment — what is this DOM region, which block does it map to — and never for mechanics: string transformation, file writes, path handling. That split is why a defect found on page 4,312 is fixed in the compiler and therefore fixed for all ten thousand, as a failing unit test rather than a re-roll of a stochastic process.

uema.app/workspace
acme.com/pricing PARITY

Captured page

No confident block match

Regions → blocks

  • Hero0.96
    heroExact match
  • Feature grid0.94
    cardsExact match
  • Logo strip0.81
    logo-cloudVariant
  • Comparison table0.42
    —Needs a new block
  • Footer CTA0.98
    ctaExact match

One model call per cluster — never per region.

01

Connect a project

Point UEMA at the site you are migrating and the git repository it is migrating into.

  1. 1

    Name the source and the target

    A project is one migration: a source URL, a git remote and branch, a target (Edge Delivery or AEM Cloud Service) and a budget. Three fields are mandatory and marked as such — the tenant, the source URL and the git remote.

  2. 2

    Pick a mode

    PARITY reproduces the source as closely as possible. DESIGN_SYSTEM maps everything into a library you already have and refuses to invent a block that is not in it. HYBRID lets the two coexist per region, which is what most real migrations need.

  3. 3

    Connect GitHub

    A GitHub App installation gives UEMA short-lived, per-push tokens. The API never holds a private key, and a push opens a pull request rather than committing to your default branch.

uema.app/cockpit

Cockpit

How far the migration has got, and what it has cost.

10,412

Discovered

9,884

Verified

9,102

Published

528

Excluded

Budget

On budget

$18.40 / $2,500.00

Spend comes from the exemplar passes you asked for, not from page count — the bulk run makes no model call at all.

Verification gates

  • Content parity Pass
  • Visual diff Pass
  • Links Pass
  • Accessibility Pass
  • Performance Pass
  • SEO preservation Pass
  • Structural sanity 12 to review
02

Crawl the source site

Capture the pages as a browser sees them — no export, no plugin, no vendor tool.

  1. 1

    Queue an ingest job

    Start it from the workspace and the job is queued in the database with a scope and a page cap. Nothing claims it automatically — the runner is a local process, because a few hundred megabytes of headless Chromium doing a batch job is the wrong thing to put on a web service.

  2. 2

    Run the ingest runner

    One command, pointed at your deployment. It claims the job, drives real Chromium over the site, respects robots and the scope you set, and completes the job with the captured documents.

  3. 3

    Watch it in the Cockpit

    Discovered, verified, published and excluded counts, live. Excluded is not a failure — it is deliberately out of scope, and collapsing the two would misreport how complete the migration is in the direction that flatters it.

uema.app/workspace
acme.com/pricing PARITY

Captured page

No confident block match

Regions → blocks

  • Hero0.96
    heroExact match
  • Feature grid0.94
    cardsExact match
  • Logo strip0.81
    logo-cloudVariant
  • Comparison table0.42
    —Needs a new block
  • Footer CTA0.98
    ctaExact match

One model call per cluster — never per region.

03

Approve one to three exemplars

The only step where a model touches your content, and the only one that needs your judgment.

  1. 1

    Open a page in the Workspace

    The canvas shows the captured page, the regions detected in it, and the block each region was mapped to. Regions are found deterministically and then clustered; a model is asked what a cluster is — one call per cluster, never per region.

  2. 2

    Correct what is wrong

    Each mapping arrives as an exact match, a match with a variant, a request for a new block, or unsupported — each with a reason. Fixing one here is fixing it for every page in that cluster.

  3. 3

    Approve the template

    Approving is the human gate. It is what tells the agent this pattern is understood well enough to write a compiler for.

uema.app/cockpit

Cockpit

How far the migration has got, and what it has cost.

10,412

Discovered

9,884

Verified

9,102

Published

528

Excluded

Budget

On budget

$18.40 / $2,500.00

Spend comes from the exemplar passes you asked for, not from page count — the bulk run makes no model call at all.

Verification gates

  • Content parity Pass
  • Visual diff Pass
  • Links Pass
  • Accessibility Pass
  • Performance Pass
  • SEO preservation Pass
  • Structural sanity 12 to review
04

Let the compiler run the rest

Deterministic, parallel, resumable — and it makes no model call at all.

  1. 1

    The agent writes an importer

    From the approved exemplars, it produces a deterministic TypeScript module with fixture tests. You approve that too — the template and the importer are approved separately, because the pattern being right and the code being right are different claims.

  2. 2

    The module runs over every remaining page

    Not the model. That is the whole economic argument of the product, and it is enforced by the dependency graph: the packages that do this work cannot reach a model call.

  3. 3

    Fix defects in the compiler, not the output

    A problem on page 4,312 becomes a failing unit test in the importer. Fix it once and it is fixed for all ten thousand — reproducibly, and reviewably.

uema.app/review

Review queue

What the gates could not clear on their own.

12 open
  • /pricing/enterpriseStructural sanity

    Comparison table matched no block above the confidence floor

    Approve Waive with reason
  • /about/leadershipVisual diff

    Visual diff 4.1% — headshot grid reflowed at 768px

    Approve Waive with reason
  • /resources/2019-reportLinks

    3 outbound links resolve to 404 on the source site

    Approve Waive with reason

Every decision records who made it and why, in an append-only table.

05

Pass the gates, clear the queue

Eight blocking checks, and a human on whatever they could not settle.

  1. 1

    Seven gates run

    Content parity, visual diff, links, accessibility, performance, SEO preservation and structural sanity. Each is a gate rather than a report: a page that fails one does not proceed with a warning attached to it.

  2. 2

    Work the review queue

    What the gates could not clear alone arrives ranked by what is uncertain about it — a region with no confident block match, a broken link, a layout that shifted.

  3. 3

    Your decision is recorded

    Approving or waiving writes an append-only resolution carrying who you are and why. The decision is the artifact; removing the row is just what happens next.

uema.app/code
migration/pricing 7 / 7 gates

Emitted files

  • blocks/hero/hero.js
  • blocks/hero/hero.css
  • blocks/cards/cards.js
  • content/pricing.md
  • content/legacy-promo.md

A deleted path keeps its prior content until the next emission, so you can stage the deletion.

Diff against migration/pricing

blocks/hero/hero.js
  export default function decorate(block) {-   block.classList.add('hero-legacy');+   const [picture, text] = block.children;+   picture?.classList.add('hero-media');+   text?.classList.add('hero-body');  }
Stage 4 files Open pull request
06

Review the diff and open the PR

What you review is the commit itself, not a rendering of an intention.

  1. 1

    Emit

    Assembly runs inline — it is pure CPU over rows already in the database and makes no model call by construction, so there is no queue to wait on. Emitting zero documents is refused rather than stored, because an empty set would read as 'the migration produced nothing'.

  2. 2

    Read the diff

    Every emitted file against what is on your branch. Deletions stay visible with their prior content until the next emission, so you can see and stage them rather than discovering them later.

  3. 3

    Push

    Stage what you want, and UEMA commits, pushes and opens a pull request — or updates the existing one on that branch, which is what a re-emission should do.

Concretely

The crawl is one command

The ingest runner is deliberately not deployed. It drives headless Chromium, and a few hundred megabytes of browser doing a batch job is the wrong thing to put on a web service — so it runs on your machine, against your deployment.

A job sits queued until something claims it. Nothing claims it automatically — which is a design decision, not an omission.

start a crawl
cd packages/ingest-runner

UEMA_API_URL=https://your-api.example \
  npx tsx src/main.ts --ingest <siteId> https://acme.com
watch it land
curl -s https://your-api.example/projects/<id>/stats \
  -H "authorization: Bearer $TOKEN"

# { "discovered": 10412, "verified": 9884,
#   "published": 9102, "excluded": 528 }

See it run against a real site

The quickest way to judge this is a working session on one of your own templates, not a page of prose describing one.