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:
- 11,000-file monorepo
- 40-60 active engineers
- Stale model knowledge
- Need enforceable migration end states
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]
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
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
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, statedModels used: Goose
Scale
- The repo had 11k tracked files, including 10k TypeScript/TSX files, while 40-60 engineers landed changes daily.“At the start of the product migration phase, the project repo had 11k tracked files, including 10k TypeScript and TSX files. Most of the front-end surface was still tied to Base Web.”article, stated
- The migration used more than 50 module-hint files and more than 20 custom linters.“We ended up with more than 50 module-hint files and more than 20 custom linters. That was not prompt bloat for its own sake.”article, stated
- The full effort spanned 451 days and migrated more than 80 distinct targets.“By commit history, more than 80 distinct targets were migrated to Fluent across shared code and product surfaces.”article, stated
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.
Single-shot prompting
Rejected because: The model generated plausible TypeScript that could still violate Fluent UI and React semantics.
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.
Patterns
tool-use-orchestration (migration)
The agent operates inside a tool-backed loop rather than a single prompt.
eval-driven-development (validation)
Diagnostics, rule validation, linters, and tests define the migration end state.
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.
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.
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.
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.
Evaluation
The migration was validated by TypeScript diagnostics, custom rules, linters, and tests.
Metrics: diagnostics · rule validation · tests · migration targets
Outcomes
- The 451-day effort migrated over 80 targets, according to the summary.
The source frames AI migration as a validated program.