· 7 min read

Download kjarni.dll: Kjarni on Windows for C#, Unity and C++

Which Kjarni file you need on Windows and where it comes from: Kjarni.dll and kjarni_ffi.dll for C# and Unity, kjarni_ffi.lib and kjarni.h for C++, and kjarni.exe for the command line. One runtime dependency, the Visual C++ Redistributable.

Kjarni on Windows is a handful of files, and which ones you need depends on what is calling them. People search for kjarni.dll and kjarni_ffi.lib, and both exist, but they are not the same kind of file and they do not come from the same place.

FileWhat it isYou need it forWhere it comes from
kjarni_ffi.dllThe engine: a native library with a C ABIEverythingNuGet package and the release zip
Kjarni.dllThe C# binding, a managed assemblyC#, .NET and UnityNuGet package
kjarni_ffi.libImport library for kjarni_ffi.dllLinking from C or C++ with MSVCRelease zip
kjarni.h, kjarni.hppC header and C++23 wrapperC and C++Release zip
kjarni.exeThe command line toolShell and scriptsRelease zip

kjarni_ffi.dll is the one that does the work. Kjarni.dll is a managed wrapper of under 50 KB that calls into it, so in C# you always ship both, and in C++ you link against the .lib and ship the native DLL next to your executable.

The one thing Windows needs installed

The native library imports VCRUNTIME140.dll, which is the Microsoft Visual C++ Redistributable. Most Windows machines already have it, because most software ships it, but a clean install or a minimal VM may not. Install the x64 build from Microsoft:

https://aka.ms/vs/17/release/vc_redist.x64.exe

Everything else kjarni_ffi.dll imports is part of Windows itself: kernel32, advapi32, user32, bcrypt, ws2_32, the Universal C Runtime and opengl32. There is no CUDA runtime, no ONNX Runtime, no Python and no DirectML package to install. You can check that yourself with dumpbin /dependents kjarni_ffi.dll from a Visual Studio developer prompt.

If the redistributable is missing, the failure you see is not obviously about it. C# reports DllNotFoundException: Unable to load DLL 'kjarni_ffi' even when the file is sitting right there, because Windows reports a missing dependency of a DLL as the DLL itself not loading.

C# and .NET

On .NET 8 there is nothing to download by hand:

dotnet add package Kjarni
using Kjarni;

using var embedder = new Embedder("minilm-l6-v2");
Console.WriteLine(embedder.Similarity("doctor", "physician")); // 0.8598
Console.WriteLine(embedder.Similarity("doctor", "banana"));    // 0.3379

The package carries kjarni_ffi.dll under runtimes/win-x64/native/, and the .NET SDK copies it into your output directory at build time. That is why you never see the native file unless you go looking for it. The rest of the C# API is covered in Semantic Search in C# and Sentiment Analysis in C#.

Kjarni.Extensions.AI, the IChatClient and IEmbeddingGenerator adapter, targets .NET 8 only. The core Kjarni package targets both .NET 8 and .NET Standard 2.1.

Unity

Unity is why the .NET Standard 2.1 build exists. It needs Unity 2021.2 or later, with Api Compatibility Level set to .NET Standard 2.1 under Project Settings, Player, Other Settings.

Unity does not read NuGet packages, which is where most of the kjarni.dll searches come from: the files have to be put into the project by hand. There are two ways to do it.

With NuGetForUnity. Install NuGetForUnity, search for Kjarni and install it. It resolves managed dependencies for you, which matters for 0.2.3: that version's .NET Standard build depends on System.Text.Json, and NuGetForUnity pulls it in along with everything it depends on. Check afterwards that kjarni_ffi.dll is under Assets and enabled for your platform, and copy it in as below if it is not.

By hand. A .nupkg file is a zip archive. Download it from the NuGet page, rename it to .zip, and copy two files out of it:

lib/netstandard2.1/Kjarni.dll           ->  Assets/Plugins/Kjarni/Kjarni.dll
runtimes/win-x64/native/kjarni_ffi.dll  ->  Assets/Plugins/Kjarni/x86_64/kjarni_ffi.dll

Select kjarni_ffi.dll in the Project window and, in the Inspector, enable it for the Editor and for Standalone Windows x86_64. For 0.2.3 you also need System.Text.Json and its dependencies in Assets/Plugins, which is the reason to prefer NuGetForUnity for that version.

Loading a model reads it from disk and, the first time, downloads it, so do not do it on the main thread. A MonoBehaviour can hand the work to a background thread and pick the result up again on the main thread:

using System.Threading.Tasks;
using Kjarni;
using UnityEngine;

public class SemanticMatch : MonoBehaviour
{
    private Embedder _embedder;

    private async void Start()
    {
        // Keep models in the game's own data folder rather than the user's cache.
        var cache = Application.persistentDataPath + "/kjarni";
        _embedder = await Task.Run(() => new Embedder("minilm-l6-v2", cacheDir: cache, quiet: true));

        var score = await Task.Run(() => _embedder.Similarity("open the door", "unlock the gate"));
        Debug.Log($"similarity: {score:F4}");
    }

