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.
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.
-
Clone the repository
Get the source and change into the project directory.
-
Install Project Dependencies
Enable Corepack and use the repository's pinned pnpm workflow instead of introducing a different package manager.
-
Download Mihomo and Runtime Assets
Run the prebuild script to download the Mihomo core and service/sidecar binaries required by the current platform.
-
Start the Development Shell
pnpm devis the standard development command. The repository also exposespnpm dev:diffandpnpm dev:taurifor specific development cases. -
Build the Application
Use
pnpm buildfor the standard Tauri build orpnpm build:fastfor a faster testing build. Final artifact locations depend on the active target and Tauri bundle output.
# 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.
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.
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();
// 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.
# 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.
-
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.
-
Fork and create a branch
One branch, one thing, with a name that states the intent — for example
fix/tray-menu-crash. -
Run the Required Checks
Run
cargo clippy-allfor Rust,pnpm lintfor the frontend, then format withcargo fmtandpnpm format. Also reproduce the reported behavior and verify the actual fix. -
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.
-
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 |
Clash Verge Development Resources
Use the repository, contribution guide, source tree, workflow files, Releases and issue tracker when you need version-specific implementation details.
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.