Clash Verge Developer Guide

A technical overview for building and contributing to Clash Verge Rev: the Tauri 2 + Rust + React architecture, local development commands, project structure, frontend-to-Rust communication, the Mihomo external controller API, debugging data, release workflows and the checks expected before a pull request.

  • ClientTauri 2 + Rust + React
  • CoreMihomo (formerly Clash Meta)
  • LicenseGPL-3.0

Clash Verge Project Architecture

Clash Verge Rev is a Tauri 2 desktop application built around a separate proxy core. React and TypeScript implement the interface, Rust/Tauri provide desktop and operating-system integration, and Mihomo handles DNS, routing rules, proxy groups and traffic forwarding. Keeping those layers separate makes debugging much easier.

Layer Technology Responsibilities
Interface layer React + TypeScript + Vite Visual management of subscriptions, nodes, rules, connections and logs
Application layer Tauri 2 + Rust Window and tray, core process management, system proxy and TUN, config read/write, auto-update
Core layer Mihomo (Clash Meta) Protocol implementations, rule matching, DNS, traffic forwarding, plus a RESTful API for external callers

Note A UI symptom does not always mean a frontend bug. Trace the feature through the React interface, Tauri/Rust application layer and Mihomo core before deciding where the fault lives. System integration and privileged operations belong to the desktop layer; proxy behavior belongs to Mihomo.

Clash Verge Development Prerequisites

Local development requires Rust, Node.js, Corepack/pnpm and the Tauri system packages for your operating system. Platform-specific toolchains matter before you run any project scripts.

System What to install Notes
All platforms Node.js, Corepack/pnpm and a Rust toolchain Enable Corepack, then confirm node, pnpm and cargo are available
Windows MSVC Rust toolchain and GNU patch; Windows ARM also needs LLVM/clang Make sure Rust and Node.js are on PATH; Windows ARM needs clang because of native dependencies
macOS Xcode Command Line Tools xcode-select --install
Linux WebKitGTK 4.1, Ayatana AppIndicator, librsvg, patchelf and related build packages Package names differ per distribution; follow Tauri's official dependency list

Caution The current contribution guide lists Ubuntu packages such as libwebkit2gtk-4.1-dev, libayatana-appindicator3-dev, librsvg2-dev and patchelf. Other distributions use different package names, so follow the error and your platform's Tauri requirements.

Local Development and Build Commands

The current development flow installs JavaScript dependencies, downloads Mihomo and service binaries with the prebuild script, then starts the desktop shell or produces a platform build.

  1. Clone the repository

    Get the source and change into the project directory.

  2. Install Project Dependencies

    Enable Corepack and use the repository's pinned pnpm workflow instead of introducing a different package manager.

  3. Download Mihomo and Runtime Assets

    Run the prebuild script to download the Mihomo core and service/sidecar binaries required by the current platform.

  4. Start the Development Shell

    pnpm dev is the standard development command. The repository also exposes pnpm dev:diff and pnpm dev:tauri for specific development cases.

  5. Build the Application

    Use pnpm build for the standard Tauri build or pnpm build:fast for a faster testing build. Final artifact locations depend on the active target and Tauri bundle output.

shell
# 1. Clone the repository
git clone https://github.com/clash-verge-rev/clash-verge-rev.git
cd clash-verge-rev

# 2. Enable Corepack and install dependencies
corepack enable
pnpm install

# 3. Download Mihomo and service binaries
pnpm run prebuild
# Re-download and overwrite them when needed:
# pnpm run prebuild --force

# 4. Start development
pnpm dev
# Alternatives:
# pnpm dev:diff
# pnpm dev:tauri

# 5. Build the current platform
pnpm build
# Faster test build:
# pnpm build:fast

Note The dev branch currently defines prebuild, dev, dev:diff, dev:tauri, build and build:fast in package.json. Check that file again when working against a different commit or release branch.

Clash Verge Source Structure

