Version v1.12
You're viewing docs for v1.12. If you are cloning the repository, make sure to check out this release: git checkout v1.12
Quickstart¶
Install Cactus and run your first on-device AI completion.
Installation¶
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup
cactus build --flutter
Build output:
| File | Platform |
|---|---|
libcactus.so |
Android (arm64-v8a) |
cactus-ios.xcframework |
iOS |
cactus-macos.xcframework |
macOS |
Platform Integration¶
Android¶
- Copy
libcactus.sotoandroid/app/src/main/jniLibs/arm64-v8a/ - Copy
cactus.dartto yourlib/folder
iOS¶
- Copy
cactus-ios.xcframeworkto yourios/folder - Open
ios/Runner.xcworkspacein Xcode - Drag the xcframework into the project
- In Runner target > General > "Frameworks, Libraries, and Embedded Content", set to "Embed & Sign"
- Copy
cactus.dartto yourlib/folder
macOS¶
- Copy
cactus-macos.xcframeworkto yourmacos/folder - Open
macos/Runner.xcworkspacein Xcode - Drag the xcframework into the project
- In Runner target > General > "Frameworks, Libraries, and Embedded Content", set to "Embed & Sign"
- Copy
cactus.dartto yourlib/folder
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup
cactus build --android
Build output: android/libcactus.so (and android/libcactus.a)
Platform Integration¶
Android-only¶
- Copy
libcactus.sotoapp/src/main/jniLibs/arm64-v8a/ - Copy
Cactus.kttoapp/src/main/java/com/cactus/
Kotlin Multiplatform¶
Source files:
| File | Copy to |
|---|---|
Cactus.common.kt |
shared/src/commonMain/kotlin/com/cactus/ |
Cactus.android.kt |
shared/src/androidMain/kotlin/com/cactus/ |
Cactus.ios.kt |
shared/src/iosMain/kotlin/com/cactus/ |
cactus.def |
shared/src/nativeInterop/cinterop/ |
Binary files:
| Platform | Location |
|---|---|
| Android | libcactus.so → app/src/main/jniLibs/arm64-v8a/ |
| iOS | libcactus-device.a → link via cinterop |
build.gradle.kts:
kotlin {
androidTarget()
listOf(iosArm64(), iosSimulatorArm64()).forEach {
it.compilations.getByName("main") {
cinterops {
create("cactus") {
defFile("src/nativeInterop/cinterop/cactus.def")
includeDirs("/path/to/cactus/ffi")
}
}
}
it.binaries.framework {
linkerOpts("-L/path/to/apple", "-lcactus-device")
}
}
sourceSets {
commonMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}
}
}
git clone https://github.com/cactus-compute/cactus && cd cactus && source ./setup
cactus build --apple
Build outputs (in apple/):
| File | Description |
|---|---|
cactus-ios.xcframework/ |
iOS framework (device + simulator) |
cactus-macos.xcframework/ |
macOS framework |
libcactus-device.a |
Static library for iOS device |
libcactus-simulator.a |
Static library for iOS simulator |
Platform Integration¶
iOS/macOS: XCFramework (Recommended)¶
- Drag
cactus-ios.xcframework(orcactus-macos.xcframework) into your Xcode project - Ensure "Embed & Sign" is selected in "Frameworks, Libraries, and Embedded Content"
- Copy
Cactus.swiftinto your project
iOS/macOS: Static Library¶
- Add
libcactus-device.a(orlibcactus-simulator.a) to "Link Binary With Libraries" - Create a folder with
cactus_ffi.handmodule.modulemap, add to Build Settings: - "Header Search Paths" → path to folder
- "Import Paths" (Swift) → path to folder
- Copy
Cactus.swiftinto your project
Add to your Cargo.toml:
Build requirements: CMake, C++20 compiler, and platform tools (Xcode CLI on macOS, build-essential + libcurl4-openssl-dev + libclang-dev on Linux).
Homebrew (macOS):
From Source (macOS):
From Source (Linux):
Include the Cactus header in your project:
See the Cactus repository for CMake build instructions.
Your First Completion¶
import { useCactusLM } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM();
useEffect(() => {
if (!cactusLM.isDownloaded) {
cactusLM.download();
}
}, []);
const handleGenerate = () => {
cactusLM.complete({
messages: [{ role: 'user', content: 'What is the capital of France?' }],
});
};
if (cactusLM.isDownloading) {
return <Text>Downloading: {Math.round(cactusLM.downloadProgress * 100)}%</Text>;
}
return (
<>
<Button onPress={handleGenerate} title="Generate" />
<Text>{cactusLM.completion}</Text>
</>
);
};
Basic Completion¶
from src.downloads import ensure_model
from src.cactus import cactus_init, cactus_complete, cactus_destroy
import json
# Downloads weights from HuggingFace if not already present
weights = ensure_model("LiquidAI/LFM2-VL-450M")
model = cactus_init(str(weights), None, False)
messages = json.dumps([{"role": "user", "content": "What is 2+2?"}])
result = json.loads(cactus_complete(model, messages, None, None, None))
print(result["response"])
cactus_destroy(model)
use cactus_sys::*;
use std::ffi::CString;
unsafe {
let model_path = CString::new("path/to/weight/folder").unwrap();
let model = cactus_init(model_path.as_ptr(), std::ptr::null(), false);
let messages = CString::new(
r#"[{"role": "user", "content": "What is the capital of France?"}]"#
).unwrap();
let mut response = vec![0u8; 4096];
cactus_complete(
model, messages.as_ptr(),
response.as_mut_ptr() as *mut i8, 4096,
std::ptr::null(), std::ptr::null(),
None, std::ptr::null_mut(),
);
println!("{}", String::from_utf8_lossy(&response));
cactus_destroy(model);
}
#include <cactus.h>
cactus_model_t model = cactus_init(
"path/to/weight/folder",
"path/to/rag/documents",
false
);
const char* messages = R"([
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
])";
char response[4096];
int result = cactus_complete(
model, messages, response, sizeof(response),
nullptr, nullptr, nullptr, nullptr
);
Supported Models¶
- LLMs: Gemma-3 (270M, FunctionGemma-270M, 1B), LiquidAI LFM2 (350M, 2.6B) / LFM2.5 (1.2B-Instruct, 1.2B-Thinking) / LFM2-8B-A1B, Qwen3 (0.6B, 1.7B) (completion, tools, embeddings)
- Vision: LFM2-VL, LFM2.5-VL (with Apple NPU), Qwen3.5 (0.8B, 2B)
- Transcription: Whisper (Tiny/Base/Small/Medium with Apple NPU), Parakeet (CTC-0.6B/CTC-1.1B/TDT-0.6B-v3 with Apple NPU), Moonshine-Base
- VAD: Silero VAD for voice activity detection
- Embeddings: Nomic-Embed, Qwen3-Embedding
See the full list on HuggingFace.
Next Steps¶
- Engine API -- Full inference API reference
- Graph API -- Zero-copy computation graph for custom models
- Fine-tuning & Deployment -- Convert and deploy custom fine-tunes
- Choose Your SDK -- Help picking the right SDK for your project