Back office ops · Production

Block migrates go/console from Base Web to Fluent UI without a flag day using an agentic migration system

The problem

Block's internal platform go/console had 11k tracked files mostly tied to Base Web, which was scaling back maintenance. With 40 to 60 engineers landing changes daily and no acceptable freeze window or downtime, a standard migration cutover was impossible.

First attempt

Single-shot prompting produced code that was syntactically valid but semantically wrong — the model would generate React-incorrect patterns like creating makeStyles hook factories inside the component body. Attempting to fix output quality with global hint libraries consumed 25% of the 256k context window before the model even saw the target file.

Workflow diagram · grounded in source
1
File selected for migration
trigger
“what file should we migrate next? - what does this symbol resolve to? - what references and related files matter?”
2
AST-based selective hint injection
ai_action
“We used the TypeScript AST to inspect the file's import statements and injected only the hints that mattered for that file. If a file imported Button and Tag, it got the Button and Tag hints.”
3
Model migrates file in tool-backed loop
ai_action
“migrate a file inside a tool-backed loop”
4
Import rule validation
validation
“this import cannot be removed yet - this Base Web import must be replaced with that Fluent import - these new imports are not allowed - this required binding exists but is still unused”
5
Custom linter enforcement
validation
“more than 20 custom linters. That was not prompt bloat for its own sake. It was accumulated operational knowledge from repeated failures.”
6
TypeScript language server diagnostics
validation
“the model could edit a file and get near-real-time feedback from the TypeScript language server against the relevant slice of the codebase”
7
Warm Jest test execution
validation
“Starting Jest for even one file in a large monorepo can take 10 to 30 seconds, and that delay becomes expensive when a model keeps running tests after each change. To reduce the startup cost, we kept a Jest process warm in memory and put…”
8
Temporary Fluent migration lane
routing
“we created a temporary Fluent lane inside the repo. New surfaces could move onto that lane gradually while old ones kept working.”
Reported outcome

The migration succeeded: more than 80 distinct targets were migrated to Fluent, Base Web was fully removed in February 2026, and the entire effort across 451 days was driven primarily by one IC, producing 1,004 commits and 14,713 file changes.

Reported metrics
Tracked files in repo11k tracked files
TypeScript and TSX files10k
Engineers landing changes daily40 to 60
Context window consumed by hint library25%
Show all 19 reported metrics
tracked files in repo11k tracked files
TypeScript and TSX files10k
engineers landing changes daily40 to 60
context window consumed by hint library25%
module-hint filesmore than 50
custom lintersmore than 20
distinct targets migrated to Fluentmore than 80
pre-work duration210 days
pre-work commits809
pre-work file changes4,912
migration phase duration240 days
migration-related commits195
migration phase file changes9,801
total project duration451 days
total commits1,004
total file changes14,713
migration team sizedriven primarily by one IC
full project typecheck durationaround four minutes
Jest startup time per file10 to 30 seconds
Reported stack
TypeScript language serviceGooseANTLRJest
Source
https://engineering.block.xyz/blog/from-base-web-to-fluent-ui-without-a-flag-day
Read source ↗

Frequently asked questions

What did this team achieve with this AI workflow?

The migration succeeded: more than 80 distinct targets were migrated to Fluent, Base Web was fully removed in February 2026, and the entire effort across 451 days was driven primarily by one IC, producing 1,004 commit…

What tools did this team use?

TypeScript language service, Goose, ANTLR, Jest.

What results were reported?

Tracked files in repo: 11k tracked files; TypeScript and TSX files: 10k; Engineers landing changes daily: 40 to 60; Context window consumed by hint library: 25% (source-reported, not independently verified).

What failed first in this deployment?

Single-shot prompting produced code that was syntactically valid but semantically wrong — the model would generate React-incorrect patterns like creating makeStyles hook factories inside the component body.

How is this back office ops AI workflow structured?

File selected for migration → AST-based selective hint injection → Model migrates file in tool-backed loop → Import rule validation → Custom linter enforcement → TypeScript language server diagnostics → Warm Jest test execution → Temporary Fluent migration lane.