Skip to content
Back to skills

Mojo

ASecurity

Mojo development patterns for high-performance computing: SIMD vectorization, zero-copy Python interop, GIL-free parallelism, C FFI (external_call, DLHandle), Python C-API extensions, and Hatch build integration. Use when writing Mojo kernels or hybrid Python-Mojo projects.

  • 57 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 17, 2026
ai-agentspythongoc++bashtestinggitapibackendperformance

Works with

  • claude code
  • cursor
  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned October 17, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill mojo --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mojo?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mojo
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-mojo/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-mojo)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: mojo
description: "Mojo development patterns for high-performance computing: SIMD vectorization, zero-copy Python interop, GIL-free parallelism, C FFI (external_call, DLHandle), Python C-API extensions, and Hatch build integration. Use when writing Mojo kernels or hybrid Python-Mojo projects."
---

# Mojo (High-Performance Computing)

## Scope

- Work in `src/mo/` (Mojo source) and `src/py/` (Python wrapper).
- Build high-performance kernels for numeric, AI, and data-intensive workloads.
- Develop Python extensions using Mojo's native C-API features.
- Call C/C++ libraries via CFFI (`external_call`, `DLHandle`).
- Zero-copy data exchange between Python and Mojo.

## Core Rules

### Strict Typing

- **Prefer `fn` over `def`:** Strict type checking, predictable performance, deterministic behavior.
- Explicit types for all function arguments and return values.
- Use `alias` for compile-time constants.

```mojo
fn dot_product(a: SIMD[DType.float32, 8], b: SIMD[DType.float32, 8]) -> Float32:
    return (a * b).reduce_add()
```

### Memory Safety

- Leverage ownership semantics: `owned`, `borrowed`, `inout`.
- Document every use of `UnsafePointer` with a safety comment.
- Prefer stack allocation over heap when size is known at compile time.

```mojo
fn process(borrowed data: Tensor[DType.float32]) -> Tensor[DType.float32]:
    # borrowed: read-only, no copy, caller retains ownership
    var result = Tensor[DType.float32](data.shape())
    # ... transform ...
    return result^  # Transfer ownership to caller
```

### Tooling

- Use `uv` exclusively for Python environment management. Never `pixi` or `conda`.
- Use `mojo` CLI for compilation and testing.

## Docs Retrieval Policy (Modular)

Use Modular docs as the primary source of truth for Mojo behavior, MAX integration details, and assistant workflows.

Resolution order for reference context:

1. Use scoped reference files first:
- https://docs.modular.com/llms-mojo.txt
- https://docs.modular.com/llms-mojo-python.txt
- https://docs.modular.com/llms-mojo-kernel.txt
- https://docs.modular.com/llms-max.txt
2. Use https://docs.modular.com/llms.txt for broad discovery.
3. Use https://docs.modular.com/llms-full.txt only when scoped files are insufficient.

Doc-linking requirements:

- Prefer deep links to exact manual/API pages instead of only top-level doc hubs.
- Include source links when behavior depends on implementation details.
- Avoid version-pinned changelog anchors; link to the latest changelog root.

## Assistant Integration

Place shared Modular guidance in the assistant root context file for your environment:

- Codex / Gemini CLI: `AGENTS.md`
- Claude Code / Cline / Roo: `CLAUDE.md`
- Cursor: `.cursorrules` or `.cursor/rules`
- Windsurf: `.windsurfrules` or `.windsurf/rules`

For Codex-style instructions, require links under:

- MAX docs: `https://docs.modular.com/max/...`
- Mojo docs: `https://docs.modular.com/mojo/...`
- Source code: `https://github.com/modular/modular/tree/main/...`

## Performance: SIMD + Parallelize

### SIMD-First Vectorization

Replace scalar loops with SIMD operations:

