
Open-source deep learning framework simplifies creation of modern AI applications, adhering to GitFlow for branching and Semantic Versioning for release management.
Click the diagram for the full architecture reference, or read the short ARCHITECTURE.md.
SKaiNET is a Kotlin Multiplatform AI framework. New here? Choose the path that matches what you want to try first.
| Goal | Start here | Time |
|---|---|---|
| Run tensor operations | Quickstart (below) | 2–5 min |
| Build and train a neural net | Hello Neural Net (below) | 5 min |
| Run a local GGUF model | SKaiNET Transformers starter | 5 min after model setup |
| Export a secure MCU bundle | Minerva getting started | 10 min without firmware flashing |
Working in Java? SKaiNET ships first-class Java support — see the Java getting-started guide.
[!NOTE] Looking for LLM inference? Llama, Qwen, Gemma, Apertus, BERT embeddings and GGUF chat models live in SKaiNET-transformers — this repository is the engine underneath it (tensors, NN DSL, compiler, CPU/native backends, GGUF/SafeTensors IO). Depend on the
sk.ainet.transformersartifacts, pinned together by the transformers BOM.
Use the version shown in this README as the source of truth for first-run snippets. If another page shows a different version, please open an issue or PR.
Add the core dependencies (Gradle Kotlin DSL):
dependencies {
// Recommended: import the umbrella BOM and drop versions on the engine modules.
implementation(platform("sk.ainet:skainet-bom:0.62.4"))
implementation("sk.ainet.core:skainet-lang-core")
implementation("sk.ainet.core:skainet-backend-cpu")
}val model = nn {
input(28 * 28)
dense(out = 128)
relu()
dense(out = 10)
}val a = tensor(shape(2, 2)) { float(1f, 2f, 3f, 4f) }
val b = tensor(shape(2, 2)) { float(5f, 6f, 7f, 8f) }
val c = a matMul b
val d = c.relu()// Recommended: streaming reader — memory-efficient, supports quantized types
val source = JvmRandomAccessSource.open("model.gguf")
StreamingGGUFReader.open(source).use { reader ->
println("Tensors: ${reader.tensorCount}")
// Load specific tensor on demand (no whole-file loading)
val bytes = reader.loadTensor("token_embd.weight")
// Or get a TensorStorage descriptor with encoding/placement metadata
val storage = reader.loadTensorStorage("token_embd.weight")
}More examples: SKaiNET-examples | SKaiNET-notebook
SKaiNET is a modular ecosystem. While this repository contains the core engine, specialized high-level libraries are maintained in standalone repositories:
| Project | Description |
|---|---|
| SKaiNET-transformers | Pre-built transformer architectures and layers |
| SKaiNET-examples | Sample projects and integration demos |
| Goal | Start here |
|---|---|
| Examples and sample projects | SKaiNET-examples |
| Interactive notebooks | SKaiNET-notebook |
| Eager backends & kernels (what runs where) | Backends & kernels map |
| Design proposals and long-lived API decisions | SKEEP proposals |
| Memory & storage architecture (storage, views, scopes, planning) | The memory model · Packed weight layout |
First time here? Three links are all you need:
skill:android, skill:numerics (no Kotlin), skill:docs, or by size: size:xs.[Lane N · skill] title prefix means.Small fixes can go straight through the normal contribution flow described in CONTRIBUTING.md and GITFLOW.adoc.
Non-trivial work goes through one of two processes:
docs/modules/skeep/pages/ with three-digit numbering. See the
SKEEP index.SKaiNET ships an official Phoronix-Test-Suite-compatible benchmark
program for the compute engine. See the
methodology and replay docs,
the release manifest, and the
CI workflow. Smoke runs fire
on every PR via ubuntu-latest; full publishable runs fire on a
self-hosted Linux x86 runner on release.
Quick local replay:
./gradlew :skainet-backends:benchmarks:jvm-cpu-publish:shadowJar
./scripts/run_engine_smoke.shSKaiNET is built around one path: a model is defined once in the Kotlin DSL, then either compiled or executed eagerly — without rewriting it.
nn { } / dag { }).ComputeGraph.ComputeGraph through one of several
sibling code-generation backends, each emitting code for a different target
from the same graph:
HloGenerator) → IREE-compilable, for native / edge /
accelerator targets and the wider MLIR ecosystem.StableHLO/MLIR is therefore one code-generation backend among siblings — the IREE/native path next to the C99/Arduino and Minerva MCU paths — not a separate pipeline.
flowchart LR
DSL["Model — Kotlin DSL"] --> Graph["Tape / DAG (ComputeGraph)"]
Graph --> Eager["Eager backend (JVM, …)"]
Graph -->|code generation| HLO["StableHLO / MLIR"]
Graph -->|code generation| C99["Arduino / C99"]
Graph -->|code generation| Minerva["Minerva"]
HLO --> Native["IREE → native / edge / accelerator"]
C99 --> MCU["Microcontroller"]
Minerva --> SecMCU["Secure-MCU bundle"]The same DSL model feeds every path: eager execution for development and JVM deployment, and the code-generation backends — StableHLO/MLIR (→ IREE), Arduino/C99, and Minerva — as sibling alternatives for native, edge, and secure-MCU targets.
SKaiNET now includes a Minerva export backend for secure MCU deployment. It is a sibling to StableHLO and Arduino/C99 export: it starts from a supported ComputeGraph, lowers static MLPs to a Minerva compiler input, invokes libminerva when configured, and packages generated weights, host fixtures, firmware skeletons, and a fingerprinted manifest.json.
Start here:
Runnable examples:
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaSecureMcuExamples
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaSecureMcuExamples \
-Pminerva.example=sensor-classifiersafe-lowbit, balanced, experimental-max. See TurboQuantUsage for integration guide.nn { input(); dense(); relu(); dense() }
dag { } for ResNet-style skip connections and multi-scale detector headsfile://, https://, hf+https://, and hf://...
.jsonl, .ndjson)val raw = JvmDataSourceResolver().rawDataset {
from("hf://datasets/org/repo@main/train.jsonl")
format(DataFormat.JSON_LINES)
cachePolicy(CachePolicy.Use)
}
val withoutLabel = dataPipeline<RawDataset>()
.stage(
dataTransformer(
name = "drop-label",
outputSchema = { schema -> DataSchema(schema.columns - "label") }
) { dataset ->
val columns = dataset.schema.columns - "label"
dataset.copy(
schema = DataSchema(columns),
rows = dataset.rows.map { row ->
RawDataRow(row.values.filterKeys { key -> key in columns })
}
)
}
)
.execute(raw)HloGenerator
An arm64 release. On macOS the JVM's dense FP32 products — A · B on heap or segment-backed operands and x · Wᵀ
on a resident dense weight — now go to Accelerate's SGEMM by default, which runs on the matrix units of Apple
silicon and threads itself; JvmBlas had never reached a BLAS before (the framework lookup and the heap downcall
both failed silently), and -Dskainet.cpu.blas.enabled=false restores the bundled kernels. Elsewhere the default
stays off and skainet.cpu.blas.library names an OpenBLAS or reference BLAS to use. The native dense FP32 kernels
get register tiles on AArch64 (Apple silicon, Android arm64, Linux arm64): an 8 × 8 tile of lane-indexed FMAs over a
packed panel of B for A · B and a four-by-three tile for x · Wᵀ, bit-identical across slices, threads and whole
calls, exercised on Apple silicon by the macOS CI leg. Both are unmeasured on arm64 in this release; the pull
requests (#1449, #1450) say how to run the bench.
A load-time and kernel release. StreamingGGUFReader decodes the GGUF metadata from 64 KB blocks instead of one
source read per value, and TextFrontEnds.fromGguf builds a SentencePiece tokenizer in one pass over the vocabulary
instead of three to four copies of it; fields, the public API and the token ids stay the same. On a Gemma-3
tokenizer GGUF a file-source parse drops from 1.0 s to 21–45 ms on the JVM and from 23.3 s to 1.2 s on a 32-bit ARM
Android device, where read + build on the first load in a process goes from 8.4–11.2 s to 6.0–6.4 s. The native
dense FP32 A · B kernel gets an AVX2/FMA register-tiled lane on x86-64 (63 × 1024 × 1024: 21 → 281 GFLOP/s), and
no longer overwrites the parts of a sub-block caller's output buffer outside the block.
A performance release for the JVM native lane. The dense FP32 x · Wᵀ kernel — what every resident dense
weight resolves to once skainet-backend-native-cpu is on the classpath — now splits its work across the
context Schedule (SKEEP-005) instead of a fixed four-thread C pool, and on x86-64 hosts with AVX2 and FMA
runs a runtime-selected eight-lane register-tiled lane; threaded, sliced and single calls stay bit-identical.
A single 63 × 1024 × 1024 call goes from 29.6 to 131.7 GFLOP/s on a six-core laptop, and a ModernBERT-large
encoder request in the LayaMoE example from 13.0 s to 6.4 s with unchanged answers. The text front-end
indexes added tokens by first character and length, so a Gemma chat turn encodes in 36 µs instead of 2.0 ms.
CoroutineSchedule.forRange never hands a body an empty range any more.
A fix release on top of 0.62.0: the native FFM bindings of the Q8_0, Q4_0, Q5_0 and Q5_1 kernels
copied a zero-filled staging buffer back from index 0, so a product served row by row — any
quantize-at-load encoder on the JVM with skainet-backend-native-cpu on the classpath — kept only
its last row. Single-row decode steps were never affected. A regression test now covers every packed
format for one, seven and fifty rows. Also: the YOLOv8 model code moves out of core into its cartridge
blueprint (skainet-model-yolo is gone; Letterbox, BoundingBox and nonMaxSuppression stay in
skainet-data-media), the StableHLO softmax axis and logSoftmax lowering are fixed, and the docs
gain Flexibility at every compile stage and the SKEEP-008 draft on precision and encoding conversion.
JVM ↔ Kotlin/Wasm parity: the browser tier runs the same kernels as the JVM, keeps its activations in the sidecar, and reads models the way the JVM does — with every remaining difference documented.
Storage.OffHeap in a browser) and come back to the Kotlin heap only when
something outside needs them.x · Wᵀ kernel
(no transposed weight copy), fused softmax, layer and RMS normalisation, and SDPA with
key lengths, windows and grouped-query heads. One C source per kernel serves every native build.Blob sources address Long positions (shards over 2 GB), copy in bulk, and
serve blocking reads inside a Web Worker; sharded SafeTensors load from Blobs;
PlannerProfile.BROWSER; MemoryProbe reports the JavaScript heap, linear memory and the
sidecar's resident bytes; skainet-data-source resolves HTTP and Hugging Face URIs over fetch
on Kotlin/JS and Kotlin/Wasm.engine-* scenarios of the JVM publish harness run with identical
shapes in wasm-bench, and the kernel support matrix names what each tier serves and why the
rest is N/A. The operator coverage matrix is generated from backend data, with StableHLO, backward
and NN-layer columns and a CI leg that rejects unmarked stubs.split fast
path and bulk copies from mapped tensors.See CHANGELOG.md for full release notes, including every prior release.
We love contributions! Whether it's a new operator, documentation, or a bug fix:
Browse the full codebase documentation on DeepWiki.
CoroutineSchedule fix, the added-token index, and
the releasex · Wᵀ kernels, resident
activations with the elementwise, fused and convolution kernels on both tiers, the browser IO
parity, skainet-data-source on JS and wasm, the operator coverage matrix, the BitNet decode
allocation fixes, and the releaseClassificationSupport helpers extracted
from Accuracy, preparing the precision, recall and F1 metrics (#1222)skainet-quantize, the skainet-backend-wasm-simd sidecar kernel pack, the
scheduled SKEEP-006 removal, and the releasescaledDotProductAttention across the CPU kernel, recorder, executor
and StableHLO lowering, the n-ary composite seam with the skainet.sdpa composite, the
SKEEP-006 deprecation step, and the releaseerf
across the CPU kernels, graph executor and backward rules, the lowering-metadata path with
composite emission and the legalization pass, and the releasescaledDotProductAttention and its StableHLO lowering, structural schedule defaults, and
schedule-aware graph execution contexts (SKEEP-005 phase 2)BufferHandle.Floats path, and the sharded SafeTensors loaderViewKernelPack SPI, dense FP32 for mapped/off-heap
storage, the decode-shaped FP32 kernel work, Android-native targets across the downstream
chain, and the ternary packs joining the self-healing SPISEQUENTIAL I2_S, the AOT GGUF converter and its IREE-facing
counterpart in SKaiNET-IREE-tools, and the scoped dense-FP32 activation matmul-chooser fixtranspose() block-grid correctness fix, all three kernel tiers (#968, #969)DEQUANTIZE_TO_FP32 over-allocation fix (#782), native Q5_0/Q5_1 packed matmul kernels (#708), Apple arm64 runtime FEAT_DotProd dispatch (#958), Apple iOS/macOS Kotlin/Native kernel targets (#959)createRandomAccessSource streaming loads (#922), cinterop klib archive embedding (#942), Q4_0 NEON kernel (#939), GGUF loader fail-fast (#919), tensor-storage correctness fixes (#927, #928, #929, #930, #931), AAR release publishing (#947)Lstm layer (#824), Dropout masking (#867), LR schedules (#866), optional/open Linear (#870, #875), SDPA scale fix (#880), autograd fixes (#877), argMax DAG spec (#878), tokenizer + gather fixes (#879), Android native IO targets (#836, #842, #845)If you use SKaiNET in your research, please cite it. Citation metadata lives in
CITATION.cff (GitHub's Cite this repository button exports BibTeX and APA
from it). Ready-to-paste BibTeX:
@misc{skainet,
author = {Harakal, Michal and {SKaiNET-developers contributors}},
title = {{SKaiNET}: A {Kotlin} Multiplatform {AI} Framework},
year = {2026},
note = {Version 0.62.4. MIT License},
howpublished = {\url{https://github.com/SKaiNET-developers/SKaiNET}}
}Please include the version you used (each release is tagged).
MIT — see LICENCE.
Click the diagram for the full architecture reference, or read the short ARCHITECTURE.md.
SKaiNET is a Kotlin Multiplatform AI framework. New here? Choose the path that matches what you want to try first.
| Goal | Start here | Time |
|---|---|---|
| Run tensor operations | Quickstart (below) | 2–5 min |
| Build and train a neural net | Hello Neural Net (below) | 5 min |
| Run a local GGUF model | SKaiNET Transformers starter | 5 min after model setup |
| Export a secure MCU bundle | Minerva getting started | 10 min without firmware flashing |
Working in Java? SKaiNET ships first-class Java support — see the Java getting-started guide.
[!NOTE] Looking for LLM inference? Llama, Qwen, Gemma, Apertus, BERT embeddings and GGUF chat models live in SKaiNET-transformers — this repository is the engine underneath it (tensors, NN DSL, compiler, CPU/native backends, GGUF/SafeTensors IO). Depend on the
sk.ainet.transformersartifacts, pinned together by the transformers BOM.
Use the version shown in this README as the source of truth for first-run snippets. If another page shows a different version, please open an issue or PR.
Add the core dependencies (Gradle Kotlin DSL):
dependencies {
// Recommended: import the umbrella BOM and drop versions on the engine modules.
implementation(platform("sk.ainet:skainet-bom:0.62.4"))
implementation("sk.ainet.core:skainet-lang-core")
implementation("sk.ainet.core:skainet-backend-cpu")
}val model = nn {
input(28 * 28)
dense(out = 128)
relu()
dense(out = 10)
}val a = tensor(shape(2, 2)) { float(1f, 2f, 3f, 4f) }
val b = tensor(shape(2, 2)) { float(5f, 6f, 7f, 8f) }
val c = a matMul b
val d = c.relu()// Recommended: streaming reader — memory-efficient, supports quantized types
val source = JvmRandomAccessSource.open("model.gguf")
StreamingGGUFReader.open(source).use { reader ->
println("Tensors: ${reader.tensorCount}")
// Load specific tensor on demand (no whole-file loading)
val bytes = reader.loadTensor("token_embd.weight")
// Or get a TensorStorage descriptor with encoding/placement metadata
val storage = reader.loadTensorStorage("token_embd.weight")
}More examples: SKaiNET-examples | SKaiNET-notebook
SKaiNET is a modular ecosystem. While this repository contains the core engine, specialized high-level libraries are maintained in standalone repositories:
| Project | Description |
|---|---|
| SKaiNET-transformers | Pre-built transformer architectures and layers |
| SKaiNET-examples | Sample projects and integration demos |
| Goal | Start here |
|---|---|
| Examples and sample projects | SKaiNET-examples |
| Interactive notebooks | SKaiNET-notebook |
| Eager backends & kernels (what runs where) | Backends & kernels map |
| Design proposals and long-lived API decisions | SKEEP proposals |
| Memory & storage architecture (storage, views, scopes, planning) | The memory model · Packed weight layout |
First time here? Three links are all you need:
skill:android, skill:numerics (no Kotlin), skill:docs, or by size: size:xs.[Lane N · skill] title prefix means.Small fixes can go straight through the normal contribution flow described in CONTRIBUTING.md and GITFLOW.adoc.
Non-trivial work goes through one of two processes:
docs/modules/skeep/pages/ with three-digit numbering. See the
SKEEP index.SKaiNET ships an official Phoronix-Test-Suite-compatible benchmark
program for the compute engine. See the
methodology and replay docs,
the release manifest, and the
CI workflow. Smoke runs fire
on every PR via ubuntu-latest; full publishable runs fire on a
self-hosted Linux x86 runner on release.
Quick local replay:
./gradlew :skainet-backends:benchmarks:jvm-cpu-publish:shadowJar
./scripts/run_engine_smoke.shSKaiNET is built around one path: a model is defined once in the Kotlin DSL, then either compiled or executed eagerly — without rewriting it.
nn { } / dag { }).ComputeGraph.ComputeGraph through one of several
sibling code-generation backends, each emitting code for a different target
from the same graph:
HloGenerator) → IREE-compilable, for native / edge /
accelerator targets and the wider MLIR ecosystem.StableHLO/MLIR is therefore one code-generation backend among siblings — the IREE/native path next to the C99/Arduino and Minerva MCU paths — not a separate pipeline.
flowchart LR
DSL["Model — Kotlin DSL"] --> Graph["Tape / DAG (ComputeGraph)"]
Graph --> Eager["Eager backend (JVM, …)"]
Graph -->|code generation| HLO["StableHLO / MLIR"]
Graph -->|code generation| C99["Arduino / C99"]
Graph -->|code generation| Minerva["Minerva"]
HLO --> Native["IREE → native / edge / accelerator"]
C99 --> MCU["Microcontroller"]
Minerva --> SecMCU["Secure-MCU bundle"]The same DSL model feeds every path: eager execution for development and JVM deployment, and the code-generation backends — StableHLO/MLIR (→ IREE), Arduino/C99, and Minerva — as sibling alternatives for native, edge, and secure-MCU targets.
SKaiNET now includes a Minerva export backend for secure MCU deployment. It is a sibling to StableHLO and Arduino/C99 export: it starts from a supported ComputeGraph, lowers static MLPs to a Minerva compiler input, invokes libminerva when configured, and packages generated weights, host fixtures, firmware skeletons, and a fingerprinted manifest.json.
Start here:
Runnable examples:
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaSecureMcuExamples
./gradlew :skainet-compile:skainet-compile-minerva:runMinervaSecureMcuExamples \
-Pminerva.example=sensor-classifiersafe-lowbit, balanced, experimental-max. See TurboQuantUsage for integration guide.nn { input(); dense(); relu(); dense() }
dag { } for ResNet-style skip connections and multi-scale detector headsfile://, https://, hf+https://, and hf://...
.jsonl, .ndjson)val raw = JvmDataSourceResolver().rawDataset {
from("hf://datasets/org/repo@main/train.jsonl")
format(DataFormat.JSON_LINES)
cachePolicy(CachePolicy.Use)
}
val withoutLabel = dataPipeline<RawDataset>()
.stage(
dataTransformer(
name = "drop-label",
outputSchema = { schema -> DataSchema(schema.columns - "label") }
) { dataset ->
val columns = dataset.schema.columns - "label"
dataset.copy(
schema = DataSchema(columns),
rows = dataset.rows.map { row ->
RawDataRow(row.values.filterKeys { key -> key in columns })
}
)
}
)
.execute(raw)HloGenerator
An arm64 release. On macOS the JVM's dense FP32 products — A · B on heap or segment-backed operands and x · Wᵀ
on a resident dense weight — now go to Accelerate's SGEMM by default, which runs on the matrix units of Apple
silicon and threads itself; JvmBlas had never reached a BLAS before (the framework lookup and the heap downcall
both failed silently), and -Dskainet.cpu.blas.enabled=false restores the bundled kernels. Elsewhere the default
stays off and skainet.cpu.blas.library names an OpenBLAS or reference BLAS to use. The native dense FP32 kernels
get register tiles on AArch64 (Apple silicon, Android arm64, Linux arm64): an 8 × 8 tile of lane-indexed FMAs over a
packed panel of B for A · B and a four-by-three tile for x · Wᵀ, bit-identical across slices, threads and whole
calls, exercised on Apple silicon by the macOS CI leg. Both are unmeasured on arm64 in this release; the pull
requests (#1449, #1450) say how to run the bench.
A load-time and kernel release. StreamingGGUFReader decodes the GGUF metadata from 64 KB blocks instead of one
source read per value, and TextFrontEnds.fromGguf builds a SentencePiece tokenizer in one pass over the vocabulary
instead of three to four copies of it; fields, the public API and the token ids stay the same. On a Gemma-3
tokenizer GGUF a file-source parse drops from 1.0 s to 21–45 ms on the JVM and from 23.3 s to 1.2 s on a 32-bit ARM
Android device, where read + build on the first load in a process goes from 8.4–11.2 s to 6.0–6.4 s. The native
dense FP32 A · B kernel gets an AVX2/FMA register-tiled lane on x86-64 (63 × 1024 × 1024: 21 → 281 GFLOP/s), and
no longer overwrites the parts of a sub-block caller's output buffer outside the block.
A performance release for the JVM native lane. The dense FP32 x · Wᵀ kernel — what every resident dense
weight resolves to once skainet-backend-native-cpu is on the classpath — now splits its work across the
context Schedule (SKEEP-005) instead of a fixed four-thread C pool, and on x86-64 hosts with AVX2 and FMA
runs a runtime-selected eight-lane register-tiled lane; threaded, sliced and single calls stay bit-identical.
A single 63 × 1024 × 1024 call goes from 29.6 to 131.7 GFLOP/s on a six-core laptop, and a ModernBERT-large
encoder request in the LayaMoE example from 13.0 s to 6.4 s with unchanged answers. The text front-end
indexes added tokens by first character and length, so a Gemma chat turn encodes in 36 µs instead of 2.0 ms.
CoroutineSchedule.forRange never hands a body an empty range any more.
A fix release on top of 0.62.0: the native FFM bindings of the Q8_0, Q4_0, Q5_0 and Q5_1 kernels
copied a zero-filled staging buffer back from index 0, so a product served row by row — any
quantize-at-load encoder on the JVM with skainet-backend-native-cpu on the classpath — kept only
its last row. Single-row decode steps were never affected. A regression test now covers every packed
format for one, seven and fifty rows. Also: the YOLOv8 model code moves out of core into its cartridge
blueprint (skainet-model-yolo is gone; Letterbox, BoundingBox and nonMaxSuppression stay in
skainet-data-media), the StableHLO softmax axis and logSoftmax lowering are fixed, and the docs
gain Flexibility at every compile stage and the SKEEP-008 draft on precision and encoding conversion.
JVM ↔ Kotlin/Wasm parity: the browser tier runs the same kernels as the JVM, keeps its activations in the sidecar, and reads models the way the JVM does — with every remaining difference documented.
Storage.OffHeap in a browser) and come back to the Kotlin heap only when
something outside needs them.x · Wᵀ kernel
(no transposed weight copy), fused softmax, layer and RMS normalisation, and SDPA with
key lengths, windows and grouped-query heads. One C source per kernel serves every native build.Blob sources address Long positions (shards over 2 GB), copy in bulk, and
serve blocking reads inside a Web Worker; sharded SafeTensors load from Blobs;
PlannerProfile.BROWSER; MemoryProbe reports the JavaScript heap, linear memory and the
sidecar's resident bytes; skainet-data-source resolves HTTP and Hugging Face URIs over fetch
on Kotlin/JS and Kotlin/Wasm.engine-* scenarios of the JVM publish harness run with identical
shapes in wasm-bench, and the kernel support matrix names what each tier serves and why the
rest is N/A. The operator coverage matrix is generated from backend data, with StableHLO, backward
and NN-layer columns and a CI leg that rejects unmarked stubs.split fast
path and bulk copies from mapped tensors.See CHANGELOG.md for full release notes, including every prior release.
We love contributions! Whether it's a new operator, documentation, or a bug fix:
Browse the full codebase documentation on DeepWiki.
CoroutineSchedule fix, the added-token index, and
the releasex · Wᵀ kernels, resident
activations with the elementwise, fused and convolution kernels on both tiers, the browser IO
parity, skainet-data-source on JS and wasm, the operator coverage matrix, the BitNet decode
allocation fixes, and the releaseClassificationSupport helpers extracted
from Accuracy, preparing the precision, recall and F1 metrics (#1222)skainet-quantize, the skainet-backend-wasm-simd sidecar kernel pack, the
scheduled SKEEP-006 removal, and the releasescaledDotProductAttention across the CPU kernel, recorder, executor
and StableHLO lowering, the n-ary composite seam with the skainet.sdpa composite, the
SKEEP-006 deprecation step, and the releaseerf
across the CPU kernels, graph executor and backward rules, the lowering-metadata path with
composite emission and the legalization pass, and the releasescaledDotProductAttention and its StableHLO lowering, structural schedule defaults, and
schedule-aware graph execution contexts (SKEEP-005 phase 2)BufferHandle.Floats path, and the sharded SafeTensors loaderViewKernelPack SPI, dense FP32 for mapped/off-heap
storage, the decode-shaped FP32 kernel work, Android-native targets across the downstream
chain, and the ternary packs joining the self-healing SPISEQUENTIAL I2_S, the AOT GGUF converter and its IREE-facing
counterpart in SKaiNET-IREE-tools, and the scoped dense-FP32 activation matmul-chooser fixtranspose() block-grid correctness fix, all three kernel tiers (#968, #969)DEQUANTIZE_TO_FP32 over-allocation fix (#782), native Q5_0/Q5_1 packed matmul kernels (#708), Apple arm64 runtime FEAT_DotProd dispatch (#958), Apple iOS/macOS Kotlin/Native kernel targets (#959)createRandomAccessSource streaming loads (#922), cinterop klib archive embedding (#942), Q4_0 NEON kernel (#939), GGUF loader fail-fast (#919), tensor-storage correctness fixes (#927, #928, #929, #930, #931), AAR release publishing (#947)Lstm layer (#824), Dropout masking (#867), LR schedules (#866), optional/open Linear (#870, #875), SDPA scale fix (#880), autograd fixes (#877), argMax DAG spec (#878), tokenizer + gather fixes (#879), Android native IO targets (#836, #842, #845)If you use SKaiNET in your research, please cite it. Citation metadata lives in
CITATION.cff (GitHub's Cite this repository button exports BibTeX and APA
from it). Ready-to-paste BibTeX:
@misc{skainet,
author = {Harakal, Michal and {SKaiNET-developers contributors}},
title = {{SKaiNET}: A {Kotlin} Multiplatform {AI} Framework},
year = {2026},
note = {Version 0.62.4. MIT License},
howpublished = {\url{https://github.com/SKaiNET-developers/SKaiNET}}
}Please include the version you used (each release is tagged).
MIT — see LICENCE.