Available as a desktop GUI for end-users, and as a headless Rust crate with language bindings for embeddable API use.
Pumas Library is an easy to use AI model library that downloads, organizes, and serves AI model weights and metadata to other apps. Instead of having models duplicated or scattered across applications, Pumas Library provides a standardized central source that is automatically maintained. When integrated into other software via the Rust crate, it eliminates the need for a slew of file, network, and remote API boilerplate and smart logic.
- Single portable model library with rich metadata and full-text search (SQLite FTS5)
- HuggingFace integration — search, download with progress tracking, metadata lookup, cached search (24hr TTL)
- Model import with automatic type detection and dual-hash verification (SHA256 + BLAKE3)
- Model mapping — symlink/hardlink models into app directories with health tracking
- Instance convergence — multiple processes share a single primary via local TCP IPC
- Cross-process library discovery via global SQLite registry
- Resilient networking — per-domain circuit breaker, exponential backoff, rate limit handling
- Library merging with hash-based deduplication
Supported Model Types: LLM, Diffusion, Embedding, Audio, Vision Supported Subtypes: Checkpoints, LoRAs, VAE, ControlNet, Embeddings, Upscale, CLIP, T5 Compatible Engines: Ollama, llama.cpp, Candle, Transformers, Diffusers, ONNX Runtime, TensorRT
- Link your apps to your library, no manual setup required
- System and per-app resource monitoring
- Install and run different app versions (ComfyUI, Ollama, OpenWebUI, InvokeAI, KritaDiffusion)
- Smart system shortcuts that don't require the launcher to work
- Plugin system for JSON-based app definitions
The Rust crate (pumas-library) operates in one of two transparent modes:
- Primary — owns the full state and runs a local IPC server. Holds all subsystems: model library, network manager, process manager, HuggingFace client, model importer, model mapper, IPC server, and registry.
- Client — discovers a running primary via the global registry and proxies calls over TCP IPC. The public API is identical in both modes.
Key internals:
- Registry: SQLite database at
~/.config/pumas/registry.dbfor cross-process library and instance discovery - IPC Protocol: JSON-RPC 2.0 over length-prefixed TCP frames on localhost
- Search Index: SQLite FTS5 for model metadata full-text search
- Best-effort design: registry and IPC failures never block API initialization
- Feature flags:
full(default),hf-client,process-manager,gpu-monitor,uniffi
- Frontend: React 19 + Vite (rendered in Electron's Chromium)
- Desktop Shell: Electron 38+ (with native Wayland support on Linux)
- Backend: Rust
pumas-rpcbinary running as a sidecar (Axum HTTP server, JSON-RPC) - IPC: JSON-RPC communication between Electron and the Rust backend
Add the dependency:
[dependencies]
pumas-library = { path = "rust/crates/pumas-core" }
# Or with specific features only
pumas-library = { path = "rust/crates/pumas-core", features = ["hf-client"] }Basic usage:
use pumas_library::PumasApi;
#[tokio::main]
async fn main() -> pumas_library::Result<()> {
// Standard initialization
let api = PumasApi::new("/path/to/pumas").await?;
// Or use the builder for more control
let api = PumasApi::builder("./my-models")
.auto_create_dirs(true)
.with_hf_client(false)
.build()
.await?;
// Or discover an existing instance from the global registry
let api = PumasApi::discover().await?;
// List models in the library
let models = api.list_models().await?;
println!("Found {} models", models.len());
// Search for models
let search = api.search_models("llama", 10, 0).await?;
println!("Search found {} results", search.total_count);
Ok(())
}| Platform | Status | Notes |
|---|---|---|
| Linux (x64) | Full support | Debian/Ubuntu recommended, AppImage and .deb packages |
| Windows (x64) | Full support | NSIS installer and portable versions |
| macOS | Theoretically Works | Architecture ready, builds available via CI. Not tested. |
- Operating System: Linux (Debian/Ubuntu-based distros recommended)
- Rust: 1.75+
- Node.js: 22+ LTS
- Operating System: Windows 11 (x64)
- Rust: 1.75+ (install via rustup)
- Node.js: 22+ LTS (install via nodejs.org)
- Build Tools: Visual Studio Build Tools with C++ workload
Run the automated installation script:
./install.shThe installer will:
- Check and install system dependencies (with your permission)
- Build the Rust backend
- Install and build the frontend
- Install and build Electron
- Create the launcher script
-
Install system dependencies (Debian/Ubuntu):
sudo apt update sudo apt install nodejs npm cargo
-
Build Rust backend:
cd rust cargo build --release cd ..
-
Install and build frontend:
cd frontend npm install npm run build cd ..
-
Install Electron dependencies:
cd electron npm install npm run build cd ..
-
Make launcher executable (should already be executable):
chmod +x launcher
For system-wide access:
ln -s $(pwd)/launcher ~/.local/bin/pumas-libraryThen run from anywhere:
pumas-library-
Install Rust via rustup:
- Download and run
rustup-init.exe - Follow the prompts to install
- Download and run
-
Install Node.js from nodejs.org:
- Download the LTS version (22+)
- Run the installer
-
Install Visual Studio Build Tools (if not already installed):
- Download from Visual Studio Downloads
- Select "Desktop development with C++" workload
Open PowerShell and run:
-
Build Rust backend:
cd rust cargo build --release cd .. -
Install and build frontend:
cd frontend npm install npm run build cd ..
-
Install and build Electron:
cd electron npm install npm run build cd ..
-
Run the application:
cd electron npm start
To create a distributable Windows installer:
cd electron
npm run package:winThis creates:
- NSIS installer (
.exe) inelectron/release/ - Portable version (
.exe) inelectron/release/
Run the launcher with different modes:
| Command | Description |
|---|---|
./launcher |
Launch the application |
./launcher dev |
Launch with developer tools |
./launcher build |
Build all components (Rust, frontend, Electron) |
./launcher build-rust |
Build Rust backend only |
./launcher build-electron |
Build Electron TypeScript only |
./launcher package |
Package Electron app for distribution |
./launcher electron-install |
Install Electron dependencies |
./launcher generate-bindings --python |
Generate Python bindings |
./launcher generate-bindings --csharp |
Generate C# bindings |
./launcher generate-bindings --elixir |
Build Elixir Rustler NIF |
./launcher generate-bindings --all |
Generate all language bindings |
./launcher help |
Display usage information |
On Windows, use npm scripts directly:
| Command | Description |
|---|---|
npm start (in electron/) |
Launch the application |
npm run dev (in electron/) |
Launch with developer tools |
npm run package:win (in electron/) |
Package for Windows distribution |
# Build Rust backend
cd rust
cargo build --release
# Build frontend
cd ../frontend
npm ci
npm run build
# Build and run Electron
cd ../electron
npm ci
npm run build
npm start| Platform | Command | Output |
|---|---|---|
| Linux | npm run package:linux |
AppImage, .deb |
| Windows | npm run package:win |
NSIS installer, portable |
| macOS | npm run package:mac |
DMG |
Pumas-Library/
├── rust/ # Rust workspace
│ └── crates/
│ ├── pumas-core/ # Core headless library (model library, IPC, registry, networking)
│ ├── pumas-app-manager/ # App version and extension management (ComfyUI, Ollama)
│ ├── pumas-rpc/ # Axum JSON-RPC server (Electron backend)
│ ├── pumas-uniffi/ # Python, C#, Kotlin, Swift, Ruby bindings (UniFFI)
│ └── pumas-rustler/ # Elixir/Erlang NIFs (Rustler)
├── frontend/ # React 19 + Vite frontend
├── electron/ # Electron 38+ shell
├── bindings/ # Generated language bindings (not committed)
└── .github/workflows/ # CI/CD
All platform-specific code is centralized in rust/crates/pumas-core/src/platform/:
paths.rs- Platform-specific directoriespermissions.rs- File permission handlingprocess.rs- Process management
Process management, version installation, and model mapping are supported for:
ComfyUI, Ollama, OpenWebUI, InvokeAI, and KritaDiffusion.
Additional apps can be defined via the JSON plugin system without code changes.
Pumas Library's core Rust crate can be used from other languages via cross-language bindings. Two binding systems are available:
- UniFFI (Python, C#, Kotlin, Swift, Ruby) — Mozilla's cross-language bindings generator
- Rustler (Elixir/Erlang) — Native Implemented Functions for the BEAM VM
Use the launcher to generate bindings:
# Generate Python bindings
./launcher generate-bindings --python
# Generate C# bindings
./launcher generate-bindings --csharp
# Build Elixir Rustler NIF
./launcher generate-bindings --elixir
# Generate all
./launcher generate-bindings --allOr use the standalone script directly:
./scripts/generate-bindings.sh python
./scripts/generate-bindings.sh csharp
./scripts/generate-bindings.sh elixir
./scripts/generate-bindings.sh allGenerated bindings are written to bindings/ and are not committed to the repository.
| Language | Tool | Install Command |
|---|---|---|
| Python | uniffi-bindgen | cargo install uniffi-bindgen-cli |
| C# | uniffi-bindgen-cs | cargo install uniffi-bindgen-cs --git https://github.com/NordSecurity/uniffi-bindgen-cs --tag v0.9.0+v0.28.3 |
| Elixir | Rustler | Add {:rustler, "~> 0.34"} to mix.exs |
After generating, the bindings are in bindings/python/. The native shared library is copied alongside the Python module.
import sys
sys.path.insert(0, "bindings/python")
from pumas_uniffi import version
print(version())After generating, add the .cs files from bindings/csharp/ to your .NET project and ensure the native library (libpumas_uniffi.so / .dll / .dylib) is in the output directory.
using PumasUniFFI;
Console.WriteLine(PumasUniffiMethods.Version());Elixir bindings use Rustler, which compiles the NIF as part of the Mix build rather than generating source files. Add Rustler as a dependency and create a NIF module:
# mix.exs
defp deps do
[{:rustler, "~> 0.34"}]
end# lib/pumas/native.ex
defmodule Pumas.Native do
use Rustler, otp_app: :pumas, crate: "pumas_rustler"
def version(), do: :erlang.nif_error(:nif_not_loaded)
def parse_model_type(_type), do: :erlang.nif_error(:nif_not_loaded)
def validate_json(_json), do: :erlang.nif_error(:nif_not_loaded)
endThe uniffi feature on pumas-core is optional and only adds derive annotations. It has zero overhead when disabled:
# Use pumas-core without FFI (default)
pumas-library = { path = "rust/crates/pumas-core" }
# Use pumas-core with UniFFI derives enabled
pumas-library = { path = "rust/crates/pumas-core", features = ["uniffi"] }