MCPcopy Index your code
hub / github.com/Epistates/pmetal

github.com/Epistates/pmetal @v0.5.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.5.0 ↗ · + Follow
15,331 symbols 57,019 edges 750 files 5,779 documented · 38%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Crates.io Rust License Platform

PMetal

Powdered Metal — An ML SDK, framework, and application suite for Apple Silicon, written in Rust.

PMetal is a complete machine learning platform for Apple Silicon — from low-level Metal GPU kernels and Apple Neural Engine integration to high-level training APIs, a terminal TUI, and a full desktop GUI. Ship fine-tuned models without leaving the Apple ecosystem.

Use PMetal Your Way

Desktop GUI

pmetal screenshot showing GUI

A full Tauri + Svelte desktop application for visual model management, training, and inference.

cd crates/pmetal-gui
bun install && bun tauri dev

10 pages: Dashboard, Models, Datasets, Training, Distillation, GRPO, Inference, Merging, Quantize, and Settings. Download models from HuggingFace, configure LoRA training with live loss metrics, chat with models, merge weights, and quantize — all from the GUI. Training runs in-process with real-time progress updates.

Terminal TUI

pmetal screenshot showing TUI

A full-featured terminal control center with 9 tabs.

pmetal tui
Tab Description
Dashboard Live loss curves (braille), LR schedule, throughput sparklines, timing breakdown gauges
Device GPU/ANE info, Metal feature detection, memory gauge, kernel tuning, UltraFusion topology
Models Browse cached models, HuggingFace Hub search (S), memory fit estimation, download
Datasets Scan and preview local datasets (JSONL, Parquet, CSV) with line counts
Training Configure and launch SFT/LoRA/QLoRA training runs with sectioned parameter forms
Distillation Configure knowledge distillation (online, offline, progressive)
GRPO Configure GRPO/DAPO reasoning training with reward functions and sampling params
Inference Interactive chat interface with markdown rendering and generation settings sidebar
Jobs Training run history with log viewer, status tracking, and metadata

Keybindings: Tab/Shift+Tab to switch tabs, Alt+1-9 for direct access, L to adjust learning rate mid-run, q to quit.

CLI

# LoRA fine-tuning with sequence packing (default)
pmetal train \
  --model Qwen/Qwen3-0.6B \
  --dataset train.jsonl \
  --output ./output \
  --lora-r 16 --batch-size 4 --learning-rate 2e-4

# Inference with LoRA adapter
pmetal infer \
  --model Qwen/Qwen3-0.6B \
  --lora ./output/lora_weights.safetensors \
  --prompt "Explain quantum entanglement" \
  --chat --show-thinking

# Knowledge distillation
pmetal distill \
  --teacher Qwen/Qwen3-4B \
  --student Qwen/Qwen3.5-0.8B-Base \
  --dataset train.jsonl

# GRPO reasoning training
pmetal grpo \
  --model Qwen/Qwen3-0.6B \
  --dataset reasoning.jsonl \
  --reasoning-rewards

# HuggingFace model search with memory fit
pmetal search "qwen 0.6b" --detailed

# Merge models with SLERP
pmetal merge \
  --models model-a model-b \
  --method slerp --t 0.5

# Quantize to GGUF
pmetal quantize \
  --model ./output \
  --output model.gguf --type q4km

# Fuse LoRA into base model
pmetal fuse \
  --model Qwen/Qwen3-0.6B \
  --lora ./output/lora_weights.safetensors

# Evaluate perplexity
pmetal eval \
  --model Qwen/Qwen3-0.6B \
  --dataset eval.jsonl

# Start OpenAI-compatible server (requires --features serve)
pmetal serve --model Qwen/Qwen3-0.6B --port 8080

All CLI Commands

