Agent-Driven UI Framework Migration at Enterprise Scale

block · Tech · 2026 · source Agentic: yes · promotional bias: low · source-backed · extracted with prompt 0.5.2 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Enterprise UI migration

Block needed to migrate a large React monorepo from Base Web to Fluent UI without a freeze window or mass manual rewrite.

Constraints:

Architecture

Block's UI migration system is a validated agent program built around TypeScript intelligence and repeated feedback. A TypeScript language-service/diagnostics server provides definitions, references, diagnostics, file selection, and test execution; Goose and later runtimes select files, build prompts, and let a model call the server's tools; import-rule DSLs define done states; selective context injects only relevant component hints; custom AST linters encode repeated failure modes; worktrees, tests, progress tracking, and a temporary Fluent migration lane let product teams migrate gradually while development continued.

Diagram confidence: explicit (topology described by the source).

flowchart LR
  react-monorepo[React monorepo] --> migration-runtime[Migration runtime]
  migration-runtime --> typescript-diagnostics-server[TypeScript diagnostics server]
  migration-runtime --> selective-context-injector[Selective context injector]
  selective-context-injector --> component-hint-library[Component hint library]
  component-hint-library --> import-rule-dsl[Import-rule DSL]
  migration-runtime --> coding-model[Coding model]
  coding-model --> validation-loop[Validation loop]
  typescript-diagnostics-server --> validation-loop
  import-rule-dsl --> validation-loop
  custom-ast-linters[Custom AST linters] --> validation-loop
  validation-loop --> temporary-fluent-lane[Temporary Fluent lane]
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
React monorepo Console codebase with Base Web surfaces to migrate. Migration runtime
TypeScript diagnostics server Language-service backend for definitions, references, diagnostics, file selection, and tests. Migration runtime, Validation loop
Migration runtime Goose and later orchestration layers that select files, build prompts, and invoke the model. React monorepo, TypeScript diagnostics server, Selective context injector, Coding model
Selective context injector Injects only component hints relevant to a file's imports. Migration runtime, Component hint library
Component hint library Base Web to Fluent UI mappings and examples. Selective context injector, Import-rule DSL
Import-rule DSL Tool-checkable migration rules defining the done state for each file. Component hint library, Validation loop
Custom AST linters Checks for repeated model mistakes and framework-contract violations. Validation loop
Coding model Model operating inside the migration tool loop. Migration runtime, Validation loop
Validation loop Rules, linters, diagnostics, and tests that push files toward correct migration. TypeScript diagnostics server, Import-rule DSL, Custom AST linters, Coding model, Temporary Fluent lane
Temporary Fluent lane Scaffolded product path for gradual migration without flag day or downtime. Validation loop

Data flow

The migration runtime selects a file, inspects imports with the TypeScript AST, injects only relevant Base Web to Fluent hints, asks the agent to migrate inside a tool-backed loop, checks import rules and custom linters, queries the TypeScript server for diagnostics, runs targeted tests, and moves clean changes through a temporary Fluent lane before collapsing the lane back into the main platform.

3 supporting quotes
“It provided definitions, references, diagnostics, file selection, and eventually test execution. This is one of the places where the historical timeline matters most.”article, implied
“We used the TypeScript AST to inspect the file’s import statements and injected only the hints that mattered for that file.”article, stated
“pile of internal pieces. By that point, the migration loop had become much more layered: 1. migrate a file inside a tool-backed loop 2. check import rules 3. run linters 4. ask the TypeScript server for diagnostics 5. run and fix only the related tests when needed 6. spend on broader validation”article, stated

Why this architecture

Block built a tool-backed program because neither a freeze window, manual migration, nor naive prompting could handle an active 11,000-file monorepo. The model's Fluent knowledge was stale, so Block moved correctness into TypeScript diagnostics, explicit import rules, linters, selective context, and a temporary migration lane.

3 supporting quotes
“At the same time, there was no acceptable downtime, no realistic freeze window, and no flag day cutover. Console was a live internal platform, and 40 to 60 engineers were still landing changes in it every day.”article, stated
“The main problem was that model knowledge of Fluent UI was uneven and often stale. The model could generate TypeScript that sometimes compiled cleanly, but still produce code that was not actually good Fluent code.”article, stated
“treat AI migrations as validated programs, not giant prompts. In late 2024, we had to migrate go/console, Block’s internal web platform for deploying and monitoring services, and for building the dashboards teams use to run them, from Base Web”article, stated

Models used: Goose

Scale

Alternatives considered (roads not taken)

Fork and maintain Base Web

Rejected because: Block could make it build, but maintaining a dead-end framework created long-term maintenance and knowledge costs.

“We got a Base Web fork building and passing tests the old-fashioned way, by hand. Technically, that proved the point.”article, implied

Single-shot prompting

Rejected because: The model generated plausible TypeScript that could still violate Fluent UI and React semantics.

“The model could generate TypeScript that sometimes compiled cleanly, but still produce code that was not actually good Fluent code.”article, stated

Include all migration hints in every prompt

Rejected because: The full hint library consumed about a quarter of the context window before the file was added.

“By the time we had built out the hint library, it was already consuming about 25% of a 256k context window before the model had even seen the file it needed to migrate.”article, stated

Patterns

tool-use-orchestration (migration)

The agent operates inside a tool-backed loop rather than a single prompt.

“More importantly, it turned the problem from “ask a model for a rewrite” into “put a model inside a tool-backed loop.” It was still early and rough, but it was already a very different shape from a copy-paste prompt.”article, stated

eval-driven-development (validation)

Diagnostics, rule validation, linters, and tests define the migration end state.

“Today, a lot of the techniques in this story sound obvious: selective context, rule-driven validation, AST-based linters, worktrees, targeted tests, temporary migration lanes.”article, stated

Tradeoffs

How to run a large UI migration.

Chose validated agent program over flag-day or weekend refactor.

Rationale: The source says the migration could not be solved by a freeze window or weekend refactor.

“We started with a migration problem that could not be solved with a freeze window or a weekend refactor.”article, stated

How to bound prompt context for migration.

Chose selective context based on imports over injecting all component hints into every prompt.

Rationale: Selective context kept the useful mapping knowledge without spending a quarter of the context window before the target file.

“injected only the hints that mattered for that file.”article, stated

How to keep product development moving during migration.

Chose a temporary Fluent lane over freeze window or flag-day cutover.

Rationale: The lane let old and new surfaces coexist while product teams migrated in waves.

“New surfaces could move onto that lane gradually while old ones kept working.”article, stated

Gotchas (what bit them)

Single-shot prompting produced plausible but bad Fluent UI code.

Root cause: Model knowledge of Fluent UI was stale and uneven.

Resolution: Block added tool-backed validation and explicit rules.

“The main problem was that model knowledge of Fluent UI was uneven and often stale.”article, stated

Evaluation

The migration was validated by TypeScript diagnostics, custom rules, linters, and tests.

Metrics: diagnostics · rule validation · tests · migration targets

“## The First Tool Was a TypeScript Server”article, stated

Outcomes

The source frames AI migration as a validated program.

“Migrating an enterprise-scale React monorepo off an unmaintained UI library taught us to treat AI migrations as validated programs, not giant prompts.”article, stated