Add Uint Support
pytorch/pytorch
Add unsigned integer (uint) type support to PyTorch operators by updating ATDISPATCH macros.
Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]).
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-model --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .claude/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .claude/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .claude/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-modelType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-model --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .agents/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .agents/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .agents/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-model --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .cursor/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .cursor/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/facebook/pyrefly.git --path tensor-shapes/skills/add-shape-types-to-torch-model--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-model --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .gemini/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .gemini/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-modelInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .github/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .github/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .github/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install facebook/pyrefly add-shape-types-to-torch-model --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/facebook/pyrefly.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/tensor-shapes/skills/add-shape-types-to-torch-model .opencode/skills/add-shape-types-to-torch-model && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "add-shape-types-to-torch-model" agent skill from https://github.com/facebook/pyrefly/tree/main/tensor-shapes/skills/add-shape-types-to-torch-model into .opencode/skills/add-shape-types-to-torch-model/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-shape-types-to-torch-model", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
add-shape-types-to-torch-modelPort a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]).
Add Shape Types To Torch Model is an agent skill from facebook/pyrefly, published by the product's own GitHub organization. Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]). Use this skill whenever the user wants to add shape annotations to a PyTorch model, type a model with tensor dimensions, port a model to use shape tracking, or annotate model forward methods with tensor shapes. Also use when the user mentions tensor shape ports, Int types for PyTorch, or pyrefly shape checking on a model file. Invoke BEFORE starting any model port — the skill's gated workflow prevents common failure…
Its SKILL.md is about 13k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files (for example `porting_principles.md`, `shape_tracking_capabilities.md` and `style_guide.md`).
It sits in AI & LLM Engineering, covering Deep learning. It works with PyTorch. The repository describes itself as: A fast type checker and language server for Python. The licence is MIT.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 331449e. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships script files (Shell), which the agent can run.
Shell commands in SKILL.md call:
python3From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Add Shape Types To Torch Model loads about 13k tokens when it runs. Until then it costs about 138 tokens; SKILL.md has 6,613 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from facebook/pyrefly at commit 331449e, republished under its MIT licence (© facebook). 6,613 words, ~13,466 tokens.
.claude/skills/add-shape-types-to-torch-model/SKILL.md (or your agent's skills folder). This skill also uses 4 other files; get the full folder from GitHub.You are porting a PyTorch model to use pyrefly's tensor shape type system.
This usually works. The example corpus contains dozens of substantial, explicitly scoped ports of real open-source research models, including transformers, convolutional encoder-decoders, autoregressive architectures, and dynamic module stacks. A first checker pass with errors or gradual tensors is a diagnosis, not evidence that the model is unportable. Work module by module and expect a few short probe–fix–check iterations before accepting a boundary.
When subagents are available, use them for bounded, independent read-only work: map the source's stated shapes, audit the model's ops against the stubs, or cluster checker errors by root cause. The main agent still owns the port and integrates the evidence; do not have several agents edit the same file.
The gates below prevent the common failure mode of writing the whole port from reasoning and checking only at the end. Apply their rigor according to the deliverable:
assert_type coverage, and provide the receipts and counts
because other people use the port as reference material. A skill that invokes
this one for corpus work will say so.assert_type after every local, or model-file smoke
tests. Add focused static tests only for reusable stub behavior. Use temporary
reveal_type probes as needed and remove them before handoff. Existing test
and lint conventions take precedence.If the goal is native-syntax conversion, inventory every jaxtyping annotation
and its intended shape, including local annotations. If the goal is shape
checking with minimal production churn, consider declaring dimension names with
@static_jaxtyping("...") and keeping the existing annotations instead. Choose
from the request and repository context; do not convert syntax merely because a
conversion is possible.
After a native conversion, compare the inventory against the new annotations: every removed annotation must have a native counterpart with equal or better precision, or a documented reason why that precision is not representable.
Treat each jaxtyping annotation as an information-preservation obligation, not merely syntax to remove. Preserve its rank, literal dimensions, named-dimension equalities, arithmetic relationships, and variadic-prefix semantics whenever native shape types can express them. A clean type check is not sufficient if a precise jaxtyping contract became gradual.
IntVar
or IntTuple parameters so it continues to document and check the intended
relationship."*B D" using Bs: IntTuple and
Tensor[[*Bs, D]]; do not collapse it to a bare Tensor. Use
*Elements[Bs] only when annotations evaluate eagerly at runtime.IntVar, for example Tensor[[B, NewH, NewW]]. Pyrefly
instantiates such unconstrained variables as gradual dimensions at call
sites. Use int only when a useful name is unavailable, and bare Tensor
only when even the rank is genuinely unknown. Record every loss of precision
in the before/after audit.cast immediately around
the untracked operation. Keep all dimensions bound by parameters on both sides
of that boundary. A runtime rewrite is separate work and requires explicit
user direction.Shape: IntTuple and Tensor[[*Shape]]; if the code requires
trailing dimensions, spell those out after a variadic prefix.Resolve these from the repository and invoking skill whenever possible. Do not interrupt the user when the checkout, config, or request already answers them; ask only when a real ambiguity remains.
pyrefly check and inspect the resolved paths with pyrefly dump-config. The
Torch stubs are partial overlays, so Pyrefly must also see a real torch
installation through the selected interpreter or --site-package-path.
When the model uses einops, add the pyrefly-einops-stubs root too; without
that overlay, an einops transform can incorrectly appear to preserve its
input shape. Before porting, check one known-good nearby example and require
0 errors. If it fails, repair the environment rather than weakening the
model annotations. Also record the target boundary's own pre-port error
count before annotating; pre-existing errors are fixed or preserved as
you go, but only the baseline tells them apart from errors you
introduce. In a repository, prefer its documented check command; an
invoking skill may provide all paths, as the corpus skill does.A no-stub-change port is a supported outcome, not a failure. If stub changes are
in scope, port first and confirm each gap with reveal_type before editing a
stub. Do not decide about deeper Pyrefly shape-logic changes up front; react only
if a computed shape is provably wrong.
Create tasks for each gate and the module loop/verification phases that follow. Update them as you complete each stage — this gives visibility during long-running ports.
Complete these gates before writing any code.
Read shape_tracking_capabilities.md and porting_principles.md (this skill
dir). They explain the tracking mechanisms, current API, priority order, and
stub philosophy.
Then skim the model index at the end of style_guide.md and open one to three
closest examples under pyrefly-torch-stubs/examples/. Use them as evidence
that substantial real models can be ported and as templates for
architecture-level patterns such as attention, dynamic module stacks,
encoder-decoders, and variadic batches. Existing prose can be stale: only a
current assert_type, focused probe, or passing check proves the present
behavior. Do not copy annotations blindly; the target source and checker remain
authoritative. Save the full style-guide comparison for verification.
Inventory every tensor-producing or shape-changing expression in the selected
model boundary: module construction and calls, Tensor methods, operators and
indexing, torch/F. functions, module-instance methods, third-party APIs, and
dynamic dispatch. For Torch APIs, inspect the relevant partial overlay module
and read the return annotation; if it calls a type-level shape function, confirm
that function in _shapes.pyi. Special handlers live separately in Pyrefly's
Rust implementation, so confirm them with source or a minimal probe.
Classify each expression as tracked-stub, tracked-DSL, tracked-handler,
gradual Tensor, Any, unavailable-overlay-symbol, or third-party-boundary.
The distinction matters: these are partial PEP 561 overlays, and a public name
omitted from an overlaid module is unavailable rather than guaranteed to fall
back gracefully. A declared loose return may produce a gradual Tensor, while
an undeclared Tensor member may flow through __getattr__ as Any.
This is a diagnostic pass, not a blocker. A subagent may collect the source operation inventory, but the primary agent must validate the final stub/DSL/handler classification against the local checkout. Do not use web search as authority for current support.
For a reference-corpus contribution, include the audit table in the work log before Gate 2. For ordinary and production ports, keep it as concise working notes unless the user asks for the full audit:
## Gate 1: Ops audit
| Op | Stub location | Shape function in the return annotation (or "none") | Status |
|----|---------------|------------------------------|--------|
| nn.Conv2d | tensor-shapes/pyrefly-torch-stubs/torch-stubs/nn/__init__.pyi — generic [InC,OutC,K,S,P,D] | none (generic signature) | tracked-stub |
| F.adaptive_avg_pool2d | tensor-shapes/pyrefly-torch-stubs/torch-stubs/nn/functional.pyi — `Tensor[adaptive_pool2d_shape(Shape, OH, OW)]` | `adaptive_pool2d_shape`, defined in `_shapes.pyi` | tracked-DSL |
| ...Status is one of tracked-stub, tracked-DSL, tracked-handler, gradual
(a declared bare return), Any, unavailable-overlay-symbol, or
third-party-boundary.
For a stub or DSL result, read the declaration's return annotation; if it calls
a shape function, confirm that function exists in _shapes.pyi. Write "none"
only after confirming that the signature's own generics compute the shape.
A non-precise result is information, not a blocker, but its exact category
determines the response. Preserve known rank and dimensions in the public
contract, isolate a dynamic or third-party boundary with a precise cast when the
shape is justified, and use bare Tensor only when rank itself is genuinely
unknown. An unavailable overlay symbol may require a stub declaration just to
type-check; it does not necessarily degrade to Tensor. If stub work is in
scope, consider a general stub improvement.
Define the port boundary before inventorying it. For a single-file model, the boundary is usually that file. For a repository containing many model families (for example, a policy zoo or a framework that builds models from YAML), choose the smallest coherent requested model plus its transitive custom tensor modules; do not inventory unrelated training, data, CLI, or deployment code. State the boundary and proceed. Ask only if several incompatible model families are plausible and the request gives no way to choose. A corpus-invoking skill may require one complete upstream file or another explicit boundary. When the boundary is smaller than its package, state the exclusion rule alongside it: which files are out and why, so coverage is visible without opening the report.
Mine the source for shape evidence before inventing annotations:
(B, C, H, W) or reshape arrows;view/reshape arguments,
einsum or einops equations, config dimensions, and test fixtures;Turn this evidence into a short shape map and use its names consistently. Comments are hypotheses, not proof: resolve conflicts by following the actual operations and tests, then preserve or correct useful comments in the port. This is especially valuable in research models, which often document shapes more precisely than their Python annotations do.
For a reference-corpus port, write the inventory as a comment block at the top of the port file using this format. For an ordinary port, keep the same list in working notes; production migrations should inventory only changed public boundaries and existing annotations.
# ## Inventory
# - [ ] ClassName.__init__ — Int: param1, param2; int: param3
# - [ ] ClassName.forward
# - [ ] function_name — utility, no tensors
# ...Every class, function, and method inside the selected port boundary must appear, and every inventory item must be ported. Do not silently narrow the boundary after discovering a hard dependency. A dependency outside the boundary may remain behind a precise cast, typed interface, or gradual boundary. If stub work is in scope, add only general improvements that help more than this model.
For each class, list constructor parameters and whether each is Int or int.
Also record configuration or mode flags that change tensor rank, layout, return
arity, or container type (training/eval, cache, export, optional backends). Use
Literal overloads when the existing API exposes a statically knowable mode;
otherwise preserve the honest union or gradual boundary. Runtime assertions
support preconditions but do not by themselves turn unrelated int values into
symbolic dimensions.
Check off corpus inventory items as you port them. Do not proceed to verification with unchecked items inside the declared boundary.
For a single-file or few-module port, one commit is usually fine. When the
boundary spans several files or many modules, consider annotating in phases
on a branch, one commit per phase. Phases order the work; they do not shrink
the boundary — every inventory item is still ported. Order phases by
dependency: leaf modules and shared contracts first, then the modules that
consume them. Run the module loop over one coherent subset per phase and
require a 0 errors check before committing, so every commit is a working
checkpoint and later phases never debug earlier ones. Commit messages should
state the phase's coverage (which modules, public-contract coverage delta,
remaining gradual boundaries); keep reveal_type probes and working notes
out of the commits. For production migrations this also keeps each diff
reviewable and landable on its own.
You have completed pre-flight. You have NOT written any model code yet.
Your analysis so far is a hypothesis. The module loop tests it empirically. If you catch yourself planning multiple modules' forwards in your head, STOP — you are substituting reasoning for testing, and reasoning is less reliable.
Write the file with imports, the inventory comment, and utility functions (no tensor shapes). Then start Step 1 for the FIRST module only.
Read porting_principles.md (this skill dir) for the mindset: why we port,
priority order, and stub philosophy.
Repeat the following for each module in dependency order. Each module's typing may inform the next — e.g., discovering that a submodule tracks shapes internally changes how the parent handles its loop.
ONE MODULE AT A TIME. Complete Steps 1–6 for module A before starting module B; in the corpus case, record the Step 6 checklist at that point. If you find yourself typing two modules' constructors before running the checker, you have already entered the primary failure mode: writing the entire file and validating at the end leads to hidden gradual boundaries.
List every constructor parameter. For each, decide:
nn.Linear,
nn.Conv2d, tensor creation, or any typed function that uses the value
as a shape dimension).n_layers, n_res_block) or boolean-like flag.If in doubt, make it Int. The cost is one more type param; the cost of
int is permanent shape loss in everything downstream.
Critical rules:
A dimension that enters new typed code should be Int[X], not int. In an
existing public API, changing int to Int[X] narrows the static contract;
get the user's agreement first. Otherwise preserve the signature and recover
precision at the first boundary where the dimension is justified. When no
user can be asked (a headless trial, eval, or bulk migration), default to
preserve-and-recover: keep the signature, add a bridge dim or cast, and
note each site in the report. Never narrow a public contract silently.
len(tensor) returns plain int, while tensor.size(dim) can preserve a
symbolic Int. In annotation-only work, keep the original expression and
restore precision at a downstream boundary; suggest the equivalent size
spelling separately if it would improve inference.
Int is a subtype of int, so int(dim) erases tracking when dim is already
an int at runtime. Do not remove conversions around floats, tensors,
round(), or expressions such as seq**0.5; those conversions can affect
runtime behavior and are expected gradual boundaries. Arithmetic mixing a
plain int with an Int produces plain int.
Derived dims use expressions (D // NHead, 4 * ES), not independent
type params. Only independent degrees of freedom get type params. Keep
preconditions such as divisibility, perfect-square sequence lengths,
nonempty scans, and mask-cardinality equalities separate from shape types;
runtime assertions document them but do not justify simplifying
(H // P) * P to H.
Structured inputs and mode-dependent outputs. Inventory heterogeneous
tensor mappings and flags for training/eval, cache, export, or optional
backends. Use an existing TypedDict/dataclass or honest union when available.
Introducing a narrower public container type or overload requires the user's
agreement that it matches the real API.
Dimensions from list[int] or other untracked sources. Element access
erases the value to int. Preserve the source and restore precision with a
justified cast or typed interface when the value reaches a known component
boundary. Adding an explicit Int config field or constructor parameter
changes the API; suggest it as separate work unless the user requested it.
Keep existing register_buffer, register_parameter, dynamic factories, and
container construction. Replacing them with nn.Buffer, explicit attributes,
or typed classes is a runtime refactor, not annotation work.
Bridge dims. When part of the model is untracked (e.g., features
built via nn.Sequential(*list)), look for dimensions that connect
the untracked section to tracked downstream modules. For example, if
features output feeds a Linear classifier, the Linear's in_features
is a bridge dim — making it a class type param enables annotation
fallback to recover a shaped type (e.g., Tensor[[B, LastC]]) that
then flows naturally through downstream ops. Without it, annotation
fallback can only recover bare Tensor or batch-only shapes.
class Model[NC: IntVar, LC: IntVar](nn.Module):
def __init__(self, num_classes: Int[NC] = 1000,
last_channel: Int[LC] = 1280):
...
self.classifier = nn.Linear(last_channel, num_classes)Here LC bridges the untracked feature extractor to the typed
classifier, recovering Tensor[[B, NC]] at the output.
Int[X] | None for optional dimensions. In new code, a genuinely
optional shape-bearing parameter can use Int[X] | None and narrow with
if value is not None:. Replacing an existing public Optional[int] with
Int[X] | None narrows its static contract; do so only with user agreement.
Otherwise preserve the public type and recover a justified shape downstream.
Parameterized config dataclasses. When multiple modules consume
dimensions from the same @dataclass config, note it — Step 2
shows how to parameterize the config so dims propagate across
module boundaries.
Lazy-initialized buffer attributes. An attribute's type is fixed at its
declaration. If self.x: Tensor | None = None is assigned a shaped tensor in
a later setup hook, reads after narrowing retain only bare Tensor. Preserve
the lifecycle and record this as a dynamic boundary. Eager initialization can
recover the shape, but it changes runtime structure and requires separate user
direction.
Uppercase locals shadow type parameters. A local named B, C,
or D can shadow a type parameter of the same name inside annotations
evaluated in that scope (including assert_type shape strings),
producing invalid-annotation. Rename the local behavior-neutrally
(B_ssm, lowercase destructuring); call sites are unaffected.
Write __init__ with the Int params from Step 1. Construct sub-modules
using those Int params — they get typed automatically.
Default values for Int params: a literal constructor default can be used
with Int[X] directly. A PEP 696 default is optional: it makes the unspecialized
class name carry that default at the type level.
# Works; callers bind NC from the argument or literal default:
def __init__(self, num_classes: Int[NC] = 1000): ...
# Also works; bare Model means Model[1000]:
class Model[NC: IntVar = 1000](nn.Module):
def __init__(self, num_classes: Int[NC] = 1000): ...Dataclass field defaults are different: dim: Int[D] = 768 currently needs a
specific # type: ignore[pyrefly:bad-assignment].
Constructor patterns that create expected shape-typing boundaries:
nn.Sequential(*list_var) and factory functions returning
nn.Sequential erase the member module types at the dynamic boundary.getattr(nn, name)() and YAML/config-selected module factories return
Any or a broad module type.stride=2 against an inherited Int[1])
are correctly rejected — accepting them would be unsound, since the
object is statically the default specialization. Respond by annotating
attributes with the precise base type (self.conv: nn.Conv1d[...] = Subclass(...)), which recovers exact shapes at use sites. Specializing
the base explicitly (class Sub(Base[2])) silences the constructor
conflict but attribute reads still come back gradual, and a bare
ignore is worse: the object keeps the default shapes, which then
silently contradict the runtime values.Preserve known dimensions in typed public interfaces around these boundaries. Do not extract modules, replace factories, or redesign containers solely for shape tracking unless the user separately requests that rewrite.
Parameterized config dataclasses. For a new/corpus model, or when the user
agrees to the narrower static API, a @dataclass holding shared dimension
hyperparameters can be generic so dimensions propagate through constructors.
For an existing public production config, preserve its annotations by default
and recover shapes at component boundaries instead:
@dataclass
class Config[D: IntVar, NHead: IntVar, VocabSize: IntVar]:
dim: Int[D]
n_head: Int[NHead]
vocab_size: Int[VocabSize]
dropout: float = 0.0Modules extract only the params they need using Any for the rest:
class MLP[D: IntVar](nn.Module):
def __init__(self, config: Config[D, Any, Any]):
super().__init__()
self.fc = nn.Linear(config.dim, 4 * config.dim)Without this, each module must independently accept and thread every dim through its constructor — error-prone and verbose.
If the original config had default values (e.g., dim: int = 768),
combine the two patterns above — give the dataclass type params PEP
696 defaults so callers can omit dims:
@dataclass
class Config[D: IntVar = 768, NHead: IntVar = 12, VocabSize: IntVar = 50257]:
dim: Int[D] = 768 # type: ignore[pyrefly:bad-assignment]
n_head: Int[NHead] = 12 # type: ignore[pyrefly:bad-assignment]
vocab_size: Int[VocabSize] = 50257 # type: ignore[pyrefly:bad-assignment]
dropout: float = 0.0Two different defaults are at play here, and only one is clean:
[D: IntVar = 768, ...]) are
what let callers omit dims — those need no ignore.dim: Int[D] = 768) still need
# type: ignore[pyrefly:bad-assignment], because a plain int literal is not
assignable to Int[D]. This is the accepted corpus pattern (see
examples/finalmlp.py). Note that constructor-parameter defaults
(def __init__(self, num_classes: Int[NC] = 1000)) do not need the
ignore — only dataclass field defaults do.Now Config() produces Config[768, 12, 50257] and
Config(dim=1024) produces Config[1024, 12, 50257] — dims
propagate even when callers don't pass every parameter.
DO NOT write the forward method yet. The forward signature and
assert_type expressions depend on what the checker infers, which you
don't know until Step 3.
Run the checker to verify the constructor compiles. In the corpus case, record that output before proceeding; otherwise keep iterating without dumping routine success output.
For a corpus contribution, count and probe every tensor local in the forward method. For an ordinary model, probe each shape-changing local and every point where the shape could be lost; include enough checkpoints to cover each operator chain and module boundary. For production code, use targeted temporary probes around changed boundaries and checker failures.
Add reveal_type at those points and run the checker. In the corpus case,
record the results in this format; elsewhere keep concise working notes:
# reveal_type results for ClassName.forward:
# Locals: N (list them: var1, var2, var3)
# var1 (line N): Tensor[[B, C, H, W]] → SHAPED
# var2 (line M): Tensor → BARE — investigate in Step 4
# var3 (line P): Tensor[[B, D]] → SHAPEDFor a corpus contribution, verify that the reveal count matches the tensor-local count. In every mode, do not continue while a shape-changing path is unprobed.
If a reveal_type result contradicts your understanding of the op (e.g., spatial dims unchanged after a strided conv, or a shaped op returning bare), write a small isolating test, run the checker, and confirm the behavior before proceeding. Either your understanding is wrong (update your mental model) or the checker has a simplification you should document. If a second pass still has unexplained plain or unchanged Tensor results, re-run the environment sanity check and confirm the einops search path before declaring the code untrackable.
This table is your Step 4 input. Do not write assert_type until Step 4
is complete for every BARE entry. The results tell you:
assert_type in Step 5.Tensor → shape lost. Investigate in Step 4 before deciding.Not all statically typed tensor code can be shape-typed. Python's type system
cannot represent a general container whose element at each runtime position has
a different shape type, nor can it recover module types chosen by an arbitrary
factory, YAML parser, getattr, or data-dependent control flow. Recognizing
such a boundary is a successful diagnosis, not a reason to keep forcing the
checker.
For each bare result:
len, conversion, config, buffer, factory, and container behavior intact.F.interpolate(scale_factor=...) may track when a symbolic size=... form
remains gradual, and F.softmax may be more precise than other softmax entry
points.Tensor only when rank itself is unknown.ModuleList values indexed or iterated dynamically, nn.Sequential(*items)
built from a runtime list, dynamic factories, and data-dependent result
counts commonly require a gradual boundary.Fixed list literals such as torch.cat([a, b]) can retain distinct element
shapes on current Pyrefly. Dynamically built or broadly annotated lists usually
homogenize their members. Probe before changing collection syntax; a fixed or
explicitly typed tuple is useful only when it preserves the original behavior
and the checker demonstrates the benefit.
Do not redesign runtime code solely to improve shape coverage. A cast is acceptable because it does not change runtime behavior. Narrowing a public type contract is allowed only when the user explicitly agrees that the narrower contract is correct. Extracting modules from a dynamic container, converting inheritance to composition, splitting loops or branches, or replacing a model factory changes source structure and is outside this annotation skill. Report possible narrowing or rewrite options and let the user request them separately.
Before accepting a bare result or typed boundary, record this short receipt in working notes; include it in the response for a corpus contribution:
## Boundary receipt [<Module>.<variable>]
- First precision loss: <operation or incoming bare value>
- Source evidence for expected shape: <comment/assertion/equation/test>
- Stub / shape function / handler checked: <result>
- Annotation-only repairs tried: <result>
- Boundary: <precise cast / typed interface / bare Tensor and why>
- Rewrite that could improve coverage: <none, or describe for separate approval>type: ignore categories. Before writing one, identify the cause:
N * (X // N) ≠ X): no annotation-only fix.Inp == Oup at runtime but separate
type params): no annotation-only fix.bad-return from an untracked subsection: do not hide a dynamic region at
the return. Preserve bridge dimensions in the signature and use one narrow
cast or typed boundary where precision becomes known again.Use # type: ignore[pyrefly:<code>] with the exact error code Pyrefly prints,
for example pyrefly:bad-assignment, pyrefly:bad-return,
pyrefly:bad-argument-type, or pyrefly:assert-type. Pyrefly may accept a bare
or mismatched code, so accuracy here is documentation for reviewers rather than
a validation mechanism. Do not use mypy spellings such as arg-type,
return-value, or assignment.
When an op's shape is wrong. The cases above cover missing precision, which
may appear as a gradual Tensor, Any, a third-party boundary, or an unavailable
symbol in a partial overlay. None is a reason to discard the surrounding
contract. The rarer hard case is a wrong concrete shape: Pyrefly computes a
specific shape that is incorrect (for example, floor division where the runtime
op rounds up). You cannot annotate around that disagreement.
When it happens, tell the user; fixing it means teaching Pyrefly new shape logic,
not editing a stub signature. If a shape-DSL skill (e.g. modify-shaped-array-dsl)
is available, hand off to it; otherwise file an upstream issue describing the op
and the correct rule, and document the spot with type: ignore for now. Don't
reach for this on ordinary bare-Tensor gaps — only when a computed shape is
provably wrong.
Bare Tensor where you know the shape? A shaped annotation or
assert_type against a gradual value can be accepted without proving inference.
First trace the loss. If it is a genuine dynamic or third-party boundary, use a
narrow explicit cast to the source-supported shape and record the boundary;
otherwise fix the annotation or stub that lost precision.
Annotation hierarchy (most to least desirable):
assert_type — verifies the checker's inference. Proves the system
works, not just that the declared contract is accepted.cast at a boundary — use when dynamic or third-party code
cannot express the shape but source evidence establishes it. This preserves
runtime behavior and makes the non-inferred step explicit.x: Tensor[[B, C, H, W]] = unrefined_op(...).
Pyrefly may accept a gradual RHS without proving the shape, so mark and audit
it exactly like a cast; prefer an explicit cast when clarity matters.type: ignore — the checker produces a wrong concrete type (algebraic
gap or conditional equality). Last resort; explain the specific gap.Tensor — rank genuinely unknown or a dynamic boundary with no
defensible precise contract. Document the reason.Type the forward signature:
D, spell the trailing dim out with the variadic
batch idiom: Tensor[[*Bs, D]] (with Bs: IntTuple), not a whole-shape
Tensor[S] that swallows D. Use *Elements[Bs] only for eagerly evaluated
runtime annotations. See examples/tacotron2.py.Use the recorded probes to add assert_type checkpoints:
reveal_type → assert_type(x, Tensor[...]) with that shape.reveal_type → assert_type(x, Tensor) only when documenting an
accepted tracking gap, with a comment naming the root cause.For a corpus contribution, every tensor local in every forward method gets an
assert_type; verify the count before leaving the module. For an ordinary
model, checkpoint every shape-changing operation, module boundary, and repaired
shape-loss site. Production code should keep only focused assertions that fit
its existing test conventions. In all modes, do not omit a checkpoint merely
because the shape expression is complex — use what reveal_type showed.
For a corpus contribution, record the count in this form:
# assert_type count for ClassName.forward:
# Locals: var1, var2, var3 (N total)
# assert_type calls: N
# Match: yesIf the counts don't match, you missed some. Go back and add them.
Boundary receipt check. Every bare assert_type(x, Tensor), precise cast,
and annotation fallback (x: Tensor[[B, C]] = untracked_op(...)) must cite the
Step 4 boundary receipt that justifies it. If no receipt exists, go back and
diagnose the first precision loss.
# Bare/cast/fallback sites and their boundary receipts:
# - var2 (bare): receipt MLP.var2 — runtime-built mixed module list
# - var3 (cast): receipt MLP.var3 — third-party transform, shape from equation
# - var5 (bare): receipt MLP.var5 — input is bare from the parent boundaryFor reference-corpus examples, smoke tests at the bottom of the file must use
assert_type on the typed output, not assert out.shape == (...). Runtime shape
asserts do not exercise Pyrefly; they only prove the model runs. For ordinary or
production code, preserve the project's test layout and add an equivalent
static check only where its conventions support one.
model = MyModel(num_classes=10)
x = torch.randn(2, 3, 32, 32) # inferred as Tensor[[2, 3, 32, 32]]
out = model(x)
assert_type(out, Tensor[[2, 10]]) # not: assert out.shape == (2, 10)Before proceeding, confirm the module's public contract, shaped checkpoints, gaps, and ignores are understood. For a corpus contribution, record every line of this checklist; for other ports, keep only the items that found a gap:
### Post-module: <ClassName>
- type: ignore count: ___
For each: [line] [category: A1 / conditional / stub-gap] [fix attempted]
- Boundary receipts: [list receipt IDs, or "none — all tracked"]
- int params: [list each int param and why it's not Int, or "none"]
- int() casts: [list each, or "none"]
- Sequential(*list): [list each instance and what you did, or "none"]
- bare Tensor in sigs: [list each with reason, or "none"]
- assert_type: ___ checkpoints covering ___ locals in ___ forward methods
- missing stubs: [list each, or "none"]Do not proceed to the next module with unfilled lines.
Everything above produced a DRAFT. This phase reviews it.
Run verify_port.sh on standalone and corpus model files. For production code,
use it only when its corpus-oriented checks are relevant; the repository's own
lint, type-check, and tests are authoritative.
tensor-shapes/skills/add-shape-types-to-torch-model/verify_port.sh <path/to/your/port.py>For a corpus contribution, include the full output in the work log. Otherwise, report actionable warnings and what you did about them.
verify_port.sh is a line-oriented advisory check; it does not type-check the
port or establish per-forward coverage, and multiline constructs can confuse its
counts. Treat its output as hints. You must also run Pyrefly itself against the
port file. There is no --tensor-shapes flag — shape tracking is on whenever
the shape stubs and shape_extensions are on the search path. The single-file
check mirrors tensor-shapes/pyrefly-torch-stubs/run_pyrefly.py:
pyrefly check --config /dev/null --python-version 3.13 \
--search-path <root containing torch-stubs> \
--search-path <root containing shape_extensions> \
--site-package-path <site-packages containing real torch> \
path/to/your/port.py
# If the model imports einops, also pass:
# --search-path <root containing the shape-aware einops-stubs>The core search roots are tensor-shapes/pyrefly-torch-stubs (the
torch-stubs package) and tensor-shapes/pyrefly-shape-extensions (the
shape_extensions package). The partial overlay still needs the installed
Torch package for names it does not declare. For einops models, add
tensor-shapes/pyrefly-einops-stubs; omitting it can make a transform appear to
return the unchanged input shape rather than report a gap. When checking a
multi-file package, also pass its root as a --search-path; with
--config /dev/null there is no project root to infer, so relative imports
otherwise fail as missing-import.
In fbsource, build fbcode//pyrefly/tensor-shapes:torch-stubs-search-path and
pass the output directory reported by buck targets --show-output—a Buck target
label is not itself a filesystem search path. Prefer an invoking skill's
build-and-check command when it supplies the complete environment. Confirm the
resolved paths with pyrefly dump-config and check a known-good example before
typing the target model.
Python version: the PEP 695/696 generics syntax (class Net[D: IntVar],
type-param defaults) requires --python-version 3.12 or later; the corpus runs
3.13.
To type-check the whole corpus (or a stack of edits) at once:
python3 tensor-shapes/run_all_shape_tests.py --mode auto
# In an internal checkout, including runtime tests:
python3 tensor-shapes/run_all_shape_tests.py --mode buck --include-runtime-testsRun Pyrefly and require 0 errors; reveal_type output is acceptable only
while probing and must not remain in the finished port. For a corpus
contribution, include the checker output in the work log. Otherwise report the
command and result concisely. For each component contract, also confirm that
one wrong-shaped input errors — a contract that accepts everything proves
nothing. Use throwaway probes for this unless the repo's test conventions
support a committed check.
For EACH warning in the verify_port.sh output, write one of:
Do not write "all warnings audited" — list them individually.
The port's quality metric is: what fraction of assert_type calls verify
a shaped type vs. document a bare Tensor gap? Every bare
assert_type(x, Tensor) is a tracking gap. Minimizing these is the goal.
For each assert_type(x, Tensor) in the port (bare, no shape params):
# Sequential(*list), # input is bare).If any bare assert_type lacks a comment or boundary-receipt trail, go back and
either recover precision or document the boundary properly.
Record the full bare audit for a corpus contribution. For ordinary and production ports, report each remaining bare boundary and its root cause concisely:
## Bare assert_type audit
Total assert_type in forward bodies: ___
Shaped (assert_type(x, Tensor[...])): ___
Bare (assert_type(x, Tensor)): ___
Bare fraction: ___
Each bare:
- line N: var — root cause (boundary receipt: <module>.Step4)
- line M: var — root cause (boundary receipt: <module>.Step4)For an ordinary or production port, prioritize public-contract coverage: precisely shaped component tensor inputs and outputs divided by in-scope component tensor boundaries. Report that one number plus each remaining gradual boundary; do not count every local expression merely to manufacture a metric.
For a reference-corpus contribution, report three additional measures so source evidence, casts, and inferred shapes do not get conflated:
cast(Any, ...) boundaries, and bare-Tensor boundaries separately.Treat 80–90% inference coverage as a solid corpus result when genuine dynamic or third-party boundaries remain, but investigate each one; do not narrow contracts merely to reach a clean check. Aim above 90% when the necessary stubs or shape rules exist. Annotation preservation and source-evidence resolution should normally be 100%; anything lower needs a specific reason.
Read the full style_guide.md now. The earlier model-index and example skim
was orientation; this pass compares the empirical draft against all known
patterns.
For each module in a corpus port, find the closest matching pattern and record the comparison below. For other ports, apply relevant improvements without printing the full table unless it clarifies a remaining gap:
## Style guide comparison
| Module | My approach | Closest style guide pattern | Could I improve? |
|--------|------------|---------------------------|-----------------|
| ... | ... | ... | yes/no — reason |If any row says "yes", go back and try the improvement before proceeding. If it doesn't work, document why in the row.
If you made any changes during this phase, re-run the script and paste the new output. If no changes were made, write "No changes — output unchanged."
Re-check callers. If you changed a module's forward signature or
return type during this phase, re-run reveal_type in every module
that calls it and update their assert_type expectations. A fix to
module X can change the inferred types in module Y's forward body.
For ordinary and production ports, report only: the check command and result,
file coverage (shaped files over total package .py files, with the exclusion
rule when partial), public-contract coverage, remaining bare/cast boundaries with their
justifications, and any stub or shape-logic follow-ups. Do not dump the internal
gates.
For a reference-corpus contribution, fill the exhaustive template below before reporting completion:
## Port complete: <model name>
Gate 1 ops audited: ___. Stubs added/fixed: ___.
Gate 2 inventory items: ___. All checked off: yes/no.
Modules ported (dependency order): ___
Step 6 checklists filled for each: yes/no
type: ignore total: ___
___ A1 algebraic, ___ conditional equality, ___ stub gap, ___ other
assert_type total: ___ (___ shaped, ___ bare)
Bare fraction: ___%
Each bare assert_type has comment + boundary-receipt trail: yes/no
Annotation preservation: ___ / ___ removed annotation sites = ___%
Source-evidence resolution: ___ / ___ comments/assertions/equations/tests = ___%
Inference coverage: ___ / ___ precise native shape expressions = ___%
Precise shape casts: ___. cast(Any) boundaries: ___. Bare Tensor boundaries: ___.
smoke tests: ___ — all use `assert_type` on typed output (not `.shape ==`): yes/no
Verification phase:
- verify_port.sh warnings: ___
Fixed: ___. Accepted: ___ (each justified above).
- Pyrefly check: 0 errors: yes/no
- Style guide comparison rows: ___
Improvements attempted: ___. Improvements that worked: ___.
- verify_port.sh re-run (if changes made): 0 actionable: yes/no
Gaps & proposed improvements (for the user):
- Ops that stayed untracked, and why: ___ (or "none")
- Stub-signature improvements that would recover shapes (if stubs weren't
changed): ___ (or "none")
- Wrong computed shapes found (needing a shape-DSL change): ___ (or "none")
- Suggest filing an upstream issue for: ___ (or "none")The "Gaps & proposed improvements" block is the user-facing payload of the lighter deliverable. Fill it from non-precise Gate 1 classifications and Step 4 boundary receipts.
The shape_extensions package bridges pyrefly's type system and Python runtime.
Importing it patches torch.Tensor, nn.Conv2d, and other torch classes to
accept subscript syntax (e.g., Tensor[[B, C, H, W]]) at runtime without
crashing. It also provides IntVar with arithmetic support (N + 1, N // 2
return self instead of TypeError) and Int for binding runtime ints to
type-level symbols.
shape_extensions is installed alongside the shape-aware torch stubs (wherever
those live in your environment — pyrefly dump-config reports the location). In an
fbsource Buck checkout specifically, the runtime package is
fbcode//pyrefly/tensor-shapes/pyrefly-shape-extensions:shape_extensions, the importable stub package is
fbcode//pyrefly/tensor-shapes/pyrefly-torch-stubs:torch-stubs, and the
filegroup to pass as a Pyrefly --search-path is
fbcode//pyrefly/tensor-shapes:torch-stubs-search-path.
Pick an import mode based on whether the port file will be executed, not just type-checked:
Static-check-only (common case — you only run the checker on the file): guard the shape imports. The file is never executed, so the annotations never evaluate and the guarded names need not resolve at runtime.
from typing import assert_type, TYPE_CHECKING
import torch
import torch.nn as nn
if TYPE_CHECKING:
from torch import Tensor
from shape_extensions import Int, IntTuple, IntVarRunnable (the file is imported/executed): ordinary annotations evaluate unless postponed; PEP 695 bounds themselves are lazy. Either:
from __future__ import annotations and keep annotation-only names under
TYPE_CHECKING; orElements for variadic
splats that evaluate eagerly — see
examples/runtime/gptfast_sym_int_var_runnable.py.Runnable on Python older than 3.12: PEP 695/696 syntax is unavailable.
Use old-style type variables with a dual binding — IntVar from
shape_extensions under TYPE_CHECKING, typing.TypeVar at runtime — so
Generic[...] bases work and annotations (deferred via from __future__ import annotations) never evaluate:
if TYPE_CHECKING:
from shape_extensions import Int, IntVar
else:
from typing import TypeVar as IntVar
NState = IntVar("NState")
class Block(Generic[NState], nn.Module): ...There is no old-style equivalent of the IntTuple factory, so keep
everything fixed-rank; do not use whole-shape variables in such files.
Int binds runtime ints; IntVar bounds scalar dimension parameters and
IntTuple bounds variadic/whole-shape parameters. Bare *Bs is preferred in
check-only files, stubs, and deferred annotations. Use *Elements[Bs] when an
annotation evaluates eagerly, because a bare TypeVar is not iterable. Deferred
annotations can still be forced by typing.get_type_hints, so test any runtime
annotation consumer explicitly.
For a codebase that already uses jaxtyping, decide whether the goal is native
syntax or static checking with minimal churn. @static_jaxtyping("...") can
declare the dimension names so Pyrefly checks the existing jaxtyping
annotations; use that alternative when preserving source annotations matters.
If native syntax is requested, translate deliberately rather than mechanically.
An empty shape string may have been used as an escape hatch even when the value
is not scalar, and _ dimensions only promise rank. Use bare Tensor for
genuinely unconstrained inputs and Tensor[[int, ...]] when rank or fixed axes
are the useful contract.
If the model uses einops, include pyrefly-einops-stubs on the search path.
Those stubs compute shapes for rearrange, reduce, repeat, and einsum from
the pattern. Without them, a transform can incorrectly appear to preserve the
input shape. Patterns that require unsupported dynamic axes_lengths may still
return an unrefined Tensor; use a local cast justified by the pattern string,
for example cast("Tensor[[B, H * W, C]]", rearrange(...)).
Runtime-compatible annotations: assert_type is always a runtime no-op, but
its second argument and cast's first argument are ordinary expressions and are
still evaluated. Quote shape expressions that should not execute. If an eagerly
evaluated expression needs arithmetic on a PEP 695 dimension parameter, use
IntVar[N] (often imported as iv[N]) because bare N + 1 raises TypeError.
Import shape_extensions directly when runtime shape annotations are required.
© facebook, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 4 other files in tensor-shapes/skills/add-shape-types-to-torch-model of facebook/pyrefly.
Open the folder on GitHubat commit 331449e
Add Shape Types To Torch Model next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Add Shape Types To Torch Model this skillfacebook/pyrefly | 7.1k | — | ~13k | Automated safety check: Pass | MIT | |
| Add Uint Supportpytorch/pytorch | 104k | 2 repos | ~2.3k | Automated safety check: Pass | Custom licence | |
| CLIP Image-Text MatchingOrchestra-Research/AI-Research-SKILLs | 13k | 7 repos | ~1.7k | Automated safety check: Pass | MIT | |
| MUSA GPU Training Optimizeropen-infra-skills/infra-skills | 141 | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| Ghstack CIpytorch/pytorch | 104k | — | ~1.4k | Automated safety check: Pass | Custom licence | |
| Depth EstimationSharpAI/DeepCamera | 3.1k | — | ~945 | Automated safety check: Pass | MIT |
pytorch/pytorch
Add unsigned integer (uint) type support to PyTorch operators by updating ATDISPATCH macros.
Orchestra-Research/AI-Research-SKILLs
Explains OpenAI's CLIP model for zero-shot image classification, image-text similarity, semantic image search and content moderation, with install steps and code patterns.
open-infra-skills/infra-skills
Profiles, benchmarks and tunes AI training workloads on Moore Threads MUSA GPUs with a measurement-first process that keeps model behavior unchanged.
pytorch/pytorch
Manage CI for PyTorch ghstack stacks by running CI where its results are useful now and deferring other PRs with [no-ci].
SharpAI/DeepCamera
Real-time depth map privacy transforms using Depth Anything v2 (CoreML + PyTorch)
pytorch/executorch
Answers ExecuTorch questions from a local wiki on backends, export pitfalls, quantization recipes, runtime errors and SoC compatibility.
facebook/pyrefly
A skill your agent uses when adding a new PyTorch model to Pyrefly's shape-tracking example corpus under tensor-shapes/pyrefly-torch-stubs/examples — i.e.
facebook/pyrefly
Run Pyrefly benchmarks locally via Buck or Cargo, including PyTorch real-world LSP benchmarks.
facebook/pyrefly
A skill your agent uses when Pyrefly computes a wrong tensor shape (or is missing one that can't be expressed in a stub signature) and you need to add or fix a shape-DSL rule.
facebook/pyrefly
Produces a scorecard evaluating a pyrefly change on correctness and quality.
facebook/pyrefly
Reviews a comma separated pyrefly diff according to the pyrefly review best practices.
Works with
Categories
Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]). Add Shape Types To Torch Model is an agent skill from facebook/pyrefly, published by the product's own GitHub organization. Port a PyTorch model to use pyrefly's tensor shape type system (Tensor[[B, C, H, W]], Int[T]).
Add Shape Types To Torch Model fits situations like: the user wants to add shape annotations to a PyTorch model; type a model with tensor dimensions; port a model to use shape tracking; annotate model forward methods with tensor shapes.
Run `npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a claude-code`. Or copy the skill folder (tensor-shapes/skills/add-shape-types-to-torch-model in facebook/pyrefly) into .claude/skills/add-shape-types-to-torch-model in your project. Claude Code loads it when a task matches its description.
Run `npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a codex`. Or copy the skill folder (tensor-shapes/skills/add-shape-types-to-torch-model in facebook/pyrefly) into .agents/skills/add-shape-types-to-torch-model in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add facebook/pyrefly --skill add-shape-types-to-torch-model -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/add-shape-types-to-torch-model, .gemini/skills/add-shape-types-to-torch-model, .github/skills/add-shape-types-to-torch-model and .opencode/skills/add-shape-types-to-torch-model in your project.
Going by SKILL.md and its folder, Add Shape Types To Torch Model needs a shell for the scripts in its folder and the command-line tools its instructions call (python3). Our summary lists: A Bash shell.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Add Shape Types To Torch Model is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 13k tokens (SKILL.md is roughly 54k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Add Shape Types To Torch Model: Add Uint Support (pytorch/pytorch, 104k stars), CLIP Image-Text Matching (Orchestra-Research/AI-Research-SKILLs, 13k stars), MUSA GPU Training Optimizer (open-infra-skills/infra-skills, 141 stars) and Ghstack CI (pytorch/pytorch, 104k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
facebook (a GitHub organization, an official publisher) maintains it in facebook/pyrefly, which has 7,067 GitHub stars. The repository holds 6 skills in this directory. The repository was last updated on October 9, 2026.
Source: facebook/pyrefly on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.