    private void OnDestroy() => _embedder?.Dispose();
}

Unity's synchronisation context brings the await back to the main thread, so the Debug.Log and anything else touching the scene is safe. A handle is not safe to use from two threads at once, so give each concurrent task its own or serialise calls.

The binding is written for both Mono and IL2CPP. The one place IL2CPP is particular is native code calling back into C#: it only accepts static methods carrying [MonoPInvokeCallback]. Chat streaming is written that way. The onProgress callback on Indexer is not yet, so under IL2CPP build indexes without passing onProgress.

What Unity cannot do yet is target phones or the web. The package carries native libraries for Windows x64, Linux x64 and arm64, and macOS on Apple Silicon. There is no Android, iOS or WebGL build, so a Unity project using Kjarni is a desktop project for now.

C and C++

The release zip has everything:

mkdir kjarni-quickstart; cd kjarni-quickstart
curl.exe -LO https://github.com/olafurjohannsson/kjarni/releases/latest/download/kjarni-x86_64-windows.zip
Expand-Archive kjarni-x86_64-windows.zip -DestinationPath .
curl.exe -LO https://raw.githubusercontent.com/olafurjohannsson/kjarni/main/crates/kjarni-ffi/examples/cpp/hello_c_api.cpp

hello_c_api.cpp is written against kjarni.h, the plain C header, so it needs nothing newer than C++11 and builds with any current MSVC. From a Visual Studio developer prompt:

cl /EHsc /std:c++17 /I. hello_c_api.cpp kjarni_ffi.lib
.\hello_c_api.exe
related:   0.5510
unrelated: -0.0630

kjarni_ffi.lib is the import library: it resolves the kjarni_* symbols at link time and records that they live in kjarni_ffi.dll. At run time Windows looks for the DLL next to the executable first, so to ship the program you copy kjarni_ffi.dll alongside it. There is no installer and nothing to register.

kjarni.hpp, the C++ wrapper, returns std::expected and so needs C++23. In MSVC that means Visual Studio 2022 and /std:c++latest. The C header has no such requirement, and Local Semantic Search in C++ shows the same program both ways.

With CMake, link the import library the same way:

target_include_directories(app PRIVATE ${KJARNI_DIR})
target_link_libraries(app PRIVATE ${KJARNI_DIR}/kjarni_ffi.lib)
add_custom_command(TARGET app POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${KJARNI_DIR}/kjarni_ffi.dll $<TARGET_FILE_DIR:app>)

The post-build step copies the DLL next to the binary, so the program runs from the build directory without touching PATH.

The command line

kjarni.exe in the same zip is the whole CLI, and it needs no other file from the archive:

.\kjarni.exe similarity -q "doctor" "physician"
0.859813

Everything in ML from the Command Line works the same way on Windows.

Where the models go

Models download on first use and are cached in %LOCALAPPDATA%\kjarni, which is C:\Users\<you>\AppData\Local\kjarni. Set KJARNI_CACHE_DIR to move it for every program, or pass cacheDir in C# and cache_dir in the C config to move it for one. Once a model is cached, nothing touches the network again.

FAQ

Is there a kjarni.dll?

Yes, but it is the C# binding, not the engine. Kjarni.dll is a managed .NET assembly inside the NuGet package, and it calls kjarni_ffi.dll, which is the native engine. C# and Unity need both. C and C++ need only kjarni_ffi.dll, plus kjarni_ffi.lib to link against it.

Why do I get DllNotFoundException for kjarni_ffi when the file is there?

Usually because the Visual C++ Redistributable is not installed. kjarni_ffi.dll imports VCRUNTIME140.dll, and Windows reports a missing dependency as the DLL itself failing to load. Install the x64 redistributable from https://aka.ms/vs/17/release/vc_redist.x64.exe. If that is not it, check that kjarni_ffi.dll is next to your executable, or in Unity, that it is enabled for your platform in the Inspector.

Does Kjarni work on .NET Framework 4.8?

No. .NET Framework supports .NET Standard up to 2.0, and the Kjarni package targets .NET 8 and .NET Standard 2.1. On .NET Framework, the C API in kjarni_ffi.dll can be called through P/Invoke directly, but there is no ready-made binding for it.

Which Unity versions are supported?

Unity 2021.2 and later, with Api Compatibility Level set to .NET Standard 2.1. The binding is written for both the Mono and IL2CPP scripting backends; under IL2CPP, leave out the Indexer progress callback for now. Desktop targets only: Windows x64, Linux and macOS on Apple Silicon.

Does it need a GPU or CUDA on Windows?

No. Everything runs on CPU by default. GPU support goes through WebGPU, which on Windows uses DirectX 12 or Vulkan, so AMD, Intel and NVIDIA cards all work and there is no CUDA toolkit to install.

Is there an ARM64 Windows build?

Not yet. The Windows build is x86_64 only.

Getting it

Releases (zip):    https://github.com/olafurjohannsson/kjarni/releases
NuGet (C#, Unity): https://www.nuget.org/packages/Kjarni
GitHub:            https://github.com/olafurjohannsson/kjarni

Kjarni runs the same engine on every platform: