A Rust application template with two modes: CLI and Tauri GUI. Both share a common library (src/lib.rs) for logging and configuration. Fork and keep the mode you need.
This file also provides guidance to Claude Code when working with code in this repository.
- Rust 1.85+ (edition 2024)
- Node.js LTS and npm (for Tauri GUI frontend)
- Linux (Ubuntu/Debian):
sudo apt install libwebkit2gtk-4.1-dev build-essential libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev - macOS: Xcode Command Line Tools (
xcode-select --install) - Windows: Microsoft Edge WebView2 (pre-installed on Windows 10/11)
cargo runRuns a producer-consumer demo with signal handling. Reads config from configs/main.toml. Logs to stderr (console) and log/ (rotating files).
make tauri-dev # Development (with hot reload)
make tauri-build # Production buildOpens a GUI window with the same producer-consumer demo. In debug builds the DevTools button and backend log forwarding to the browser console are available.
- Delete
src/bin/,frontend/andtauri.conf.json - In
Cargo.toml: remove the[features]section and[[bin]]section and optional dependencies (tauri,serde_json,tauri-build) - In
build.rs: remove the#[cfg(feature = "tauri")]block - In
.cargo-husky/hooks/pre-commit: remove the frontend check steps - Update CI to remove the tauri variant
- Move
src/bin/tauri/main.rslogic intosrc/main.rs - Delete
src/bin/,src/threads/andsrc/constant.rs - In
Cargo.toml: remove[features]and[[bin]]sections. Changetauri,serde_jsonandtauri-buildfrom optional to required - Update CI to remove the default variant
cargo build # Debug build
cargo build --release # Release build
cargo run # Run CLI
cargo fmt --all -- --check # Check formatting
cargo clippy --all-targets # Lint CLI
cargo test # Run all tests
cargo test <test_name> # Run a single test
# Tauri GUI
cargo clippy --all-targets --features tauri # Lint with Tauri
cargo test --features tauri # Test with Tauri
make tauri-dev # Dev mode (hot reload)
make tauri-build # Production build
# Frontend
npm run --prefix frontend format:check # Prettier
npm run --prefix frontend lint # ESLint + @html-eslint
npm run --prefix frontend lint:css # Stylelint
# Cross-compilation (requires `cross` tool)
make cross # Default: arm-unknown-linux-gnueabi
make cross TARGET=aarch64-unknown-linux-gnu # Specify target
make setup # Show setup instructions for cross env.cargo/config.toml sets rustflags = ["-Dwarnings"] — all warnings are treated as errors everywhere (local dev, CI, pre-commit hook).
This is a Rust application template built on Tokio async runtime with structured logging via tracing. The tauri Cargo feature gates all GUI dependencies. Without it only the CLI binary is built.
- Initialize logger with default TRACE level (console + file)
- Load config from
configs/main.toml - Reconfigure logger levels from loaded config
- Enter Tokio multi-threaded runtime → spawn threads → wait for completion
- Map
ResulttoExitCode(success → 0, error → non-zero viaErrorCode::as_u8())
- Initialize logger with default TRACE level (console + file + event layer in debug)
- Load config from
configs/main.tomland reconfigure logger - Take the event log receiver from the logger
- Build Tauri app: register IPC commands and set up the main window
- In
.setup(): set dynamic window title and spawn a log-forwarding task with a oneshot handshake (waits for frontendlog-readysignal before emitting) - Map
ResulttoExitCode
configs— LoadsMainConfigfrom TOML viaconfig+serde. Config path is relative to the working directory.logger— Dual-output logger (stderr console with ANSI colors + daily rotating file inlog/). Both output levels are independently reloadable at runtime viareconfig(). TheWorkerGuardmust be held alive inmain(). In debug builds with thetaurifeature anEventLayersendsLogRecordstructs viatokio::sync::mpscfor WebView forwarding.error—ErrorCodeenum (errors only, noSuccessvariant).as_u8()maps each variant to a non-zero exit code.main()returnsExitCodeby mappingOk(()) → SUCCESS,Err(e) → e.as_u8(). Thread functions returnResult<(), ThreadErrorCode>.threads— Thread management withJoinSet. Three demo threads: producer (sends i32 via MPSC), consumer (receives from MPSC), signal_handler (OS signals). All threads listen on a broadcast channel forThreadCommand::Stop.constant— Shared constants (e.g., broadcast channel capacity).bin/tauri/commands— Tauri IPC commands (start,stop,open_devtools). Producer and consumer run as Tokio tasks controlled viabroadcast::channelfor stop signaling.
- Command channel:
broadcast::channel<ThreadCommand>— all threads subscribe; used to sendStop - Data channel:
mpsc::unbounded_channel<i32>— producer→consumer - Each thread uses
tokio::select!to concurrently await data and stop commands - If any thread returns an
Err(ThreadErrorCode), remaining threads are stopped
- Frontend calls
invoke("start")/invoke("stop")via@tauri-apps/api/core - Backend emits
produceandconsumeevents viaAppHandle::emit() - Frontend listens with
listen()from@tauri-apps/api/event - Debug-only log forwarding: backend
EventLayer→mpsc→emit("log")→ frontendconsole.*
- Intentional duplication in thread modules: Each thread submodule (producer, consumer, signal_handler) has its own
cmd_handlerfunction. These are intentionally kept separate — do NOT extract them into a shared helper. This is a template project; users will fork and customize each thread independently.
Uses cfg_if! in signal_handler.rs: Unix signals (SIGTERM/SIGINT/SIGHUP) vs Windows control events (CTRL+C/CTRL+BREAK/CTRL+CLOSE).
cargo-husky with user-hooks feature reads custom hooks from .cargo-husky/hooks/ in the repo and installs them into .git/hooks/ on first cargo test. The pre-commit hook runs fmt check, clippy, tests and frontend format/lint checks.
Cross.tomldefines custom Docker images per target (seecross/docker/)- Default cross target:
arm-unknown-linux-gnueabi(Raspberry Pi Zero W) - CI runs
aarch64-unknown-linux-gnucross-compilation for the default variant