```mojo
from algorithm import vectorize

fn relu_simd(inout tensor: Tensor[DType.float32]):
    alias simd_width = simdwidthof[DType.float32]()
    let zero = SIMD[DType.float32, simd_width](0)

    @parameter
    fn _relu[width: Int](idx: Int):
        let val = tensor.load[width=width](idx)
        tensor.store(idx, val.max(zero))

    vectorize[_relu, simd_width](tensor.num_elements())
```

**Rules:**
- Use `simdwidthof` to auto-detect hardware SIMD width.
- Use `@parameter` for compile-time loop specialization.
- Benchmark SIMD vs scalar — verify vectorization gives real speedup.

### GIL-Free Parallelism

True multi-core scaling without Python's GIL:

```mojo
from algorithm import parallelize

fn parallel_transform(inout data: Tensor[DType.float32], num_workers: Int):
    let chunk_size = data.num_elements() // num_workers

    @parameter
    fn _worker(worker_id: Int):
        let start = worker_id * chunk_size
        let end = min(start + chunk_size, data.num_elements())
        for i in range(start, end):
            data[i] = expensive_compute(data[i])

    parallelize[_worker](num_workers)
```

### Combined SIMD + Parallel

```mojo
fn process_large_dataset(inout data: Tensor[DType.float32]):
    alias simd_width = simdwidthof[DType.float32]()

    @parameter
    fn _chunk(chunk_id: Int):
        let offset = chunk_id * CHUNK_SIZE

        @parameter
        fn _vectorized[width: Int](idx: Int):
            let val = data.load[width=width](offset + idx)
            data.store(offset + idx, transform(val))

        vectorize[_vectorized, simd_width](CHUNK_SIZE)

    parallelize[_chunk](data.num_elements() // CHUNK_SIZE)
```

## Zero-Copy Python Interop

### Via __array_interface__

Exchange data with NumPy without copying:

```mojo
fn from_numpy(np_array: PythonObject) -> Tensor[DType.float32]:
    # Extract raw pointer from NumPy's array interface
    let interface = np_array.__array_interface__
    let data_ptr = interface["data"][0].to_int()
    let shape = interface["shape"]

    # SAFETY: np_array must remain alive while this tensor exists.
    # The pointer is valid for shape[0] * sizeof(float32) bytes.
    let ptr = UnsafePointer[Float32](address=data_ptr)
    return Tensor[DType.float32](ptr, shape[0].to_int())
```

### Returning Data to Python

```mojo
fn to_numpy(tensor: Tensor[DType.float32]) -> PythonObject:
    let np = Python.import_module("numpy")
    # Create NumPy array from Mojo tensor data
    return np.frombuffer(
        tensor.data().as_bytes(),
        dtype=np.float32
    ).reshape(tensor.shape())
```

## Python Extensions (C-API)

### Module Entry Point

```mojo
from python.module import PythonModuleBuilder

@export
fn PyInit_my_module() -> PythonObject:
    var builder = PythonModuleBuilder("my_module")
    builder.add_function("dot_product", dot_product_wrapper)
    builder.add_function("relu", relu_wrapper)
    return builder.build()
```

### Function Wrappers

```mojo
fn dot_product_wrapper(args: PythonObject) -> PythonObject:
    let a = args[0]  # NumPy array
    let b = args[1]  # NumPy array
    let result = dot_product_simd(
        from_numpy(a),
        from_numpy(b)
    )
    return to_numpy(result)
```

## C FFI (Calling C Libraries from Mojo)

### Static External Calls

Use `external_call` for compile-time linked C functions:

```mojo
from sys.ffi import external_call

fn get_time() -> Float64:
    # Calls C's clock_gettime via libc (linked at compile time)
    return external_call["clock", Float64]()

fn allocate_aligned(size: Int, alignment: Int) -> UnsafePointer[UInt8]:
    # SAFETY: Caller must free with aligned_free/free.
    return external_call["aligned_alloc", UnsafePointer[UInt8]](alignment, size)
```

**Rules:**
- First parameter is the C function name as a string literal.
- Second parameter is the Mojo return type.
- Remaining parameters are the arguments, which must map to C-compatible types.
- Only works for functions available at link time (libc, system libraries).

