Skip to main content

quip-node-manager

Desktop GUI and CLI app for running and monitoring Quip Network nodes, built with Tauri v2 and Rust

Jump to install

Source facts

Repository
reason-machines/trending-skills
Last source activity
April 30, 2026 at 17:57
Detected SKILL.md language
English
Stars
80
Forks
15

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
quip-node-manager
description
Desktop GUI and CLI app for running and monitoring Quip Network nodes, built with Tauri v2 and Rust
triggers
["manage quip network node","run quip node with GUI","quip node manager setup","configure quip node docker","quip node manager tauri","monitor quip network node","quip node GPU configuration","install quip node manager"]
# Quip Node Manager > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. Quip Node Manager is a cross-platform desktop application (macOS, Linux, Windows) built with Tauri v2 + Rust that lets you run, configure, and monitor [Quip Network](https://gitlab.com/quip.network) nodes. It supports two execution modes — Docker (default on Windows/Linux) and Native binary (default on macOS) — with a GUI front-end and an optional terminal UI (`--cli` flag). --- ## Installation ### Quick Install (macOS / Linux) ```sh curl -fsSL https://gitlab.com/quip.network/quip-node-manager/-/raw/main/scripts/install.sh | sh ``` ### Quick Install (Windows PowerShell) ```powershell irm https://gitlab.com/quip.network/quip-node-manager/-/raw/main/scripts/install.ps1 | iex ``` ### Manual Installation | Platform | Format | Steps | |---|---|---| | macOS | `.dmg` | Open DMG, drag to `/Applications`, then run `xattr -dr com.apple.quarantine "/Applications/Quip Node Manager.app"` | | Linux | `.AppImage` | `chmod +x quip-node-manager-linux-x86_64.AppImage && ./quip-node-manager-linux-x86_64.AppImage` | | Linux | `.deb` | `sudo dpkg -i quip-node-manager-linux-x86_64.deb` | | Windows | `.exe` | Run installer; click **More info → Run anyway** if SmartScreen warns | --- ## Development Setup ### Prerequisites - [Rust](https://rustup.rs/) (stable toolchain) - [Bun](https://bun.sh/) or Node.js - Platform Tauri v2 deps: https://v2.tauri.app/start/prerequisites/ ### Clone and Run ```sh git clone https://gitlab.com/quip.network/quip-node-manager.git cd quip-node-manager bun install # Install JS dependencies bun run dev # Launch hot-reloading dev build (opens desktop window) bun run build # Production build for current platform ``` ### Rust-only checks (no frontend needed) ```sh cd src-tauri cargo check # Fast type-check cargo clippy # Lint with suggestions cargo test # Run unit tests ``` --- ## Architecture ``` quip-node-manager/ ├── src/ # Frontend: vanilla HTML/CSS/JS │ ├── index.html │ ├── main.js # Tauri IPC calls (window.__TAURI__) │ └── styles.css ├── src-tauri/ │ ├── src/ │ │ ├── main.rs # App entry point │ │ ├── commands.rs # Tauri IPC command handlers │ │ ├── node.rs # Node process management │ │ ├── config.rs # TOML config generation │ │ ├── docker.rs # Docker mode logic │ │ ├── updater.rs # Background update monitor │ │ └── gpu.rs # CUDA/Metal device detection │ ├── Cargo.toml │ └── tauri.conf.json ├── scripts/ │ ├── install.sh │ └── install.ps1 └── AGENTS.md # Detailed architecture docs ``` **Data directory:** `~/quip-data/` — stores settings, TOML config, secrets, downloaded binaries, and trust database. --- ## Key Concepts ### Run Modes | Mode | Default On | How it works | |---|---|---| | Docker | Windows, Linux | Pulls/manages a container image via Docker daemon | | Native | macOS | Downloads a standalone quip-protocol binary | ### Pre-flight Checklist Before starting the node, the manager verifies: 1. Docker available (Docker mode) or binary downloaded (Native mode) 2. Node secret exists in `~/quip-data/` 3. Public IP reachable 4. Port forwarding configured 5. Firewall rules allow node traffic --- ## Tauri IPC Commands (Frontend → Backend) The frontend calls Rust commands via `window.__TAURI__.core.invoke`. Key commands: ```js const { invoke } = window.__TAURI__.core; // Get current node status const status = await invoke('get_node_status'); // Returns: { running: bool, mode: 'docker'|'native', uptime_secs: number } // Start the node await invoke('start_node'); // Stop the node await invoke('stop_node'); // Get configuration const config = await invoke('get_config'); // Save configuration await invoke('save_config', { config: { /* see config schema below */ } }); // Run pre-flight checks const checks = await invoke('run_preflight'); // Returns: { docker: bool, secret: bool, public_ip: string, port_open: bool, firewall: bool } // Get GPU devices const gpus = await invoke('get_gpu_devices'); // Returns: [{ id: string, name: string, type: 'cuda'|'metal', enabled: bool, utilization: number }] // Check for updates const update = await invoke('check_for_updates'); // Returns: { app: string|null, node: string|null, docker_image: string|null } ``` --- ## Configuration Schema (TOML) The app generates a TOML config written to `~/quip-data/config.toml` matching the quip-protocol format: ```toml [node] mode = "native" # or "docker" secret_path = "/Users/you/quip-data/secret" data_dir = "/Users/you/quip-data" [network] public_ip = "1.2.3.4" port = 9000 tls_cert = "/path/to/cert.pem" # optional tls_key = "/path/to/key.pem" # optional [gpu] enabled = true devices = ["0", "1"] utilization = 80 # percent yield_mode = false [dwave] enabled = false token = "" # set via env: DWAVE_TOKEN daily_budget_seconds = 60 [updates] auto_restart_on_image_update = true check_interval_secs = 1800 ``` --- ## Rust Backend Patterns ### Adding a Tauri Command ```rust // src-tauri/src/commands.rs use tauri::State; use crate::node::NodeManager; #[tauri::command] pub async fn get_node_status( manager: State<'_, NodeManager>, ) -> Result<NodeStatus, String> { manager.status().await.map_err(|e| e.to_string()) } #[tauri::command] pub async fn start_node( manager: State<'_, NodeManager>, ) -> Result<(), String> { manager.start().await.map_err(|e| e.to_string()) } ``` Register in `main.rs`: ```rust // src-tauri/src/main.rs fn main() { tauri::Builder::default() .manage(NodeManager::new()) .invoke_handler(tauri::generate_handler![ commands::get_node_status, commands::start_node, commands::stop_node, commands::get_config, commands::save_config, commands::run_preflight, commands::get_gpu_devices, commands::check_for_updates, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` ### Emitting Live Log Events to Frontend ```rust // src-tauri/src/node.rs use tauri::{AppHandle, Emitter}; pub async fn stream_logs(app: AppHandle, mut reader: impl AsyncBufRead + Unpin) { let mut line = String::new(); loop { line.clear(); match reader.read_line(&mut line).await { Ok(0) => break, // EOF Ok(_) => { app.emit("node-log-line", line.trim().to_string()) .unwrap_or_default(); } Err(e) => { app.emit("node-log-error", e.to_string()).unwrap_or_default(); break; } } } } ``` Listen in the frontend: ```js const { listen } = window.__TAURI__.event; const unlisten = await listen('node-log-line', (event) => { appendToLogDrawer(event.payload); }); // Cleanup when drawer closes: unlisten(); ``` ### Docker Mode: Managing Containers ```rust // src-tauri/src/docker.rs use std::process::Command; pub fn pull_image(image: &str) -> Result<(), String> { let status = Command::new("docker") .args(["pull", image]) .status() .map_err(|e| format!("docker not found: {e}"))?; if status.success() { Ok(()) } else { Err("docker pull failed".into()) } } pub fn run_node_container(image: &str, data_dir: &str, port: u16) -> Result<String, String> { let output = Command::new("docker") .args([ "run", "-d", "--name", "quip-node", "-p", &format!("{port}:{port}"), "-v", &format!("{data_dir}:/quip-data"), image, ]) .output() .map_err(|e| e.to_string())?; if output.status.success() { Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) } else { Err(String::from_utf8_lossy(&output.stderr).to_string()) } } ``` ### GPU Detection ```rust // src-tauri/src/gpu.rs #[derive(serde::Serialize)] pub struct GpuDevice { pub id: String, pub name: String, pub device_type: String, // "cuda" or "metal" pub enabled: bool, pub utilization: u8, } pub fn detect_gpus() -> Vec<GpuDevice> { let mut devices = Vec::new(); // CUDA detection via nvidia-smi if let Ok(output) = std::process::Command::new("nvidia-smi") .args(["--query-gpu=index,name", "--format=csv,noheader"]) .output() { for line in String::from_utf8_lossy(&output.stdout).lines() { let parts: Vec<&str> = line.splitn(2, ',').collect(); if parts.len() == 2 { devices.push(GpuDevice { id: parts[0].trim().to_string(), name: parts[1].trim().to_string(), device_type: "cuda".into(), enabled: true, utilization: 80, }); } } } // macOS Metal: presence of Metal framework implies GPU #[cfg(target_os = "macos")] devices.push(GpuDevice { id: "0".into(), name: "Apple Metal GPU".into(), device_type: "metal".into(), enabled: true, utilization: 80, }); devices } ``` --- ## CLI Mode ```sh quip-node-manager --cli ``` Launches a terminal UI (TUI) instead of the desktop window — useful for headless servers. --- ## TLS Certificate Setup The GUI includes a built-in walkthrough. For scripted setup: **Let's Encrypt (certbot):** ```sh sudo certbot certonly --standalone -d your.domain.com # Certs written to /etc/letsencrypt/live/your.domain.com/ ``` Then set in config: ```toml [network] tls_cert = "/etc/letsencrypt/live/your.domain.com/fullchain.pem" tls_key = "/etc/letsencrypt/live/your.domain.com/privkey.pem" ``` **Self-signed (openssl):** ```sh openssl req -x509 -newkey rsa:4096 -keyout ~/quip-data/key.pem \
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub