feature/diffusion-vision
Onde — Ruby Gem
Ruby bindings for the Onde on-device inference engine, powered by Rust via magnus.
Manage HuggingFace model caches, inspect supported models, and access inference configuration — all from Ruby, with zero C dependencies.
Requirements
- Ruby >= 3.0
- Rust >= 1.87 (installed via rustup)
- macOS, Linux, or Windows
Installation
Add to your Gemfile:
gem 'onde'
Then:
bundle install
Or install directly:
gem install onde
The gem compiles a native Rust extension on install. Rust must be available on your $PATH.
Development Setup
cd lib/crates/onde/gem
# Install dependencies and compile the native extension
bin/setup
# Or step by step:
bundle install
bundle exec rake compile
# Open an interactive console with the gem loaded
bin/console
Building & Testing
# Compile the Rust extension
bundle exec rake compile
# Build the gem package
bundle exec rake build
# Run the default task (compile)
bundle exec rake
API Reference
Onde.list_local_models → Hash
Scans the local HuggingFace hub cache (~/.cache/huggingface/hub/) and returns all downloaded models that the inference engine supports.
response = Onde.list_local_models
response["cache_path"] # => "/Users/you/.cache/huggingface/hub"
response["total_size_bytes"] # => 24768454656
response["total_size_display"] # => "23.07 GB"
response["models"].each do |model|
puts "#{model["model_id"]} — #{model["size_display"]} (#{model["revisions"].length} revisions)"
puts " Path: #{model["path"]}"
end
Onde.list_supported_models → Hash
Returns all models the engine supports with download status flags.
Onde.list_supported_models["models"].each do |m|
status = if m["is_downloaded"]
"✓ downloaded"
elsif m["is_incomplete"]
"⏳ incomplete (#{m["local_size_display"]} / #{m["expected_size_display"]})"
else
"✗ not downloaded"
end
puts "[#{status}] #{m["name"]} (#{m["org"]})"
puts " #{m["description"]}"
end
Each model Hash contains:
| Key | Type | Description |
|---|---|---|
model_id |
String | Full HuggingFace ID, e.g. "bartowski/Qwen2.5-1.5B-Instruct-GGUF" |
name |
String | Human-friendly display name |
org |
String | Organisation or publisher |
description |
String | Short description of the model |
is_downloaded |
Boolean | Fully downloaded locally |
is_incomplete |
Boolean | Partial download exists on disk |
local_size_bytes |
Integer | Bytes currently on disk |
local_size_display |
String | Human-readable local size |
expected_size_bytes |
Integer | Approximate total size when fully downloaded |
expected_size_display |
String | Human-readable expected size |
Onde.delete_model(model_id) → nil
Delete a locally cached model. Raises RuntimeError if the model is not found or deletion fails.
Onde.delete_model("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
Onde.model_info(model_id) → Hash or nil
Look up rich metadata for a single supported model. Returns nil if the model ID is not in the supported list.
info = Onde.model_info("bartowski/Qwen2.5-1.5B-Instruct-GGUF")
# => {
# "id" => "bartowski/Qwen2.5-1.5B-Instruct-GGUF",
# "name" => "Qwen 2.5 1.5B (GGUF)",
# "org" => "Qwen / Alibaba",
# "description" => "Lightest pre-quantized chat model — ideal for iOS & Android (~941 MB)...",
# "expected_size_bytes" => 986048768
# }
Onde.supported_model_ids → Array
Returns the list of all supported model IDs as strings.
Onde.supported_model_ids
# => ["black-forest-labs/FLUX.1-schnell", "google/gemma-3n-E2B-it", ...]
Onde.cache_path → String or nil
Returns the resolved HuggingFace cache directory path, or nil if it cannot be determined.
Onde.cache_path
# => "/Users/you/.cache/huggingface/hub"
Sampling Config Helpers
Return sampling parameter Hashes suitable for passing to inference engines:
Onde.default_sampling_config
# => { "temperature" => 0.7, "top_p" => 0.95, "max_tokens" => 512, ... }
Onde.deterministic_sampling_config
# => { "temperature" => 0.0, "max_tokens" => 512, ... }
Onde.mobile_sampling_config
# => { "temperature" => 0.7, "top_p" => 0.95, "max_tokens" => 128, ... }
Constants
Onde::VERSION # => "0.1.0" (gem version)
Onde::NATIVE_VERSION # => "0.1.0" (Rust crate version)
Onde::SUPPORTED_MODELS # => ["black-forest-labs/FLUX.1-schnell", ...] (frozen Array)
Onde::SUPPORTED_MODEL_INFO # => [{ "id" => ..., "name" => ..., ... }, ...] (frozen Array of frozen Hashes)
Example: Rails Admin Dashboard
# app/controllers/admin/models_controller.rb
class Admin::ModelsController < ApplicationController
def index
@supported = Onde.list_supported_models["models"]
@local = Onde.list_local_models
end
def destroy
Onde.delete_model(params[:model_id])
redirect_to admin_models_path, notice: "Model deleted."
rescue RuntimeError => e
redirect_to admin_models_path, alert: e.message
end
end
Architecture
gem/
├── onde.gemspec # Gem specification
├── Gemfile # Dev dependencies (rake-compiler, rb_sys)
├── Rakefile # Build tasks via RbSys::ExtensionTask
├── rust-toolchain.toml # Pinned Rust toolchain version
├── lib/
│ ├── onde.rb # Entry point — loads native ext + defines module
│ └── onde/
│ └── version.rb # Onde::VERSION
├── ext/
│ └── onde/
│ ├── Cargo.toml # Rust crate — depends on `onde` + `magnus`
│ ├── extconf.rb # rb_sys build hook
│ └── src/
│ └── lib.rs # Magnus bindings — the bridge between Rust and Ruby
└── bin/
├── console # IRB with gem loaded
└── setup # One-step dev setup
The native extension compiles the onde Rust crate (which wraps mistral.rs for LLM inference and HuggingFace Hub for model management) into a shared library (.bundle on macOS, .so on Linux) that Ruby loads at require time.
All Rust structs are converted to Ruby Hashes via serde_json serialization, keeping the binding layer thin and the Ruby API simple — no custom Ruby classes needed.
License
MIT OR Apache-2.0 — same as the Onde crate.