Use when calling SKaiNET from a pure-Java app (Spring Boot, Android Java, Quarkus, plain main()) — adding the JVM-only Maven coordinates, calling `SKaiNET.context()` and `TensorJavaOps.*`, using `StableHloConverterFactory` / `TokenizerFactory`. Trigger tokens include `SKaiNET.context()`, `SKaiNET.tensor(`, `TensorJavaOps.`, `StableHloConverterFactory`, `TokenizerFactory.fromGguf`, `package sk.ainet.java` import in a `.java` file, "from Java", "Java consumer". Do NOT fire when designing the Java facade INSIDE SKaiNET (that's the contributor `skainet-java-interop` skill) or when the consumer is in Kotlin (that's `skainet-inference`).
How this skill is triggered — by the user, by Claude, or both
Slash command
/skainet-consumer-skills:skainet-java-consumerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Calling SKaiNET from a pure-Java app: which Maven artifacts to depend on, the entry-point classes that were designed to be Java-friendly, idiomatic Java patterns over the `sk.ainet.java` facade.
Calling SKaiNET from a pure-Java app: which Maven artifacts to depend on, the entry-point classes that were designed to be Java-friendly, idiomatic Java patterns over the sk.ainet.java facade.
.java, not .kt, and they want to use SKaiNET.SKaiNET.context(), SKaiNET.tensor(...), SKaiNET.zeros(...), TensorJavaOps.add(...), etc. from Java.StableHloConverterFactory.createBasic() / createExtended() for HLO export.TokenizerFactory.fromGguf(metadata) to build a tokenizer from a GGUF file.skainet-test-java as canonical usage examples.skainet-inference (and the rest of the consumer plugin) covers it more directly.@JvmStatic members) — the contributor skainet-java-interop skill.skainet-android-integration (its threading rules apply even from Java; the dispatcher just becomes ExecutorService).sk.ainet:skainet-bom:<VERSION> (BOM)sk.ainet.core:skainet-lang-core (DSL types + SKaiNET + TensorJavaOps)sk.ainet.core:skainet-backend-cpu (DirectCpuExecutionContext.create())skainet-io-core + skainet-io-{gguf|onnx|safetensors}skainet-compile-core + skainet-compile-hlo
The skainet-test-java consumer module's build.gradle.kts is the canonical reference for the dependency set: SKaiNET/skainet-test/skainet-test-java/build.gradle.kts:9-21.--enable-preview --add-modules jdk.incubator.vector); only enable those flags if you actually use Vector / preview APIs.SKaiNET and TensorJavaOps — never import internal sk.ainet.lang.* or sk.ainet.context.* packages from Java unless absolutely necessary. The Java entry points are the supported surface.Tensor<?, ?> (the Java view of Tensor<*, *>). Don't try to declare Tensor<DType, Float> in Java — the Kotlin * projection collapses to ? and any further generic bounds are awkward.DType.fp32(), DType.int32(), DType.int8(), etc. — never KClass. The SKaiNET factory takes a DType instance and resolves to a KClass<DType> internally.kotlin/sk/ainet/io/... is suspend, Java sees an extra Continuation parameter — that's not supportable from a normal Java caller. Use a Kotlin shim that exposes CompletableFuture<T> or a blocking helper.<dependency> blocks or Gradle if Java + Gradle is the setup).ExecutionContext: ExecutionContext ctx = SKaiNET.context();.SKaiNET.tensor(...) / SKaiNET.zeros(...) / SKaiNET.full(...).TensorJavaOps.<op>(...) — never reach into the Kotlin *.ops field directly.StableHloConverterFactory and TokenizerFactory.Maven pom.xml (JVM-only Java consumer):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>sk.ainet</groupId>
<artifactId>skainet-bom</artifactId>
<version>0.20.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>sk.ainet.core</groupId>
<artifactId>skainet-lang-core</artifactId>
</dependency>
<dependency>
<groupId>sk.ainet.core</groupId>
<artifactId>skainet-backend-cpu</artifactId>
</dependency>
<!-- optional: loaders -->
<dependency>
<groupId>sk.ainet.core</groupId>
<artifactId>skainet-io-core</artifactId>
</dependency>
<dependency>
<groupId>sk.ainet.core</groupId>
<artifactId>skainet-io-gguf</artifactId>
</dependency>
</dependencies>
Gradle (Java + Gradle, no Kotlin):
dependencies {
implementation(platform("sk.ainet:skainet-bom:0.20.0-SNAPSHOT"))
implementation("sk.ainet.core:skainet-lang-core")
implementation("sk.ainet.core:skainet-backend-cpu")
}
java {
toolchain { languageVersion = JavaLanguageVersion.of(21) }
}
Java tensor ops — minimal arithmetic:
package com.example;
import sk.ainet.context.ExecutionContext;
import sk.ainet.java.SKaiNET;
import sk.ainet.java.TensorJavaOps;
import sk.ainet.lang.tensor.Tensor;
import sk.ainet.lang.types.DType;
public class TensorAddDemo {
public static void main(String[] args) {
ExecutionContext ctx = SKaiNET.context();
Tensor<?, ?> a = SKaiNET.tensor(ctx, new int[]{2, 2}, DType.fp32(),
new float[]{1f, 2f, 3f, 4f});
Tensor<?, ?> b = SKaiNET.tensor(ctx, new int[]{2, 2}, DType.fp32(),
new float[]{10f, 20f, 30f, 40f});
Tensor<?, ?> c = TensorJavaOps.add(a, b);
float[] result = c.getData().copyToFloatArray();
for (float v : result) {
System.out.println(v);
}
}
}
// from: SKaiNET/skainet-test/skainet-test-java/src/test/java/sk/ainet/java/TensorJavaOpsTest.java:25-38
Default-argument overloads (@JvmOverloads from Kotlin gives you these for free):
// Both work — pick the shape that suits the call site
Tensor<?, ?> z3 = SKaiNET.zeros(ctx, new int[]{2, 2}, DType.fp32());
Tensor<?, ?> z2 = SKaiNET.zeros(ctx, new int[]{2, 2}); // dtype defaults to FP32
Tensor<?, ?> r1 = TensorJavaOps.softmax(input); // dim defaults to -1
Tensor<?, ?> r2 = TensorJavaOps.softmax(input, -1);
Activation chain:
Tensor<?, ?> logits = TensorJavaOps.matmul(x, w);
Tensor<?, ?> hidden = TensorJavaOps.relu(logits);
Tensor<?, ?> out = TensorJavaOps.softmax(hidden, -1);
HLO export (Java consumer of skainet-compile-hlo):
import sk.ainet.compile.hlo.StableHloConverter;
import sk.ainet.compile.hlo.StableHloConverterFactory;
StableHloConverter basic = StableHloConverterFactory.createBasic();
StableHloConverter extended = StableHloConverterFactory.createExtended();
// hand a ComputeGraph to one of these to produce StableHLO MLIR text
// from: SKaiNET/skainet-test/skainet-test-java/src/test/java/sk/ainet/java/ReleaseApiJavaTest.java
Tokenizer from GGUF metadata:
import sk.ainet.tokenizer.Tokenizer;
import sk.ainet.tokenizer.TokenizerFactory;
import sk.ainet.tokenizer.UnsupportedTokenizerException;
try {
Tokenizer tok = TokenizerFactory.fromGguf(ggufMetadataMap);
int[] ids = tok.encode("Hello SKaiNET");
} catch (UnsupportedTokenizerException e) {
// GGUF didn't carry a recognised tokenizer; fall back to a manual one
}
// from: SKaiNET/skainet-test/skainet-test-java/src/test/java/sk/ainet/java/ReleaseApiJavaTest.java
Spring Boot bean wiring (typical):
@Configuration
public class SkainetConfig {
@Bean(destroyMethod = "")
public ExecutionContext skainetExecutionContext() {
return SKaiNET.context();
}
}
@Service
public class Classifier {
private final ExecutionContext ctx;
public Classifier(ExecutionContext ctx) { this.ctx = ctx; }
public float[] classify(float[] features) {
Tensor<?, ?> x = SKaiNET.tensor(ctx, new int[]{1, features.length}, DType.fp32(), features);
Tensor<?, ?> y = TensorJavaOps.softmax(model.forward(x, ctx), -1); // model is Kotlin-built and exposed
return y.getData().copyToFloatArray();
}
}
For models, consumers typically build the Module in a small Kotlin module (the DSL is awkward from Java) and expose the Module<FP32, Float> to the Java service layer. Mixed-language consumer projects are the norm.
../skainet-consumer-setup/SKILL.md.suspend in Kotlin — needs a Kotlin shim) — ../skainet-model-loading/SKILL.md.ExecutorService instead of coroutines) — ../skainet-inference/SKILL.md.skainet-java-interop skill.// WRONG — KClass parameter from Java
SKaiNET.tensor(ctx, new int[]{2, 2}, FP32.class, data); // FP32::class.java is awkward
// RIGHT — DType instance
SKaiNET.tensor(ctx, new int[]{2, 2}, DType.fp32(), data);
// WRONG — calling Kotlin properties as fields
Tensor<?, ?> a = ...;
int[] dims = a.shape.dimensions; // Tensor.getShape() is the Java view
// RIGHT — Java-style accessors
int[] dims = a.getShape().getDimensions();
// WRONG — reaching into the Kotlin ops object
Tensor<?, ?> sum = a.getOps().add(a, b); // ops is Tensor<DType, Any?>.ops — generic chaos in Java
// RIGHT — go through the facade
Tensor<?, ?> sum = TensorJavaOps.add(a, b);
// WRONG — calling a suspend function directly
Tensor<?, ?> loaded = ggufReader.loadTensor("name"); // compiles only via Continuation; runtime mess
// RIGHT — write a Kotlin shim that exposes a CompletableFuture or blocking helper
public CompletableFuture<Tensor<?, ?>> loadTensorAsync(String name) {
return GlobalScope.future { ggufReader.loadTensor(name) }
}
// WRONG — JVM 8 toolchain
java { toolchain { languageVersion = JavaLanguageVersion.of(8) } }
// RIGHT — JVM 11+
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
references/maven-deps.md — Maven <dependency> blocks, BOM import scope, JDK toolchain notes.references/java-entry-points.md — every Java-friendly entry point currently shipped (SKaiNET, TensorJavaOps, StableHloConverterFactory, TokenizerFactory, TensorSpecs).Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub skainet-developers/skainet-coding-skills --plugin skainet-consumer-skills