Command Description
train Fine-tune with LoRA/QLoRA/DoRA (SFT)
infer Interactive inference with chat, tool use, and thinking mode
distill Knowledge distillation (online, offline, progressive)
grpo GRPO/DAPO reasoning training (VLM, speculative, async rewards)
rlkd Reinforcement Learning with Knowledge Distillation
embed-train Sentence-transformer fine-tuning (InfoNCE, Triplet, CoSENT)
search Search HuggingFace Hub with memory fit estimation
download Download a model from HuggingFace Hub
merge Merge two or more models (12 strategies)
quantize GGUF quantization (13 format options)
fuse Fuse LoRA adapter weights into base model
eval Evaluate model perplexity on a dataset
serve OpenAI-compatible inference server (feature-gated)
tui Full TUI control center (9 tabs)
dashboard Real-time training metrics visualization
dataset Dataset utilities: analyze, download, convert
ollama Ollama integration: modelfile, create, templates
info Show device info (GPU, ANE, bandwidth, NAX)
memory Show memory usage and available capacity
init Generate a sample configuration file
bench Benchmark training performance
bench-gen Benchmark generation loop timing
bench-ffi Benchmark FFI overhead
bench-workload Benchmark real cached inference/training workloads
bench-corpus Structured kernel benchmarking with JSON reporting
mcp Start MCP server (45 tools for Claude Desktop / MCP clients)
cluster Multi-Mac cluster: discover peers, train across machines, run all-reduce / pipeline benchmarks

Multi-Mac Cluster (Thunderbolt-aware)

Connect two or more Apple Silicon Macs into a "home cluster" for distributed training and inference. PMetal auto-detects every NIC on the box (Thunderbolt-Bridge, Ethernet, Wi-Fi), advertises them via mDNS, and forms a ring biased toward the fastest fabric — Thunderbolt cables are picked over Ethernet, Ethernet over Wi-Fi, all without configuration.

# 1. Connect the Macs (Thunderbolt-4/5 cable recommended; Ethernet works too).
# 2. On every Mac:
pmetal cluster status        # Show local NICs + any peers already announcing.
pmetal cluster up            # Join the cluster, hold connection open.

# 3. On every Mac at the same time:
pmetal cluster bench --mb 64 --iters 10                  # All-reduce throughput per fabric.
pmetal cluster pipeline-bench --tokens 16 --layers 32    # Pipeline activation transport bench.

# 4. Distributed training (each Mac runs the same command simultaneously):
pmetal train --model Qwen/Qwen3-0.6B \
             --dataset train.jsonl   \
             --distributed-auto        # mDNS-discovers peers, all-reduce gradients.

pmetal cluster status example output:

Local peer: 12D3KooW…XyZ  (rank 0/2)
Thunderbolt ring: yes

Local interfaces:
  bridge0    thunderbolt   169.254.42.1
  en0        ethernet      192.168.1.10
  lo0        loopback      127.0.0.1, ::1

Cluster peers:
  peer-id                                   local  primary-addr           fabric        paths
  12D3KooW…XyZ                              yes    169.254.42.1:52416     thunderbolt   2
  12D3KooW…AbC                              no     169.254.42.2:52416     thunderbolt   2

What's wired today: gradient all-reduce (multi-machine training, real), fabric-aware ring formation with Thunderbolt > Ethernet > Wi-Fi priority, automatic fabric fallback when a cable is unplugged mid-job, gradient compression (TopK, FP16/BF16/INT8 quantization, error feedback), and a transport-tested pipeline harness with multi-process integration tests. Per-architecture partial-layer execution (the prerequisite for serving a model that doesn't fit on one Mac) is the next step — the harness is ready, the model API is the bottleneck.

SDK

PMetal is an embeddable SDK — integrate training, inference, and model operations into your own Rust applications. The easy module provides high-level builders, while the underlying crates (pmetal-trainer, pmetal-models, pmetal-lora, etc.) offer full control over every pipeline stage.

use pmetal::easy;

// Fine-tune with LoRA
let result = easy::finetune("Qwen/Qwen3-0.6B", "train.jsonl")
    .lora(16, 32.0)
    .learning_rate(2e-4)
    .epochs(3)
    .output("./output")
    .run()
    .await?;

// DPO preference optimization
let result = easy::dpo("Qwen/Qwen3-0.6B", "preferences.jsonl")
    .dpo_beta(0.1)
    .reference_model("Qwen/Qwen3-0.6B")
    .run()
    .await?;

// Inference
let output = easy::infer("Qwen/Qwen3-0.6B")
    .temperature(0.7)
    .lora("./output/lora_weights.safetensors")
    .generate("What is 2+2?")
    .await?;

