website/docs/tensor-shapes-ai-porting.mdx
{/*
Pyrefly includes a skill for Claude Code
that can automatically port PyTorch models to use tensor shape annotations. The
skill runs a structured, multi-step workflow — auditing ops, inventorying
parameters, probing shapes with reveal_type, restructuring for tracking, and
verifying the result — that produces a fully annotated port file.
In Claude Code, from a project with pyrefly's tensor shape fixtures, ask:
Port this model to use tensor shape types: path/to/model.py
Or use the slash command directly:
/port-model path/to/model.py
The skill will:
nn.Module and torch/F. function against
fixture stubs and the DSL registry, adding missing stubs before proceeding.Dim vs int.reveal_type,
restructure bare results for tracking, write the forward with assert_type,
and fill a post-module checklist.verify_port.sh, audit bare assert_type calls, compare
against the style guide, and produce a completion report.A single pass usually gets 80-90% of the way there. The remaining gaps — bridge dims, optional dims, parameterized configs — benefit from a second pass where the AI reflects on what it missed.
The workflow:
First pass. Invoke the skill. Review the completion report, paying
attention to the bare assert_type fraction and any type: ignore counts.
Reflect. Ask the AI to re-read the skill file and compare what it did against what the skill prescribes. A prompt like:
Re-read the port-model skill and reflect on the port you just produced.
What did you miss? What could be improved?
This typically surfaces missed restructuring opportunities — cases where the
AI used a bare assert_type or annotation fallback without attempting all
the restructuring steps in Step 4.
Second pass. Ask it to fix the issues it identified. This usually converges: the bare fraction drops and shaped coverage improves.
Most models converge in 2-3 iterations. Complex models with many dynamic
patterns (e.g., nn.Sequential(*list), conditional branching, late-initialized
buffers) may need one more round.
The skill produces a verify_port.sh report with these key metrics:
| Metric | What it means |
|---|---|
ig (ignore) | type: ignore comments. Lower is better. Each should have a category (algebraic gap, conditional equality, stub gap). |
bs (bare sig) | Bare Tensor in function signatures. Should be 0 for well-typed modules. |
bv (bare var) | Bare Tensor in local variable annotations. Lower is better. |
sh (shaped) | assert_type calls with full shapes (e.g., Tensor[B, D]). Higher is better. |
ba (bare assert) | assert_type(x, Tensor) — tracking gaps. Lower is better. Each should have a root-cause comment. |
sm (smoke) | Smoke test functions. At least 1-2 per model. |
A good port has high sh, low ba, and every bare assert documented with a
root cause tracing back to a restructuring receipt.
The AI workflow handles most patterns automatically, but some decisions require domain knowledge:
nn.Sequential(*list)) connects to a tracked downstream module, you may
need to decide which dimension to promote to a class type parameter.Dim
type parameters (and which modules extract which parameters) is often a design
decision about the model's API.