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
- Torch inference server — Python backend for running models with GPU slot management
Supported Model Types: LLM, Reranker, 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 (currently ComfyUI, Ollama, Torch)
- 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(())
}Use full reconciliation when the on-disk library and SQLite index drift (for example after interrupted downloads):
cd rust
cargo run --package pumas-library --example repair_library_integrity -- /path/to/shared-resources/modelsThis maintenance flow performs duplicate cleanup, reclassification, and index rebuild in one pass. Migration reports now distinguish:
- metadata-backed index rows
- partial-download index rows
- stale index rows
Partial downloads (.part files) remain resumable and are tracked as partial rows until completed.
Migration execution can now safely relocate partial-download directories to canonical paths by pausing tracked downloads, moving the directory, updating persistence/index paths, and resuming when appropriate.
HuggingFace file downloads automatically retry transient network failures with resume support.
- Default max attempts: unlimited (
0) - Default max retry elapsed budget per file:
43200seconds (12 hours) - Override with environment variables:
PUMAS_HF_DOWNLOAD_MAX_RETRIES(0= unlimited)PUMAS_HF_DOWNLOAD_MAX_RETRY_ELAPSED_SECS(0= disable elapsed cap)
| Platform | Status | Notes |
|---|---|---|
| Linux (x64) | Full support | Debian/Ubuntu recommended, AppImage and .deb packages |
| Windows (x64) | Full support | NSIS installer and portable versions |
| macOS (ARM) | Best-effort | ARM builds via CI, not regularly 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
Use the root launcher script:
chmod +x launcher.sh
./launcher.sh --install
./launcher.sh --build-release
./launcher.sh --runThe launcher-managed flow:
- Verifies local tool/runtime dependencies (
cargo,node,npm, workspacenode_modules) - Builds Rust backend + frontend + Electron artifacts
- Starts Electron with the Rust sidecar backend
-
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 ci npm run build cd ..
-
Install Electron dependencies:
cd electron npm ci npm run build cd ..
-
Make launcher executable (should already be executable):
chmod +x launcher.sh
For system-wide access:
ln -s $(pwd)/launcher.sh ~/.local/bin/pumas-libraryThen run from anywhere:
pumas-library --help-
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 ci npm run build cd ..
-
Install and build Electron:
cd electron npm ci 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.sh --install |
Install launcher dependencies (cargo/node/npm + workspace deps) |
./launcher.sh --build |
Build debug backend + frontend + electron |
./launcher.sh --build-release |
Build release backend + frontend + electron |
./launcher.sh --run |
Run Electron in development mode |
./launcher.sh --run -- --devtools |
Run development mode with app flags |
./launcher.sh --run-release |
Run packaged artifacts directly |
./launcher.sh --help |
Display usage information |
Note: --run currently expects the release Rust backend binary (rust/target/release/pumas-rpc), so run ./launcher.sh --build-release first.
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 |
Before cutting a release, run:
cd rust
cargo test --workspace --exclude pumas_rustler
cargo clippy --workspace --exclude pumas_rustler -- -D warnings
cargo build --workspace --exclude pumas_rustler
cd ..
npm run -w frontend test:run
npm run -w frontend check:types
npm run -w frontend build
npm run -w electron validate
npm run -w electron buildFor pumas_rustler, run tests separately on a machine with Erlang/OTP installed.
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, Torch)
│ ├── 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 and artifacts
└── .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, and Torch.
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 standalone script:
./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 can be regenerated with scripts/generate-bindings.sh.
| 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"] }