Use this skill when adding a new optimized kernel or operator to veomni/ops/. Covers the full lifecycle: understanding VeOmni's ops architecture (KERNEL_REGISTRY + OpSlot dispatch, with a thin function-pointer shim for a few legacy global ops), implementing the kernel, registering it, adding tests, and documenting it. Trigger: 'add op', 'new kernel', 'add attention variant', 'new fused op', 'add triton kernel', 'optimize operator'.
72
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
.agents/knowledge/constraints.md — especially the "Hardware" section
(NPU guards, device-agnostic helpers) and "Module-level OpSlots are shared by
every model instance" under "Trainer Extensions".docs/design/kernel_selection.md and docs/design/unified_kernel_registry.md — understand the kernel lifecycle, the KERNEL_REGISTRY, and OpSlot dispatch.Most VeOmni ops in v5 are registry-driven: a kernel registers itself in
veomni.ops.kernel_registry.KERNEL_REGISTRY and is dispatched at model-build
time through OpSlot instances declared in the patchgen-generated modeling
files (see veomni/ops/dispatch.py and _bind_veomni_ops() in
veomni/models/auto.py).
veomni/ops/
├── __init__.py # apply_ops_patch / apply_ops_config entry points
├── kernel_registry.py # KERNEL_REGISTRY (the single source of truth)
├── dispatch.py # OpSlot + binding helpers
├── config/ # legacy OpSpec/BackendSpec registry: apply_global_ops()
│ # + apply_per_model_patches() for device_patch.py models
├── kernels/ # all registry-driven kernels
│ ├── attention/ # FA2/3/4 + sequence-parallel wrappers
│ ├── cross_entropy/ # eager + liger fused CE
│ ├── deepseek_sparse_attention/
│ ├── deepseek_v4/ # TileLang sparse attention / indexer
│ ├── load_balancing_loss/
│ ├── mhc/ # TileKernels DeepSeek V4 adapters
│ ├── moe/ # fused MoE (group_gemm / quack / npu_group_gemm)
│ ├── rms_norm/ # eager / liger / batch-invariant
│ ├── rotary/ # default / triton-deterministic
│ ├── swiglu/ # eager / liger
│ └── gated_delta_rule/
├── batch_invariant_ops/ # ATen-level interception for bitwise determinism
├── liger/ # Liger kernel adapters
└── platform/ # NPU-specific helpersThree mechanisms coexist. Pick the first one unless you have a concrete reason not to:
KERNEL_REGISTRY + OpSlot (preferred for new ops). Each kernel
registers itself under a (slot_name, variant) pair (e.g.
("cross_entropy_loss", "causal"), ("moe_experts", "standard")).
Patchgen-generated modeling code declares matching OpSlot instances; at
model-build time _bind_veomni_ops() walks the generated module, finds
each OpSlot, and binds it to the concrete registry entry chosen by
OpsImplementationConfig (config/registry.py).fused_moe_forward and load_balancing_loss still expose a thin pointer
that is rebound by apply_ops_config() so call sites in non-patchgen code
(DeepSeek MLA inference paths, NPU custom forwards) can keep importing the
public name without going through an OpSlot.device_patch.py via OpSpec/BackendSpec in
ops/config/registry.py. apply_per_model_patches(hf_module, model_name, targets={op: attr}) setattr-replaces attributes on an HF module. Used by the
models that have no patchgen-generated file (wan) or that need a runtime
device-specific swap after generation (deepseek_v3, deepseek_v4). Those
three device_patch.py files are its only callers. Do not extend this for
new kernels.Mechanism 1 covers any kernel living inside a patchgen-generated modeling file.
Use 2 only when the kernel must be callable from unpatched (or
non-Transformers) Python code, and 3 only when touching a model that already
ships a device_patch.py.
Determine op category:
(slot_name, variant) in KERNEL_REGISTRY and add a matching OpSlot in the relevant <model>_patch_gen_config.py. No global mutation; selection is driven by OpsImplementationConfig.fused_moe_forward, load_balancing_loss): expose a public function in veomni/ops/__init__.py and rebind it from apply_ops_config() based on the active OpsImplementationConfig. Only use this when a non-patchgen call site (NPU MLA forward, manual inference scripts, etc.) needs to import the kernel directly.is_torch_npu_available() guard.Decide selection mechanism: read docs/design/kernel_selection.md and docs/design/unified_kernel_registry.md to determine if you need:
OpsImplementationConfig (veomni/arguments/arguments_types.py)Determine binding timing:
_bind_veomni_ops() in veomni/models/auto.py when a model is constructed. New kernels just need to register themselves at import time.apply_ops_config() time: legacy global ops (rebound function pointers) are wired in veomni/ops/__init__.py::apply_ops_config(ops_config).Create the op directory under veomni/ops/kernels/<op_name>/.
Implement each kernel variant in its own file (e.g. triton_kernel.py, eager.py, npu_kernel.py). Each variant declares a concrete function with the kernel's canonical signature.
Register the kernel in veomni/ops/kernels/<op_name>/__init__.py. One
KERNEL_REGISTRY.register(KernelSpec(...)) call per implementation —
register() takes a single KernelSpec and returns None, so it is not a
decorator:
from veomni.ops.kernel_registry import KERNEL_REGISTRY, HardwareRequirement, KernelSpec
def _my_op_triton_factory():
from .triton_kernel import my_op_triton # imported only when selected
return my_op_triton
KERNEL_REGISTRY.register(
KernelSpec(
name="triton", # impl name the user selects in the config
op_name="my_op", # the logical op — matches the OpSlot
variant="standard", # op shape, when one op has several
factory=_my_op_triton_factory,
hardware=HardwareRequirement(device_type="gpu"),
description="Triton my_op",
)
)factory is a zero-argument callable returning the kernel, not the
kernel itself. Keeping it lazy is what stops an optional dependency (Liger,
Triton, torch_npu) from being imported just because the module was loaded.
hardware is enforced at resolve() time, so an unavailable kernel fails
with a clear error instead of at first use.
Mind the two axes: (op_name, variant) identifies the slot, name
identifies the implementation within it. Kernels in different variants
never collide.
Then declare a matching OpSlot in the patchgen config of every model that
uses it — the arguments are (op_name, variant), not an implementation:
from veomni.ops.dispatch import OpSlot
veomni_my_op = OpSlot("my_op", "standard")_bind_veomni_ops() calls slot.bind(impl_name) with the implementation
selected by OpsImplementationConfig. See
veomni/ops/kernels/rotary/__init__.py for a live example, and
veomni/ops/README.md for the op/variant/impl table.
Wire the config field (if the user needs to choose an implementation):
OpsImplementationConfig in veomni/arguments/arguments_types.py.register_op(OpSpec(name=..., config_field=..., scope=..., default=..., backends={...}))
from the same veomni/ops/kernels/<op_name>/__init__.py — the mapping
lives next to the kernel, not inside veomni/ops/config/registry.py,
which only defines OpSpec / BackendSpec / register_op. See
veomni/ops/kernels/rms_norm/__init__.py, which registers both an
OpSpec and its KernelSpecs.For legacy global ops (only when needed): add the public function to veomni/ops/__init__.py and rebind it from apply_ops_config(ops_config).
Async Ulysses split wrappers (only for rms_norm and rotary_pos_emb): compound Functions cannot call OpSlot. They use no-autograd (output, saved) / backward pairs in veomni/distributed/sequence_parallel/op_wrappers.py. A new backend or variant must either add a matching wrapper there, or be left off _SUPPORTED_IMPLEMENTATIONS / _SUPPORTED_VARIANTS so get_op_wrapper rejects it. KERNEL_REGISTRY coverage is not enough.
NPU support:
is_torch_npu_available().npu_kernel.py).Add unit tests to tests/ops/. The GPU job runs this directory
wholesale, so a new file needs no gpu_unit_tests.yml change. The NPU job
does not — it enumerates ops files by name, so if the kernel must run on
Ascend, add a line to npu_unit_tests.yml (see
.agents/knowledge/testing.md):
Add benchmark (optional but recommended for performance-critical ops):
veomni/ops/kernels/moe/_kernels/utils/benchmark_utils.py as referenceRun: pytest tests/ops/ -v
Update docs/design/kernel_selection.md:
Update .agents/knowledge/architecture.md if the op adds a new subdirectory to veomni/ops/.
make quality.KERNEL_REGISTRY.dump() and that the relevant OpSlot is rebound after build_foundation_model./veomni-review over the branch diff — a new kernel touches veomni/, so the gate applies.KERNEL_REGISTRY: the variant is invisible to _bind_veomni_ops() and OpSlot will fall through to its default — you'll silently exercise the wrong kernel.OpSlot to the patchgen config: registering a kernel alone has no effect — generated modeling code must declare an OpSlot for it to be picked up.is_torch_npu_available() guard crashes on GPU-only environments.build_foundation_model runs _bind_veomni_ops(). Kernels that depend on per-model config must be picked at that point — not at module-import time.rms_norm / rotary_pos_emb backend without an async wrapper: OpSlot will bind, but async Ulysses goes through op_wrappers.py, not the registry callable. Add a split wrapper or confirm get_op_wrapper rejects the new name; do not derive the supported set from KERNEL_REGISTRY.get_parallel_state().sp_enabled to check and dispatch.veomni/ops/__init__.py's __all__.b8a3edc
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.