How llmfit's Tauri Desktop Application Integrates with the Core Rust Library
The llmfit desktop application acts as a thin Tauri wrapper that exposes llmfit-core functionality through serializable commands, allowing the JavaScript UI to invoke Rust methods for hardware detection, model fitting, and provider operations.
The AlexsJones/llmfit repository implements a machine learning model fitting tool with a native desktop interface. The llmfit Tauri desktop application integrates with the core Rust library through a command-based architecture that keeps hardware detection, model catalog management, and inference provider logic decoupled from the presentation layer.
Command Registration in the Tauri Layer
The integration begins in llmfit-desktop/src/main.rs, where the Tauri builder registers Rust functions as invokable commands. These commands serve as the exclusive bridge between the web-based UI and the system-level capabilities of the core library.
Exposing Core APIs as Tauri Commands
The desktop application defines several #[tauri::command] functions that act as thin shims over llmfit-core APIs:
get_system_specs– WrapsSystemSpecs::detect()fromllmfit-core/src/hardware.rsto gather RAM, CPU, and GPU informationget_model_fits– InvokesModelDatabase::new()fromllmfit-core/src/models.rsandModelFit::analyze()fromllmfit-core/src/fit.rsto evaluate models against detected hardwarestart_pullandpoll_pull– Interface with theOllamaProviderfor model download managementis_ollama_available– Checks provider connectivity
Each command returns results serialized through #[derive(Serialize)] structs, enabling automatic marshalling to the JavaScript side without custom deserialization logic.
#[tauri::command]
fn get_system_specs() -> Result<SystemInfo, String> {
let specs = SystemSpecs::detect();
let gpus = specs.gpus.iter().map(|g| GpuInfoJs {
name: g.name.clone(),
vram_gb: g.vram_gb,
backend: format!("{:?}", g.backend),
count: g.count,
unified_memory: g.unified_memory,
}).collect();
Ok(SystemInfo {
total_ram_gb: specs.total_ram_gb,
available_ram_gb: specs.available_ram_gb,
cpu_name: specs.cpu_name.clone(),
cpu_cores: specs.total_cpu_cores,
gpus,
unified_memory: specs.unified_memory,
})
}
Managing Shared State Across the Rust-JavaScript Boundary
The integration uses Tauri's state management to maintain persistent connections across command invocations. An AppState struct holds a singleton OllamaProvider (from llmfit-core/src/providers.rs) and a mutex-protected optional pull handle.
This state is injected into commands via State<'_, AppState>, allowing the UI to start long-running model downloads and monitor progress without recreating provider objects or losing connection context between calls.
The JavaScript Bridge and UI Integration
The front-end code in llmfit-desktop/ui/app.js consumes the registered commands through Tauri's invoke API. The JavaScript layer remains purely presentational, delegating all computational work to the Rust core.
import { invoke } from '@tauri-apps/api/tauri';
async function loadSystemInfo() {
const info = await invoke('get_system_specs');
document.getElementById('cpu').textContent = `${info.cpu_name} (${info.cpu_cores} cores)`;
document.getElementById('ram').textContent = `${info.total_ram_gb.toFixed(1)} GB total`;
// Render GPU list …
}
loadSystemInfo();
When fetching model fits, the JavaScript invokes the Rust command and renders the returned JSON array:
async function loadModelFits() {
const fits = await invoke('get_model_fits');
const tbody = document.querySelector('#model-table tbody');
tbody.innerHTML = '';
fits.forEach(fit => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${fit.name}</td>
<td>${fit.params_b.toFixed(2)} B</td>
<td>${fit.quant}</td>
<td>${fit.fit_level}</td>
<td>${fit.run_mode}</td>
<td>${fit.score.toFixed(2)}</td>
`;
tbody.appendChild(row);
});
}
loadModelFits();
The corresponding Rust command handles the complex analysis logic:
#[tauri::command]
fn get_model_fits() -> Result<Vec<ModelFitInfo>, String> {
let specs = SystemSpecs::detect();
let db = ModelDatabase::new();
let fits = db.get_all_models()
.iter()
.map(|m| ModelFit::analyze(m, &specs))
.collect::<Vec<_>>();
let ranked = llmfit_core::fit::rank_models_by_fit(fits);
Ok(ranked.into_iter().map(|f| ModelFitInfo {
name: f.model.name.clone(),
params_b: f.model.parameters_raw.unwrap_or(0) as f64 / 1e9,
quant: f.best_quant.clone(),
fit_level: match f.fit_level {
FitLevel::Perfect => "Perfect",
FitLevel::Good => "Good",
FitLevel::Marginal => "Marginal",
FitLevel::TooTight => "Too Tight",
}.to_string(),
run_mode: match f.run_mode {
RunMode::Gpu => "GPU",
RunMode::CpuOffload => "CPU Offload",
RunMode::CpuOnly => "CPU Only",
RunMode::MoeOffload => "MoE Offload",
RunMode::TensorParallel => "Tensor Parallel",
}.to_string(),
score: f.score,
memory_required_gb: f.memory_required_gb,
memory_available_gb: f.memory_available_gb,
utilization_pct: f.utilization_pct,
estimated_tps: f.estimated_tps,
use_case: format!("{:?}", f.use_case),
runtime: match f.runtime {
InferenceRuntime::LlamaCpp => "llama.cpp",
InferenceRuntime::Mlx => "MLX",
InferenceRuntime::Vllm => "vLLM",
InferenceRuntime::Unsupported => "unsupported",
}.to_string(),
installed: f.installed,
notes: f.notes.clone(),
release_date: f.model.release_date.clone(),
}).collect())
}
Architectural Separation of Concerns
The integration maintains strict boundaries between the Tauri-specific desktop code and the reusable core library. All domain logic—including hardware detection in llmfit-core/src/hardware.rs, model catalog management in llmfit-core/src/models.rs, and fit analysis in llmfit-core/src/fit.rs—resides in llmfit-core.
The desktop crate handles only three responsibilities: registering Tauri commands, managing stateful provider connections, and packaging static assets (index.html, styles.css). This separation ensures the core library remains usable by the CLI (llmfit-tui) and Python wrapper without pulling in Tauri dependencies or web runtime overhead.
Summary
- Command-based integration –
llmfit-desktop/src/main.rsregisters thin command wrappers that delegate tollmfit-coreAPIs likeSystemSpecs::detect()andModelFit::analyze() - Automatic serialization – Rust structs derive
Serializeto enable seamless data transfer across the JavaScript boundary without custom marshalling code - Stateful persistence – The
AppStatestruct maintainsOllamaProviderinstances across invocations using Tauri's dependency injection system - Clean architecture – All heavy logic stays in
llmfit-core, making the library reusable by CLI and Python consumers while the desktop layer focuses strictly on UI concerns
Frequently Asked Questions
How does the Tauri front-end call functions in the Rust core library?
The front-end uses Tauri's invoke API to call commands registered in llmfit-desktop/src/main.rs. Each command is a Rust function marked with #[tauri::command] that internally calls methods from llmfit-core, such as SystemSpecs::detect() or ModelDatabase::new(), and returns serializable structs that Tauri automatically converts to JavaScript objects.
Where is the application state stored in the llmfit desktop app?
Application state is stored in an AppState struct managed by Tauri's state system. This struct, defined in the desktop crate, holds a singleton OllamaProvider from llmfit-core/src/providers.rs and a mutex-protected pull handle. Tauri injects this state into command handlers via State<'_, AppState>, allowing persistent connections across multiple UI interactions.
Can the core library be used without the Tauri desktop interface?
Yes. The llmfit-core crate contains no Tauri dependencies and exposes a standard Rust API used by both the desktop application and the llmfit-tui CLI tool. Hardware detection, model fitting, and provider interactions all live in llmfit-core, making the library consumable by any Rust binary, Python wrapper, or alternative interface without the overhead of the webview runtime.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →