How Clash Nyanpasu Integrates with Different Clash Cores: Clash Premium, Mihomo, and Clash Rust
Clash Nyanpasu uses a Rust-based Core Manager that maps user-selected core identifiers to specific binaries, enabling seamless switching between Clash Premium, Mihomo, and Clash Rust through Tauri IPC commands.
Clash Nyanpasu is a cross-platform GUI application that serves as a graphical front-end for multiple Clash proxy implementations. Understanding how Clash Nyanpasu integrates with different Clash cores reveals a sophisticated three-layer architecture that separates configuration state, process management, and frontend interactions while supporting Clash Premium, Mihomo (and its Alpha variant), and Clash Rust (plus its Alpha variant).
Core Architecture Overview
The integration follows a strict separation of concerns across three layers:
- Configuration & State (Rust) – A single
ClashCoreenum records which core the user wants to run - Core Manager (Rust) – Resolves the binary path, launches the core process, and handles hot-swapping
- Frontend UI & IPC (TypeScript) – Lets the user pick a core, fetches version info, and triggers changes via Tauri IPC
Configuration and State Management in Rust
The ClashCore Enum
In backend/tauri/src/config/nyanpasu/mod.rs, the supported cores are defined as a Rust enum:
pub enum ClashCore {
ClashPremium,
ClashRs,
Mihomo,
MihomoAlpha,
ClashRsAlpha,
}
This enum maps to the following binary names:
- Clash Premium:
clash - Mihomo:
mihomo - Mihomo Alpha:
mihomo-alpha - Clash Rust:
clash-rs - Clash Rust Alpha:
clash-rs-alpha
Persistence and Defaults
The ClashCore enum integrates with the global configuration through Config::verge().data().clash_core. When no core is selected, the system defaults to ClashCore::ClashPremium. The implementation provides From<ClashCore> for String and From<&ClashCore> for nyanpasu_utils::core::CoreType conversions to map the enum to binary filenames and generic core types used by the manager utilities.
Core Manager Implementation
Binary Resolution and Process Management
The backend/tauri/src/core/clash/core.rs file contains the CoreManager implementation that handles the lifecycle of Clash processes:
- Determine active core: Reads the chosen core from configuration with fallback to
ClashPremium - Map to generic type: Converts to
nyanpasu_utils::core::CoreTypefor abstraction - Find binary: Calls
find_binary_path(&clash_core)to locate the executable in$APPDIR/cores - Start/restart: Uses
CoreInstance::check_config_()to validate configuration before spawning the process
Hot-Swapping Cores at Runtime
The manager supports changing cores without restarting the application:
pub async fn change_core(&self, clash_core: Option<ClashCore>) -> Result<()> {
// Persists the new core in config and restarts the core process
}
This method updates the configuration storage and triggers a restart of the core process with the new binary, enabling seamless switching between Clash Premium, Mihomo, and Clash Rust implementations.
Version Resolution
In backend/tauri/src/utils/resolve.rs, the resolve_core_version function executes <binary> -V to obtain version strings for any supported core, allowing the UI to display version information regardless of which implementation is active.
Frontend Integration and IPC
State Management with Jotai
The frontend uses Jotai for reactive state management. In frontend/nyanpasu/src/store/clash.ts:
export const coreTypeAtom = atom<NonNullable<VergeConfig['clash_core']>>('mihomo')
This atom holds the core identifier ('clash' | 'mihomo' | 'clash-rs' | …) and synchronizes the UI with the backend state.
TypeScript Service Layer
The frontend/interface/src/service/core.ts file provides a typed interface to the Tauri IPC layer:
export const VALID_CORE = [
{ name: 'Clash Premium', core: 'clash' },
{ name: 'Mihomo', core: 'mihomo' },
{ name: 'Mihomo Alpha', core: 'mihomo-alpha' },
{ name: 'Clash Rust', core: 'clash-rs' },
{ name: 'Clash Rust Alpha', core: 'clash-rs-alpha' },
]
export async function getCoreVersion(core: ClashCore): Promise<string> {
return await commands.getCoreVersion(core)
}
Available IPC Commands
The backend exposes specific commands in backend/tauri/src/ipc.rs that bridge frontend actions to the Core Manager:
change_clash_core: Switches to another core (hot-swap)update_core: Downloads the latest binary for the selected coreget_core_version: Retrieves the version string viabinary -Vfetch_latest_core_versions: Queries GitHub releases for available updatesget_core_dir/open_core_dir: Manages the core binary storage location
Practical Implementation Examples
Switching Between Cores
To switch from Mihomo to Clash Rust in the frontend:
import { changeClashCore } from '@/service/core';
import { coreTypeAtom } from '@/store/clash';
import { useAtom } from 'jotai';
const [core, setCore] = useAtom(coreTypeAtom);
async function switchToRust() {
await changeClashCore('clash-rs'); // invokes Tauri IPC
setCore('clash-rs'); // update UI state
}
Under the hood, changeClashCore calls Tauri's invoke('change_clash_core', { clashCore }), which executes CoreManager::change_core in Rust, updates the configuration, and restarts the core process with the clash-rs binary.
Retrieving Core Versions
import { getCoreVersion } from '@/service/core';
import { coreTypeAtom } from '@/store/clash';
import { useAtom } from 'jotai';
const [core] = useAtom(coreTypeAtom);
async function showVersion() {
const version = await getCoreVersion(core);
console.log(`Running ${core} version ${version}`);
}
This invokes resolve_core_version in backend/tauri/src/utils/resolve.rs, which executes <binary> -V and returns the version string.
Updating Core Binaries
import { updateCore } from '@/service/core';
import { coreTypeAtom } from '@/store/clash';
import { useAtom } from 'jotai';
const [core] = useAtom(coreTypeAtom);
async function update() {
const updatedBytes = await updateCore(core);
console.log(`${core} updated, new size: ${updatedBytes} bytes`);
}
The IPC update_core triggers the Rust updater in backend/tauri/src/core/updater/mod.rs, which queries the GitHub releases API for the newest version, downloads the appropriate asset for the current OS/architecture, and replaces the binary in the core directory.
Summary
- Clash Nyanpasu supports five distinct core variants: Clash Premium, Mihomo, Mihomo Alpha, Clash Rust, and Clash Rust Alpha.
- The integration relies on a Rust
ClashCoreenum inbackend/tauri/src/config/nyanpasu/mod.rsto type-safely represent the selected implementation. - The Core Manager in
backend/tauri/src/core/clash/core.rshandles binary resolution, process lifecycle, and hot-swapping between cores without application restart. - Tauri IPC commands in
backend/tauri/src/ipc.rsexpose core operations to the TypeScript frontend, includingchange_clash_core,update_core, andget_core_version. - The frontend uses Jotai atoms in
frontend/nyanpasu/src/store/clash.tsfor reactive state management and provides typed service wrappers infrontend/interface/src/service/core.ts.
Frequently Asked Questions
How does Clash Nyanpasu determine which core binary to execute?
Clash Nyanpasu reads the active core from the configuration using Config::verge().latest().clash_core, which returns a ClashCore enum variant. The Core Manager in backend/tauri/src/core/clash/core.rs converts this to a CoreType and calls find_binary_path() to locate the executable in the application-specific cores directory (typically $APPDIR/cores).
Can I switch between Clash Premium and Mihomo without restarting the application?
Yes. The change_core method in backend/tauri/src/core/clash/core.rs supports hot-swapping. When you trigger a core change via the frontend (using changeClashCore in frontend/interface/src/service/core.ts), the backend persists the new selection to the configuration file, terminates the current core process, and spawns the new binary—all without requiring an application restart.
How does the frontend display version information for different cores?
The frontend calls getCoreVersion from frontend/interface/src/service/core.ts, which invokes the Tauri command get_core_version defined in backend/tauri/src/ipc.rs. The backend executes <binary> -V via the resolve_core_version function in backend/tauri/src/utils/resolve.rs and returns the version string to the UI, allowing the application to display accurate version data regardless of which core is active.
Where are the core binaries stored and how are they updated?
Core binaries reside in a dedicated directory accessed via get_core_dir and open_core_dir IPC commands. When you initiate an update through updateCore in the frontend, the backend's updater module (backend/tauri/src/core/updater/mod.rs) queries the GitHub releases API for the latest version of the selected core, downloads the appropriate asset for your operating system and architecture, and atomically replaces the existing binary in the cores directory.
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 →