### Dynamic Library Loading (DLHandle)

Load shared libraries at runtime for plugin-style integration:

```mojo
from sys.ffi import DLHandle, c_char

fn load_custom_library():
    # Open shared library
    var lib = DLHandle("./libcustom_ops.so")

    # Get function pointer by name
    var compute_fn = lib.get_function[fn (UnsafePointer[Float32], Int) -> Float32](
        "custom_compute"
    )

    # Call the C function
    var data = UnsafePointer[Float32].alloc(1024)
    var result = compute_fn(data, 1024)

    data.free()
    # lib closes on drop (RAII)
```

**When to use DLHandle:**
- Loading vendor-specific acceleration libraries (CUDA, oneDNN, MKL).
- Plugin architectures where the library isn't known at compile time.
- Wrapping existing C/C++ libraries without recompilation.

### C Struct Mapping

Map C structs for FFI interop:

```mojo
@register_passable("trivial")
struct CTimeSpec:
    var tv_sec: Int64
    var tv_nsec: Int64

    fn __init__(out self):
        self.tv_sec = 0
        self.tv_nsec = 0

fn get_monotonic_time() -> CTimeSpec:
    var ts = CTimeSpec()
    # SAFETY: CTimeSpec layout matches C's struct timespec.
    # CLOCK_MONOTONIC (1) is always available on POSIX systems.
    external_call["clock_gettime", Int32](Int32(1), UnsafePointer.address_of(ts))
    return ts
```

**Rules:**
- Use `@register_passable("trivial")` for C-compatible structs (no destructor, copyable by memcpy).
- Ensure field layout matches the C struct exactly (same types, same order).
- Use `Int32`, `Int64`, `Float32`, `Float64` for exact-width C type mapping.

### C String Handling

```mojo
from sys.ffi import c_char

fn call_c_with_string(name: String):
    # Convert Mojo String to null-terminated C string
    var c_str = name.unsafe_cstr_ptr()

    # SAFETY: c_str is valid for the lifetime of `name`.
    external_call["puts", Int32](c_str)

fn read_c_string(ptr: UnsafePointer[c_char]) -> String:
    # SAFETY: ptr must point to a valid null-terminated C string.
    return String(ptr)
```

### Callback Patterns (C Calling Mojo)

Pass Mojo functions as C callbacks:

```mojo
alias CCallback = fn (UnsafePointer[Float32], Int) -> None

fn my_callback(data: UnsafePointer[Float32], len: Int) -> None:
    # Process data from C callback
    for i in range(len):
        data[i] = data[i] * 2.0

fn register_with_c_library():
    # Pass Mojo function as C function pointer
    external_call["register_callback", None](my_callback)
```

**Rules:**
- Callback functions must use C-compatible types only.
- Use `@always_inline("never")` if the callback needs a stable address.
- Document lifetime requirements — the callback must not outlive its data.

### Linking C Libraries

```bash
# Link system library at compile time
mojo build --link-lib "m" src/main.mojo          # libm (math)
mojo build --link-lib "ssl" src/main.mojo         # libssl

# Link custom shared library
mojo build --link-lib "custom_ops" --link-path "./lib" src/main.mojo
```

### C FFI Type Mapping

| C Type | Mojo Type |
|--------|-----------|
| `int` / `int32_t` | `Int32` |
| `long` / `int64_t` | `Int64` |
| `float` | `Float32` |
| `double` | `Float64` |
| `size_t` | `Int` |
| `char*` | `UnsafePointer[c_char]` |
| `void*` | `UnsafePointer[NoneType]` |
| `T*` | `UnsafePointer[T]` |
| `const T*` | `UnsafePointer[T]` (enforce read-only by convention) |
| `bool` | `Bool` |

## Build System (hatch-mojo)

Use [hatch-mojo](https://pypi.org/project/hatch-mojo/) — a Hatch build hook plugin for compiling Mojo sources into Python extensions, shared libraries, executables, and other artifacts.

### Minimal Setup

```toml
# pyproject.toml
[build-system]
build-backend = "hatchling.build"
requires = ["hatchling", "hatch-mojo"]

[project]
name = "my-package"
version = "0.1.0"
requires-python = ">=3.11"

[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "core"
input = "src/mo/my_pkg/core.mojo"
emit = "python-extension"
module = "my_pkg._core"
include-dirs = ["src/mo"]
```

```bash
# Build wheel with compiled Mojo extension
hatch build -t wheel
```

### Job Types (emit)

| `emit` Value | Output | Use Case |
|--------------|--------|----------|
| `python-extension` | `.so`/`.pyd` importable by Python | Primary — Mojo kernels callable from Python |
| `shared-lib` | `.so`/`.dylib` | Shared library for FFI consumers |
| `static-lib` | `.a` | Static linking into other builds |
| `executable` | Binary | CLI tools written in Mojo |
| `object` | `.o` | Object file for custom linking |

### Multiple Jobs with Dependencies

```toml
[tool.hatch.build.targets.wheel.hooks.mojo]
parallel = true         # Compile independent jobs concurrently
fail-fast = true        # Stop on first failure

# Reusable config profiles
[tool.hatch.build.targets.wheel.hooks.mojo.profiles.common]
include-dirs = ["src/mo"]

[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "core"
input = "src/mo/my_pkg/core.mojo"
emit = "python-extension"
module = "my_pkg._core"
profiles = ["common"]

[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "ops"
input = "src/mo/my_pkg/ops.mojo"
emit = "python-extension"
module = "my_pkg._ops"
profiles = ["common"]
depends-on = ["core"]    # Compiles after core

[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "cli"
input = "src/mo/cli.mojo"
emit = "executable"
depends-on = ["core"]
install = { kind = "scripts", path = "my-cli" }
```

### Platform-Conditional Compilation

```toml
[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "unix-accel"
input = "src/mo/accel_unix.mojo"
emit = "shared-lib"
platforms = ["linux", "darwin"]          # Skip on Windows
install = { kind = "package", path = "my_pkg/lib" }

[[tool.hatch.build.targets.wheel.hooks.mojo.jobs]]
name = "cuda-kernels"
input = "src/mo/cuda_*.mojo"            # Glob expansion
emit = "shared-lib"
marker = "platform_machine == 'x86_64'" # PEP 508 marker
install = { kind = "package", path = "my_pkg/cuda" }
```

### Global Configuration Options

| Key | Default | Description |
|-----|---------|-------------|
| `mojo-bin` | auto-detect | Path to mojo binary |
| `parallel` | `false` | Compile independent jobs concurrently |
| `fail-fast` | `true` | Stop on first failure (parallel mode) |
| `skip-editable` | `true` | Skip compilation for editable installs |
| `clean-before-build` | `false` | Remove build dir before compiling |
| `clean-after-build` | `false` | Remove build dir after compiling |
| `build-dir` | `.hatch_mojo` | Working directory for artifacts |
| `include` / `exclude` | `[]` | Global git-style glob filters |

### Mojo Binary Discovery

Priority order:
1. `mojo-bin` config value
2. `HATCH_MOJO_BIN` environment variable
3. `mojo` on `PATH`
4. `.venv/bin/mojo` relative to project root

### Install Mappings (non-Python artifacts)

For jobs with `emit` other than `python-extension`, specify where to install:

| `kind` | Description | Example `path` |
|--------|-------------|----------------|
| `package` | Inside Python package dir | `my_pkg/lib` |
| `scripts` | As executable script | `my-cli` |
| `data` | As package data | `data` |
| `root` | At package root | `lib` |
| `force-include` | Arbitrary path | `vendor/lib` |

### Manual Compilation (without hatch-mojo)

```bash
# Build shared library directly
mojo build --emit shared-lib src/mo/module.mojo -o src/py/package/_module.so

# Build standalone binary
mojo build src/mo/main.mojo -o dist/main

# Run directly
mojo run src/mo/main.mojo
```

## Testing

### Mojo Tests

```mojo
fn test_dot_product():
    let a = SIMD[DType.float32, 4](1.0, 2.0, 3.0, 4.0)
    let b = SIMD[DType.float32, 4](5.0, 6.0, 7.0, 8.0)
    let result = dot_product(a, b)
    assert_almost_equal(result, 70.0)
```

```bash
mojo test src/mo/tests/
```

### Python-Mojo Boundary Tests

```python
# tests/test_module.py
import numpy as np
from my_package._my_module import dot_product

def test_dot_product():
    a = np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float32)
    b = np.array([5.0, 6.0, 7.0, 8.0], dtype=np.float32)
    result = dot_product(a, b)
    np.testing.assert_almost_equal(result, 70.0)

def test_large_array_performance():
    """Verify Mojo kernel is faster than NumPy for large arrays."""
    a = np.random.randn(1_000_000).astype(np.float32)
    b = np.random.randn(1_000_000).astype(np.float32)

    import time
    start = time.perf_counter()
    result_mojo = dot_product(a, b)
    mojo_time = time.perf_counter() - start

    start = time.perf_counter()
    result_numpy = np.dot(a, b)
    numpy_time = time.perf_counter() - start

    np.testing.assert_almost_equal(result_mojo, result_numpy, decimal=1)
    # Mojo should be competitive or faster
    print(f"Mojo: {mojo_time:.6f}s, NumPy: {numpy_time:.6f}s")
```

```bash
uv run pytest tests/
```

## Project Structure

```
project/
├── pyproject.toml            # hatch-mojo config lives here
├── src/
│   ├── mo/                   # Mojo source
│   │   ├── my_pkg/
│   │   │   ├── core.mojo     # Python extension (emit: python-extension)
│   │   │   ├── ops.mojo      # SIMD/parallel kernels
│   │   │   └── layers.mojo   # Compute layers
│   │   └── tests/            # Mojo unit tests
│   └── py/                   # Python package
│       └── my_package/
│           ├── __init__.py   # Re-exports from _core
│           └── py.typed      # PEP 561
├── tests/                    # Python integration tests
├── benchmarks/               # Performance comparisons
└── .hatch_mojo/              # Build artifacts (gitignored)
```

## Conventions

- `fn` over `def` for all Mojo functions unless Python interop requires `def`.
- Explicit types everywhere — no type inference for function signatures.
- Document `UnsafePointer` usage with safety comments.
- Benchmark against NumPy/Python baselines and document results.
- Use `@parameter` for compile-time specialization.
- Keep Python wrappers thin — compute logic stays in Mojo.
- Use `uv` for all Python tooling (never `pip`, `pixi`, or `conda`).

## Official References

- https://docs.modular.com/max/coding-assistants
- https://docs.modular.com/max/coding-assistants/codex/
- https://docs.modular.com/llms-mojo.txt
- https://docs.modular.com/llms-mojo-python.txt
- https://docs.modular.com/llms-mojo-kernel.txt
- https://docs.modular.com/llms-max.txt
- https://docs.modular.com/llms.txt
- https://docs.modular.com/mojo/
- https://docs.modular.com/mojo/changelog/
- https://docs.modular.com/mojo/manual/testing/
- https://docs.modular.com/mojo/manual/python/mojo-from-python/
- https://docs.modular.com/mojo/stdlib/ffi/external_call/
- https://github.com/modular/modular/blob/main/.github/agents/AGENTS.md
- https://github.com/modular/modular/blob/main/.github/agents/CLAUDE.md
- https://pypi.org/project/hatch-mojo/

## Shared Styleguide Baseline

- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.
- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)
- [Python](https://github.com/cofin/flow/blob/main/templates/styleguides/languages/python.md)
- Keep this skill focused on tool-specific workflows, edge cases, and integration details.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.