hem migrate converts existing TypeScript that it can prove safe to convert, and refuses everything else. It is deliberately conservative: whole-file refusal is the safety contract, so a file either migrates completely or is left exactly as it was.
It is designed for migrating bounded slices of an application rather than converting an entire repository.
Look before you touch anything
hem migrate --check src/schedule.tsThis writes nothing. It prints a per-file, per-construct readiness report classifying every recognized construct into one of four categories:
| Category | Meaning | What apply mode does |
|---|---|---|
| AUTO | Provably behavior-preserving | Rewrites it |
| SCAFFOLD | Structure converts, semantics need a human sign-off | Rewrites it with a needs-hands marker |
| FLAG | A semantic judgment call | Leaves it verbatim and reports it |
| NEEDS-HANDS | An otherwise-automatic construct whose preconditions failed | Leaves it verbatim with a marker |
Read the FLAG entries first. These represent patterns that require manual review: || defaults, truthiness conditions, this outside a class, and any. The tool does not convert them automatically.
Pick a slice worth migrating
Choose a leaf module that has test coverage and active consumers, ensuring that existing behavior can be verified after migration.
Establish the baseline before changing any code. Run the package’s tests, build, and type check on the untouched source and record any existing failures to avoid confusing them with migration issues.
Apply the safe subset
hem migrate src/schedule.tsApply mode writes a .hem sibling for every file whose proposed migration both parses and type-checks as Hem. Any file that fails either gate is refused and left untouched. Every file it writes carries a banner marking it as migrated output for review.
Refusals are grouped by their first authored diagnostic, with counts. To see every diagnostic instead of the first blocker per file:
hem migrate --verbose src/schedule.tsWhen a file refuses
You have three options, in rough order of preference.
Keep it in TypeScript. A narrow TypeScript sidecar holding a deliberate contract is a good outcome, not a failure. Hem is an application language with TypeScript at its boundaries.
Extract the implementation and keep the shell:
hem migrate --extract-implementation src/schedule.tsThis selects self-contained exported function implementations, writes them as .impl.hem, and rewrites only those bodies in the original file into exact delegating wrappers. Effectful top-level initialization and functions that capture state owned by the shell stay in TypeScript. Focused compilation, wrapper type checking, and an exact declaration comparison all run before anything is written.
Write a smaller Hem leaf by hand. Writing a concise, idiomatic module is often preferable to mechanically converting a file that failed automated checks.
Verify against the ABI, not the diff
The emitted TypeScript is the ABI, so review it. Compare the generated declarations against the originals and confirm nothing widened: exported types, mutability, optionality, overloads, generic contracts, and callable shape all have to survive.
Overload sets require manual work. The migrator does not turn an implementation into an overloaded function through an unchecked assertion. Rewrite the operation as a checked generic or separate functions first. A refused migration leaves the original TypeScript file untouched; it does not create a shim.
Then run the gates that prove behavior rather than shape: the module’s own tests, its consumers’ tests, the package build, and the type check you baselined earlier.
Feed a plan to a tool or an agent
hem migrate --check --json src/schedule.ts > plan.json--json requires --check and emits the versioned machine-readable plan. Branch on each file’s accepted or refused outcome. Construct counts do not guarantee migration: a file with a high AUTO count can still be refused, and the refusal determines the outcome.
During the private preview, collaborators with authenticated Git access can install
the Hem skill
with npx skills add ozanvos/hem --skill hem; the repository link also requires access.
It uses the CLI to assess and generate a candidate, then guides idiomatic
rewriting, contract review, and behavior
verification. Formal evidence ledgers and campaign tooling are optional references.
What this tool will not do
Semantic API redesign is a stated non-goal of both modes. hem migrate does not reinterpret truthiness checks, replace || with ??, or restructure interfaces; these changes require manual redesign.
For the full option list, see the CLI reference.