CUDA kernels
SkillDev toolsLets your agent add, build, and call CUDA kernels in the prime-rl training codebase.
Then ask your AI: use the CUDA kernels skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add it as a step in a pipeline you build on Ahel, or connect Ahel to Claude, ChatGPT, Cursor, Claude Code or Codex and ask your AI to use it.
About this skill
How prime-rl vendors, builds, and ships CUDA kernels (the `deps/prime-kernels` submodule and the `prime-kernels` wheel). Use when adding a kernel, building it locally, calling one from training code, or publishing prebuilt wheels.
What this skill tells your AI
The instructions your AI receives, as published by primeintellect-ai/prime-rl in skills/kernels/SKILL.md and read by Ahel’s review.
CUDA kernels live in their own monorepo,
prime-kernels, checked out here as the
git submodule deps/prime-kernels, alongside prime-rl's other submodules. That repo is the
wheel root (setup.py, pyproject.toml) and prime_kernels/ inside it is the importable
package: one folder per kernel, holding the
kernel's Python surface and, for compiled kernels, its C++/CUDA sources under csrc/, all declared in the single
manifest prime_kernels/kernels.toml. See deps/prime-kernels/README.md once the submodule
is initialized.
Nothing about a kernel lives in prime-rl. prime-rl pins a prime-kernels commit for local source builds and a prime-kernels release for installs. prime-kernels builds and publishes its own wheels. prime-rl stays a pure-Python wheel; never add compiled extensions to it.
Living under deps/ means tool.ruff.extend-exclude = ["deps"] in pyproject.toml
already covers it — prime-rl lints none of it.
Calling a kernel from prime-rl
Kernels are compiled for exact compute capabilities and may not be built at all, so always
gate. Never import prime_kernels.<name> directly in training code:
import prime_kernels
if prime_kernels.is_available("flash_moe"):
flash_moe = prime_kernels.load("flash_moe")
prime_kernels.status() maps every kernel to "available" or the reason it is not — log
it once at startup rather than failing a run halfway through. unavailable_reason(name) is
the same answer for one kernel (None when it is usable), which is what a test's skip guard
wants; is_available is just that call compared to None.
flash_moe is a compiled fused MoE forward kernel (bf16 + mxfp8) on Blackwell
tcgen05. Its trainer integration is dormant. mxfp8_moe is a Python-only registered
kernel package for MXFP8 grouped GEMM and torch EP transport on SM100; it owns the
MoE-specific torchao-derived orchestration and exports explicit BF16 boundaries instead
of tensor-subclass interception.
What a kernel requires of its inputs — block sizes, alignments, shape constraints — belongs
to prime-kernels, which exports it: flash_moe.BLOCK_M, flash_moe.MXFP8_SCALE_BLOCK, and
flash_moe.unsupported_shape_reason(dim, hidden_dim, mxfp8=...). When the trainer integration
is restored, call this once during setup so an unsupported model fails before training rather
than mid-step. Never hardcode a 128 on this side: then every requirement change is a change
in both repos.
Building locally
uv sync --extra kernels installs the prebuilt wheel (see "Pinning installs at the prebuilt
wheels"); building from source is for changing kernels. It is manual by design — no uv sync
may compile CUDA, so the extra resolves to release wheels, never to this source tree:
git submodule update --init deps/prime-kernels
uv pip install --no-build-isolation -e deps/prime-kernels
Requirements: nvcc on CUDA_HOME with the same CUDA major as torch (torch refuses to
build extensions otherwise).
Kernels whose toolkit is unsuitable are skipped with a message and reported unavailable at
runtime — the build still succeeds. PRIME_KERNELS=a,b builds a subset;
PRIME_KERNELS_REQUIRE=1 turns any skip into an error.
Changing or adding a kernel
The work happens in the prime-kernels repo, not here. Inside deps/prime-kernels/:
- Commit the sources under
prime_kernels/<name>/csrc/. - Add a
[<name>]table toprime_kernels/kernels.toml—sources,include-dirs,arch,cxx-std; paths are relative to the kernel folder. A vendored Python kernel usespython-only = true, may declare import checks inrequires, and omits compiled extension fields. - Write
prime_kernels/<name>/__init__.py—from . import _C, then per op a wrapper callingtorch.ops.<ns>.<op>and atorch.library.register_fake. Notorch.library.custom_opdecorator: that defines a Python op, andTORCH_LIBRARYhas already defined these C++ side — only the fake (meta) kernel is missing. A kernel used in training also needstorch.library.register_autograd, since a schema carries no backward.flash_moeis forward only and currently has no trainer integration. - Nothing else:
setup.pyand the runtime registry both read the manifest.
Rules the build assumes:
- The extension is always
prime_kernels.<name>._C, so the C++ side definesPYBIND11_MODULE(_C, m)and registers ops withTORCH_LIBRARY*. archmatches the device exactly at runtime (10.0aruns only on sm_100a); no PTX is shipped to JIT from.- Two packages registering the same
torch.opsnamespace collide. If a kernel's sources are also installed as a standalone package (e.g.prime_moefrom prime-flash-moe, whereflash_moeoriginally came from), uninstall it. - Only the Python surface and the compiled
_Cship in the wheel;csrc/is build input.
Then land it in prime-rl as a submodule bump.
Bumping the pin
Kernel sources are pinned by the submodule commit, so picking up any kernel change — yours or someone else's — is a bump:
git -C deps/prime-kernels fetch origin
git -C deps/prime-kernels log --oneline HEAD..origin/main
git -C deps/prime-kernels checkout origin/main
git add deps/prime-kernels
Then, in order:
- Read the diff for host-side contract changes, not just kernel internals. A change to what the caller must pass (weight layout, scale packing, argument order) is silently wrong numbers, not a build error, and prime-rl's call sites have to absorb it.
- Rebuild and re-run the kernel repository's numerical coverage plus every PrimeRL runtime path that calls the changed kernel; the ABI is not checked for you.
- The bump alone ships nothing: installs resolve
prime-kernelsfrom a release wheel, so the new code only reaches users once a release rebuilds the wheels and the pin below moves.
Prebuilt wheels
The prime-kernels repository owns
build_kernels.yaml. It builds prime-kernels, deep-ep, deep-gemm, and torchao for
x86_64 and aarch64. It publishes the wheels as prime-kernels release assets.
Run that workflow in prime-kernels for each torch or CUDA bump:
gh workflow run build_kernels.yaml \
--repo PrimeIntellect-ai/prime-kernels \
-f release_tag=vX.Y.Z
The wheel version carries the ABI it was built against, e.g.
prime_kernels-0.1.0+cu130torch2.13.0-cp312-cp312-linux_x86_64.whl. It imports only under
that exact torch and CUDA ABI. prime-kernels CI controls the build dependency pins.
Pinning installs at the prebuilt wheels
uv sync --extra kernels installs prime-kernels from the wheels named in
[tool.uv.sources]. deep-ep, deep-gemm, torchao, and vLLM use the same pattern. A sync must
never compile these packages:
[tool.uv.sources]
prime-kernels = [
{ url = "https://github.com/PrimeIntellect-ai/prime-kernels/releases/download/vX.Y.Z/prime_kernels-0.1.0+cu130torch2.13.0-cp312-cp312-linux_x86_64.whl", marker = "platform_machine == 'x86_64'" },
{ url = "https://github.com/PrimeIntellect-ai/prime-kernels/releases/download/vX.Y.Z/prime_kernels-0.1.0+cu130torch2.13.0-cp312-cp312-linux_aarch64.whl", marker = "platform_machine == 'aarch64'" },
]
The wheels are prime-kernels release assets. Get the exact names before you move all pins:
gh release view vX.Y.Z \
--repo PrimeIntellect-ai/prime-kernels \
--json assets
Then run uv lock.
Move the pin when a kernel, torch, or CUDA pin changes. A stale pin ships stale kernels. A torch ABI mismatch fails at import, not at install.
Gotchas
- Keep the torch floor in prime-kernels aligned with prime-rl. The wheel imports only under the torch version it was compiled against.
- Never reintroduce
prime-kernelsas a path source: uv cannot read a source tree's metadata without building it, so everyuv lockwould then need nvcc. A release-asset URL has static metadata and does not. - A fresh prime-rl clone without the submodule still installs and trains. Only a local source
build needs it. prime-kernels CI sets
PRIME_KERNELS_REQUIRE=1, so a release cannot omit kernels silently.
Signals
- GitHub stars
- 2k
- Forks
- 455
- Last commit
- Oct 2026
Ahel review
K1binfo
installs-packages
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Item type
- skill
- Key
kernels- Source
- github.com/primeintellect-ai/prime-rl
github.com/primeintellect-ai/prime-rl