The repository separates the React frontend from the Tauri/Rust application layer, with scripts and CI configuration around them. Use the current tree to locate real implementations before editing.

directory tree (illustrative)
clash-verge-rev/
├─ src/                    # React + TypeScript frontend
├─ src-tauri/              # Tauri 2 + Rust desktop application
│  ├─ src/                 # Rust application and system integration
│  ├─ resources/           # Runtime resources
│  ├─ sidecar/             # Mihomo and related sidecar binaries
│  ├─ Cargo.toml           # Rust dependencies
│  └─ tauri.conf.json      # Tauri app and bundle configuration
├─ scripts/                # Prebuild, release and development scripts
├─ .github/                # CI and GitHub Actions
├─ package.json            # pnpm scripts and frontend dependencies
├─ CONTRIBUTING.md         # Current development and contribution workflow
└─ UPDATELOG.md            # Project update log

Note This is an orientation map rather than a frozen contract. The current i18n workflow uses locale folders under src/locales/<lang>/ for frontend strings and separate backend locale files, so follow CONTRIBUTING_i18n.md when a change affects translated copy.

Tauri Frontend-to-Rust Communication

Clash Verge uses Tauri APIs to bridge the React frontend and Rust application layer. Frontend code can call registered Rust commands with invoke, while longer-lived state changes can be delivered through Tauri events. Real command names should always be traced from the current source.

typescript
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";

// Example only: use command and event names from the current source tree
const result = await invoke("command_name", {
  payload: { key: "value" },
});

const unlisten = await listen("event-name", (event) => {
  console.log(event.payload);
});

// Stop listening when the component or view is disposed
unlisten();
rust
// Example only: expose a Rust function as a Tauri command
#[tauri::command]
fn command_name(payload: serde_json::Value) -> Result<serde_json::Value, String> {
    Ok(payload)
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![command_name])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Caution These snippets explain the Tauri IPC model, not the current Clash Verge command registry. Trace the frontend call site to the corresponding Rust command, event and data type before implementing or documenting a feature.

Mihomo External Controller API

Mihomo can expose a RESTful control API through external-controller. Clash Verge uses core APIs to inspect runtime state, while external tools can also query configs, proxies, connections, rules, logs and traffic when the controller is enabled and correctly authenticated.

shell
# Example only: replace with the controller address used by your running profile
BASE=http://127.0.0.1:9090
AUTH="Authorization: Bearer your-secret"

# Version and current runtime config
curl -H "$AUTH" "$BASE/version"
curl -H "$AUTH" "$BASE/configs"

# Change runtime mode: rule / global / direct
curl -X PATCH -H "$AUTH" -d '{"mode":"rule"}' "$BASE/configs"

# Proxy groups and active connections
curl -H "$AUTH" "$BASE/proxies"
curl -H "$AUTH" "$BASE/connections"

# Live traffic and logs can also be consumed over WebSocket
# ws://127.0.0.1:9090/traffic?token=your-secret
# ws://127.0.0.1:9090/logs?level=info&token=your-secret
Endpoint Method Purpose
/version GET Core version; commonly used to check whether the API is reachable
/configs GET / PATCH / PUT Read the config, patch parts of it (mode, ports), or reload the whole config file
/proxies GET List all nodes and proxy groups along with the current selection
/proxies/{name} GET / PUT Inspect a single node, or switch the selected node for a proxy group
/proxies/{name}/delay GET Returns latency for a given test URL and timeout
/rules GET The rules currently in effect, useful for confirming that rules loaded as expected
/connections GET / DELETE List active connections, or close a specific one
/traffic, /logs WebSocket Live upload/download traffic and the log stream

Caution Treat the controller URL and secret as runtime configuration, not constants copied from a documentation example. An exposed controller can change proxy behavior and inspect runtime state, so bind it conservatively and protect it with authentication when appropriate.

Clash Verge Data and Debug Directories

