skainet-model-loading — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited skainet-model-loading (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Loading pre-trained models in the four formats SKaiNET supports: GGUF (LLM weights, llama.cpp ecosystem), ONNX (cross-framework graph + weights), SafeTensors (HuggingFace weights), and the project's own JSON serialisation. Each format has a dedicated loader in skainet-io-*.
.gguf / .onnx / .safetensors / .json file from disk, classpath, or assets.Module built with sequential or dag.Unresolved reference: GGUFModelReader) — that's skainet-consumer-setup.skainet-nn-dsl + skainet-data-dsl.skainet-inference.AssetManager specifically — coordinate with skainet-android-integration.skainet-io-onnx if the consumer is only loading .gguf files; it brings pbandk and the protobuf runtime. Use the artifact picker in skainet-consumer-setup.OnnxLoader.load(), GGUFModelReader.loadTensor(name), SafeTensorsParametersLoader.load(...) are all suspend. Wrap from non-coroutine code with runBlocking { } only at the top level (CLI / test). In an Android ViewModel, use viewModelScope.launch { }.() -> RandomAccessSource (or suspend () -> Source). Open the file inside the lambda so the loader controls lifetime; never call .use { } outside.load<T, V>(ctx, dtype, …) overload — don't load to FP32 then cast() to a smaller dtype unless quantisation is intentional.skainet-compile-* (separate skill, separate concern).skainet-consumer-setup).load(...) — bind into your model's Module parameters or hold the ModelReader for streaming.| Format | Loader | When to pick |
|---|---|---|
| GGUF | GGUFModelReader | LLM checkpoints from llama.cpp / ollama; tokenizer metadata embedded; quantised weights (Q4_0, Q8_0, …). |
| SafeTensors | SafeTensorsParametersLoader | HuggingFace models; transformer weights; safe (no pickle). |
| ONNX | OnnxLoader<ModelProto> | Cross-framework models (PyTorch / TensorFlow exports); graph + weights together. |
| JSON | skainet-compile-json | SKaiNET's own portable serialisation; for round-tripping models built with the DSL. |
GGUF — `GGUFModelReader`:
import sk.ainet.io.gguf.GGUFModelReader
import sk.ainet.context.DirectCpuExecutionContext
import kotlinx.coroutines.runBlocking
val ctx = DirectCpuExecutionContext.create()
val reader = GGUFModelReader(/* source factory pointing at file */)
runBlocking {
val metadata = reader.metadata // Map<String, Any>: arch, vocab, etc.
val tensorInfos = reader.tensors // Map<String, TensorInfo>: shape + dtype per tensor
val qProj = reader.loadTensor("model.layers.0.self_attn.q_proj.weight")
// bind qProj into your model's parameters
}
reader.close()
// from: SKaiNET/skainet-io/skainet-io-gguf/src/commonMain/kotlin/sk/ainet/io/gguf/GGUFModelReader.kt (public surface)GGUF is streaming-friendly — loadTensor(name) reads one tensor at a time, suitable for large LLM weights that don't fit in memory at once.
SafeTensors — `SafeTensorsParametersLoader`:
import sk.ainet.io.safetensors.SafeTensorsParametersLoader
import sk.ainet.lang.types.FP32
import kotlinx.coroutines.runBlocking
val ctx = DirectCpuExecutionContext.create()
val loader = SafeTensorsParametersLoader(
sourceProvider = { createRandomAccessSource("model.safetensors") },
onProgress = { current, total, name ->
println("[$current/$total] $name")
}
)
runBlocking {
loader.load(ctx, FP32::class) { name, tensor ->
// bind 'name' -> 'tensor' into your Module's parameter map
}
}
// from: SKaiNET/skainet-io/skainet-io-safetensors/src/commonMain/kotlin/sk/ainet/io/safetensors/SafeTensorsParametersLoader.kt (public surface)SafeTensors is callback-driven — the loader hands you each tensor as it's parsed; you bind it where it belongs.
ONNX — `OnnxLoader.fromModelSource`:
import sk.ainet.io.onnx.OnnxLoader
import kotlinx.coroutines.runBlocking
import kotlinx.io.asSource
runBlocking {
val loader = OnnxLoader.fromModelSource {
java.io.File("model.onnx").inputStream().asSource()
}
val loaded = loader.load()
val proto = loaded.proto // ModelProto from pbandk
val rawBytes = loaded.rawBytes // for re-serialisation
// walk proto.graph.nodes / proto.graph.initializers
}
// from: SKaiNET/skainet-io/skainet-io-onnx/src/commonMain/kotlin/sk/ainet/io/onnx/OnnxLoader.kt (public surface)ONNX is a graph format — the loader hands you the protobuf representation. Lowering ONNX into a runnable SKaiNET Module is the next step (consumer apps typically use skainet-compile-* for that).
Source factories — common idioms:
// File on disk (JVM/desktop)
val src: () -> RandomAccessSource = { JvmFileRandomAccessSource(java.io.File("path")) }
// Classpath resource (server-side)
val src: () -> RandomAccessSource = {
val bytes = MyClass::class.java.getResourceAsStream("/model.gguf")!!.readBytes()
BytesRandomAccessSource(bytes)
}
// Android assets — see ../skainet-android-integration/SKILL.mdskainet-io-* artifact — ../skainet-consumer-setup/SKILL.md.../skainet-inference/SKILL.md.../skainet-nn-dsl/SKILL.md.../skainet-android-integration/SKILL.md.TokenizerFactory.fromGguf(...) — ../skainet-java-consumer/SKILL.md.// WRONG — calling a suspend loader from non-coroutine code
val loaded = loader.load() // compile error: 'load' is suspend// RIGHT — wrap in a coroutine builder appropriate to the host
runBlocking { val loaded = loader.load() } // CLI / test
viewModelScope.launch { val loaded = loader.load() } // Android ViewModel// WRONG — opening the file outside the loader's source factory
val source = JvmFileRandomAccessSource(File("model.safetensors"))
val loader = SafeTensorsParametersLoader(sourceProvider = { source })
// Now multiple loads share one already-opened source — no, the loader expects to control lifetime.// RIGHT — open inside the lambda
val loader = SafeTensorsParametersLoader(
sourceProvider = { JvmFileRandomAccessSource(File("model.safetensors")) }
)// WRONG — load to FP32 then cast to FP16
val tensor = loader.load(...) // FP32
val small = tensor.cast<FP16, Float>() // wastes the FP32 alloc// RIGHT — request FP16 directly from the typed loader overload
loader.load(ctx, FP16::class) { name, tensor -> ... }// WRONG — silently loading a multi-GB GGUF without progress feedback
val reader = GGUFModelReader(sourceProvider)
runBlocking { val w = reader.loadTensor("...") } // 30 second freeze// RIGHT — use loaders that accept onProgress, surface progress to the UI / log
val loader = SafeTensorsParametersLoader(sourceProvider, onProgress = { c, t, n -> ui.update(c, t) })references/loaders.md — full signature of every loader, with the suspending / non-suspending split and the entry-point factory methods.references/format-picker.md — extended decision tree for "I have a model file, which format is it and which loader?".~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.