// Streaming inference
easy::infer("Qwen/Qwen3-0.6B")
    .generate_streaming("Tell me a story", |delta| {
        print!("{delta}");
        true // return false to stop early
    })
    .await?;

Available builders: easy::finetune(), easy::dpo(), easy::simpo(), easy::orpo(), easy::kto(), easy::infer().

For lower-level control, use the crates directly — pmetal-trainer::TrainingLoop, pmetal-models::DynamicModel, pmetal-lora::DynamicLoraModel, pmetal-distill::Distiller, etc. See the examples/ directory for complete working examples including manual training loop orchestration and ANE-specific workflows.

Python SDK

PMetal exposes a Python extension module via PyO3. Install with maturin develop from crates/pmetal-py.

Quick Start (Easy API)

import pmetal

# Fine-tune with sensible defaults
result = pmetal.finetune(
    "Qwen/Qwen3-0.6B",
    "train.jsonl",
    lora_r=16,
    learning_rate=2e-4,
    epochs=3,
)
print(f"Loss: {result['final_loss']}, Steps: {result['total_steps']}")

# Inference
text = pmetal.infer("Qwen/Qwen3-0.6B", "What is 2+2?")
print(text)

# Inference with LoRA adapter
text = pmetal.infer(
    "Qwen/Qwen3-0.6B",
    "Explain quantum entanglement",
    lora="./output/lora_weights.safetensors",
)

Full Control

import pmetal

# Configure training components
lora_config = pmetal.LoraConfig(r=16, alpha=32.0)
training_config = pmetal.TrainingConfig(
    learning_rate=2e-4,
    num_epochs=3,
    batch_size=4,
    max_seq_len=2048,
)

# Create trainer
trainer = pmetal.Trainer(
    model_id="Qwen/Qwen3-0.6B",
    lora_config=lora_config,
    training_config=training_config,
    dataset_path="train.jsonl",
)
trainer.add_callback(pmetal.ProgressCallback())
result = trainer.train()

# Load model for inference
model = pmetal.Model.load("Qwen/Qwen3-0.6B")
print(model.generate("Hello world", temperature=0.7))

Installation

Prebuilt signed binaries are available on the Releases page.

Crates are available on crates.io.

Build from source:

git clone https://github.com/epistates/pmetal.git && cd pmetal
cargo build --release          # CLI + TUI
cd crates/pmetal-gui && bun install && bun tauri build  # GUI (optional)

Hardware Support

PMetal automatically detects Apple Silicon capabilities at startup and tunes kernel parameters accordingly.

Chip Family GPU Family NAX ANE UltraFusion Status
M1 / Pro / Max / Ultra Apple7 - 16 cores Ultra: 2-die Fully supported
M2 / Pro / Max / Ultra Apple8 - 16 cores Ultra: 2-die Fully supported
M3 / Pro / Max / Ultra Apple9 - 16 cores Ultra: 2-die Fully supported
M4 / Pro / Max / Ultra Apple9 - 16 cores Ultra: 2-die Fully supported
M5 / Pro / Max / Ultra Apple10 Yes 16 cores Ultra: 2-die Fully supported

Auto-detected features: GPU family, device tier, core counts, memory bandwidth, dynamic caching, mesh shaders, NAX (M5+), UltraFusion topology (via sysctl hw.packages), ANE availability.

Tier-based kernel tuning: Matrix tile sizes, FlashAttention block sizes, fused kernel threadgroup sizes, and batch multipliers are automatically selected based on device tier (Base/Pro/Max/Ultra) and GPU family. See docs/hardware-support.md for the full tuning matrix.

Architecture

PMetal is organized as a Rust workspace with 20 specialized crates:

