Claude Code Workflow for Flow-to-TypeScript Migration
To solve this, we built a custom AI migration engine that treated the codebase as a graph rather than a folder of text files. Here is the breakdown of the AI workflow and the architectural decisions that made it work.
The Pre-Migration Infrastructure
Before touching a single line of code with an LLM, we had to stabilize the environment. We switched the build system from Webpack to Vite + esbuild. This was non-negotiable because it allowed .js and .ts files to coexist seamlessly. Without this, you can't maintain a "green" build while migrating incrementally.
Next, we performed a deep static analysis of the codebase to create two maps:
- Dependency Graph: Identifying who imports whom and flagging every circular dependency.
- Type-Ownership Map: Tracking which file defines a type and which files consume it.
We used this data to group files into "atomic units." If File A defines a type used by File B, they migrate together. We then sorted these groups leaf-first, ensuring that dependencies were converted before the components that relied on them. For massive files (some over 4,000 lines), we manually split them into smaller domain modules first, because one-shotting a monolith is a recipe for truncation and errors.
The AI Orchestration Pipeline
We didn't use a single prompt; we built a state machine using LangGraph JS. This allowed us to separate the roles of planning, execution, and validation.
Planner ──► Implementer ──► Reviewer ──► ✅ commit
(next group (Claude writes (tsc + tests)
from plan) the TS) │
▲ │ errors?
│ ▼
└──────── retry (feed errors back in) ◄──┘
│
stuck after 3 tries?
▼
🧠 Architect (bigger model)
→ retry smarter / reorder / flag a humanThe logic follows a strict "Reviewer" pattern:
- Implementer: Claude Sonnet handles the bulk of the work (about 95% of files) because it is fast and efficient.
- Reviewer: A combination of
tsc(TypeScript Compiler) and existing test suites. If the build fails, the exact error message is fed back to the Implementer for a retry. - Architect: If a file fails three times, we escalate to Claude Opus. The heavier model analyzes why the conversion is failing and decides if the plan needs to be reordered or if a human needs to step in.
Strict Prompt Engineering Constraints
To prevent the AI from taking the "easy way out," we imposed hard constraints in the system prompts. We explicitly forbade the use of any and the as unknown as X casting trick, which often hides bugs. The model was forced to trace prop types from actual parent component usage and import legitimate library types rather than inventing shapes.
Crucially, the LLM was restricted to editing files only. It had no shell or git access; all verification and commits happened in the Reviewer layer, ensuring the AI couldn't "fake" a successful migration.
- Orchestration: LangGraph JS
- LLM Engine: Claude Code CLI (Sonnet for implementation, Opus for architecture)
- Verification: tsc + Vite/esbuild