Client settings, downloaded profiles, generated configs and logs are stored locally. These files are useful when debugging startup, migration, profile generation or service problems.

System Approximate location What's inside
Windows %APPDATA%\<app identifier>\ Client settings, profiles and generated configs, Extension Config/Script files, Mihomo and application logs
macOS ~/Library/Application Support/<app identifier>/
Linux ~/.local/share/<app identifier>/

Note Paths and application identifiers can differ by platform or build channel. Prefer the client's own app-directory and log-directory shortcuts when available, and back up important data before testing migrations or manual file edits.

Contributing to Clash Verge Rev

The current contribution workflow emphasizes a real reported problem, a narrowly scoped diff, meaningful verification and clear ownership of the change before a pull request is reviewed.

  1. Start from a Real Issue

    Non-trivial changes should map to a pre-existing issue. Keep the implementation focused on that problem instead of mixing unrelated refactors, formatting churn or dependency updates into the same pull request.

  2. Fork and create a branch

    One branch, one thing, with a name that states the intent — for example fix/tray-menu-crash.

  3. Run the Required Checks

    Run cargo clippy-all for Rust, pnpm lint for the frontend, then format with cargo fmt and pnpm format. Also reproduce the reported behavior and verify the actual fix.

  4. Use Signed, Focused Commits

    Commits must be signed. Keep messages and diffs focused enough that reviewers can connect each changed area to the issue being solved.

  5. Explain Verification in the Pull Request

    Describe the problem in your own words, show how you reproduced and verified it, and include screenshots when UI behavior changes. If AI automation produced or co-produced the change, disclose that assistance in the pull request body.

Caution The repository requires signed commits and currently reviews contributor pull requests for scope, ownership and verification quality. GPL-3.0 licensing still applies, and new dependencies should have a clear technical reason and a compatible license.

Clash Verge Releases, AutoBuilds and Self-Built Versions

Versioned releases are published through the project's release workflow, while AutoBuild continuously produces development builds from newer commits. Mihomo Stable/Alpha is a separate core channel inside the application.

Channel Who it's for Notes
Stable Release Routine use Versioned application releases with release notes and packaged assets
AutoBuild Testing recent development Frequently generated development builds that can surface regressions before a stable release
Self-built Development and customization Useful for local development and customization; distribution behavior depends on your own signing, packaging and platform setup

Note Application release channels and Mihomo core channels are different layers. A Clash Verge AutoBuild is not the same thing as switching the bundled Mihomo core to its Alpha channel. When sharing a self-built binary, label its source clearly so users know which commit, build settings and signing process produced it.

Clash Verge Build Troubleshooting

Most local build failures fall into dependency management, platform toolchains, missing prebuild assets or runtime webview/system libraries. Start with the exact error and the step that produced it.

Symptom Common cause What to do
Dependency install reports a lockfile error Project dependencies were installed with a different package-manager workflow Enable Corepack, remove the conflicting install state if necessary, then run pnpm install
Dev mode exits right after starting The runtime asset preparation step was skipped Run pnpm run prebuild; use --force when you need to re-download Mihomo and service binaries
Rust build reports a missing linker Platform build tools are missing (MSVC / CLT) Install the system build tools, reopen the terminal, then build again
Linux reports a missing library Development packages such as WebKitGTK aren't installed Install the matching -dev package for the library named in the error
Prebuild asset download times out The development environment cannot reach the asset download endpoints Fix terminal/network access first, then rerun the documented prebuild workflow
Packaging succeeds but the app opens blank The frontend assets weren't built properly, or WebView2 is missing Confirm the frontend build output exists; on Windows, install the WebView2 runtime
Interface strings you edited disappear after switching language Frontend and/or backend locale bundles were not kept in sync Follow CONTRIBUTING_i18n.md, align locale keys and run the current i18n checks for the area you changed

Contribute to Clash Verge Rev

Set up the current development environment, reproduce a real issue, keep the change narrow, run the required checks and submit a signed pull request with clear verification notes.