pmetal/
├── pmetal-bridge       # Zero-allocation MLX C++ bridge (inline array FFI)
├── pmetal-core         # Foundation: configs, traits, types, error handling
├── pmetal-metal        # Custom Metal GPU kernels + ANE runtime
├── pmetal-mlx          # MLX backend integration (KV cache, RoPE, etc.)
├── pmetal-models       # LLM architectures (Llama, Qwen, DeepSeek, etc.)
├── pmetal-lora         # LoRA/QLoRA training implementations
├── pmetal-trainer      # Training loops (SFT, DPO, SimPO, ORPO, KTO, GRPO, etc.)
├── pmetal-data         # Dataset loading, chat templates, tokenization
├── pmetal-hub          # HuggingFace Hub integration + model fit estimation
├── pmetal-distill      # Knowledge distillation losses, offline caches, and TAID
├── pmetal-merge        # Model merging (14 strategies)
├── pmetal-gguf         # GGUF format with imatrix quantization
├── pmetal-mhc          # Manifold-Constrained Hyper-Connections
├── pmetal-distributed  # Distributed training (mDNS, Ring All-Reduce)
├── pmetal-vocoder      # BigVGAN neural vocoder
├── pmetal-serve        # OpenAI-compatible inference server
├── pmetal-mcp          # MCP server (51 tools for Claude Desktop)
├── pmetal-py           # Python bindings (maturin/PyO3)
├── pmetal-cli          # Command-line interface + TUI control center
└── pmetal-gui          # Desktop GUI (Tauri + Svelte + TailwindCSS)

The pmetal facade crate re-exports all modules with feature flags and provides the easy API for quick-start usage.

Supported Models

Inference (via DynamicModel dispatcher)

All causal language models below can b

Extension points exported contracts — how you extend this code

DistillLoss (Interface)
Trait for distillation loss functions. [14 implementers]
crates/pmetal-distill/src/losses/mod.rs
JobEventSink (Interface)
Receiver of [`JobEvent`]s. Implementors handle delivery (channel send, JSONL write, Tauri ipc emit, …). [6 implementers]
crates/pmetal-core/src/events.rs
ModelConfig (Interface)
Configuration common to all causal LM architectures. Each architecture (Llama, Qwen2, Gemma, etc.) implements this trai [14 …
crates/pmetal-models/src/traits.rs
RewardFunction (Interface)
Trait for GRPO Reward functions. [15 implementers]
crates/pmetal-trainer/src/grpo.rs
IndexOp (Interface)
Thin shim: `IndexOp` replacement for simple array-backed indexing. [30 implementers]
crates/pmetal-bridge/src/compat/indexing.rs
MergeMethod (Interface)
Trait for merge method implementations. [15 implementers]
crates/pmetal-merge/src/methods/mod.rs
LoraArchitectureConfig (Interface)
Architecture configuration trait for generic LoRA implementations. This module provides the `LoraArchitectureConfig` tr [7 …
crates/pmetal-lora/src/arch_config.rs
SlotForward (Interface)
Trait that the driver uses to invoke the model's forward pass. Kept generic so unit tests can inject a stub without ins [5 …
crates/pmetal-serve/src/continuous_driver.rs

Core symbols most depended-on inside this repo

unwrap
called by 3835
crates/pmetal-bridge/src/compat/layers.rs
clone
called by 2322
crates/pmetal-mhc/src/layer.rs
iter
called by 2255
crates/pmetal-serve/src/continuous_driver.rs
as_ref
called by 1426
crates/pmetal-bridge/src/compat/mod.rs
insert
called by 1425
crates/pmetal-gguf/src/imatrix.rs
collect
called by 1278
crates/pmetal-trainer/src/ane_reward.rs
reshape
called by 1240
crates/pmetal-bridge/src/inline_array/ops.rs
eval
called by 1213
crates/pmetal-mlx/src/neftune.rs

Shape

Method 6,893
Function 6,279
Class 1,732
Enum 321
Interface 106

Languages

Rust97%
C++2%
TypeScript1%
Python1%

Modules by API surface

crates/pmetal-models/src/architectures/qwen3_next.rs151 symbols
crates/pmetal/src/commands/bench.rs146 symbols
crates/pmetal-mlx/src/kv_cache/turboquant.rs133 symbols
crates/pmetal-gui/src-tauri/src/commands.rs124 symbols
crates/pmetal-gui/src/lib/api.ts121 symbols
crates/pmetal-metal/src/tuna.rs120 symbols
crates/pmetal-models/src/generation.rs111 symbols
crates/pmetal-bridge/src/compat/ops.rs101 symbols
crates/pmetal-bridge/src/compat/mod.rs100 symbols
crates/pmetal-gui/src/lib/stores.svelte.ts92 symbols
crates/pmetal/src/inference_runner.rs90 symbols
crates/pmetal-data/src/chat_templates.rs87 symbols

For agents

$ claude mcp add pmetal \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact