# How Rule-Based Routing and Rules Providers Are Managed in Clash Nyanpasu

> Learn how Clash Nyanpasu manages rule based routing and rule providers via its UI. View, refresh, and edit providers easily through the Tauri IPC bridge.

- Repository: [Nyanpasu/clash-nyanpasu](https://github.com/libnyanpasu/clash-nyanpasu)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Clash Nyanpasu delegates rule-based routing to the upstream Clash core while exposing a React-based UI layer that lets users view, refresh, and edit rule providers through a Tauri IPC bridge.**

Clash Nyanpasu is a modern GUI application that wraps the Clash core, providing users with intuitive control over complex proxy configurations. Understanding how rule-based routing and rules providers are managed within this architecture requires examining the clear separation between the Rust-based backend, the IPC communication layer, and the React frontend. This implementation allows users to manage external rule sets without manually editing YAML configuration files.

## Architecture Overview

The system follows a three-tier architecture that cleanly separates concerns between traffic routing logic and user interface management.

### The Three Layers

- **Clash Core (Backend)**: Written in Rust, this handles the actual `rules` array evaluation and `rule-providers` parsing. It exposes HTTP endpoints at `/providers/rules` for querying and updating providers.

- **IPC Service (Middle Layer)**: The Tauri-based backend in [`backend/tauri/src/server/mod.rs`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/backend/tauri/src/server/mod.rs) registers route handlers that bridge the Clash core's API to the frontend.

- **React UI (Frontend)**: Located in `frontend/nyanpasu/src/components/providers/`, this layer uses React Query to cache provider state and renders interactive components for manual refreshes.

## Backend Implementation

The Tauri server acts as a thin proxy between the Clash core and the frontend application.

### Route Registration

In [`backend/tauri/src/server/mod.rs`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/backend/tauri/src/server/mod.rs), the router exposes two critical endpoints for rule provider management:

```rust
router.route(
    "/providers/rules",
    get(providers_rules_handler)        // GET → returns JSON of all rule providers
        .put(put_providers_rules_handler) // PUT /:name → refresh a specific provider
);

```

The `providers_rules_handler` retrieves the current state of all rule providers from the Clash core, while `put_providers_rules_handler` triggers a download-and-reparse cycle for remote rule sets. When a refresh is initiated, the backend downloads the remote rule file, updates the provider metadata including `ruleCount` and `updatedAt`, and persists the changes to the appropriate `.dat` files on disk. The configuration parsing logic that handles the `rule-providers` section from the Clash YAML profile is located in [`backend/tauri/src/core/config/profile.rs`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/backend/tauri/src/core/config/profile.rs), which validates and updates provider entries when remote sources are refreshed.

## Frontend Data Flow

The frontend uses a custom React Query hook to manage server state and provide mutation capabilities for each provider.

### The useClashRulesProvider Hook

Located in [`frontend/interface/src/ipc/use-clash-rules-provider.ts`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/frontend/interface/src/ipc/use-clash-rules-provider.ts), this hook encapsulates the IPC communication:

```typescript
export const useClashRulesProvider = () => {
  const { providersRules, putProvidersRules } = useClashAPI()

  const query = useQuery({
    queryKey: [CLASH_RULES_PROVIDER_QUERY_KEY],
    queryFn: async () => {
      const { providers } = await providersRules()
      return Object.fromEntries(
        Object.entries(providers).map(([key, value]) => [
          key,
          { ...value, mutate: async () => {
              await putProvidersRules(key)   // backend PUT /providers/rules/:key
              await query.refetch()
            }},
        ]),
      ) as ClashRulesProviderQuery
    },
  })
  return query
}

```

This implementation caches provider data using the `CLASH_RULES_PROVIDER_QUERY_KEY` identifier. Each provider object returned by the hook includes a `mutate` function that executes `putProvidersRules(key)`, sending a `PUT` request to `/providers/rules/:name` and automatically refetching the query to update the UI with fresh metadata.

## UI Components

The visual interface for managing providers is built around the `RulesProvider` component.

### The RulesProvider Component

Found in [`frontend/nyanpasu/src/components/providers/rules-provider.tsx`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/frontend/nyanpasu/src/components/providers/rules-provider.tsx), this React component renders individual provider cards:

```tsx
export default function RulesProvider({ provider }: RulesProviderProps) {
  const { t } = useTranslation()
  const [loading, setLoading] = useState(false)

  const handleClick = useLockFn(async () => {
    try {
      setLoading(true)
      await provider.mutate()      // triggers backend refresh
    } finally {
      setLoading(false)
    }
  })

  return (
    <Paper className="flex flex-col gap-2 p-5">
      <div className="flex items-start justify-between">
        <p className="text-lg font-bold">{provider.name}</p>
        <div>{t('Last Update', { fromNow: dayjs(provider.updatedAt).fromNow() })}</div>
      </div>

      <Chip label={t('Rule Set rules', { rule: provider.ruleCount })} />
      <Button loading={loading} onClick={handleClick}>
        <Refresh />
      </Button>
    </Paper>
  )
}

```

The component displays the provider's `name`, `vehicleType`, `behavior`, and `ruleCount`. It uses `dayjs` to render human-readable timestamps via `dayjs(provider.updatedAt).fromNow()`. The refresh button utilizes `useLockFn` to prevent duplicate requests during the asynchronous update operation. This component is consumed by both the Legacy Providers page at `frontend/nyanpasu/src/pages/(legacy)/providers.tsx` and the Update Providers component at [`frontend/nyanpasu/src/components/providers/update-providers.tsx`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/frontend/nyanpasu/src/components/providers/update-providers.tsx).

## Rule-Based Routing Mechanics

While the UI manages provider metadata, the actual traffic routing logic remains inside the Clash core.

### Configuration Structure

The Clash configuration file defines routing through two key sections:

- **`rules` array**: Evaluated in order, mapping traffic to proxy groups or `RULE-SET` references
- **`rule-providers` map**: Defines external rule sets (GeoIP, GeoSite) that the core loads dynamically

When the core processes a connection, it iterates through the `rules` array. Entries referencing `RULE-SET` types point to providers defined in `rule-providers`, which can specify remote URLs for automatic updates. The core automatically reloads updated `.dat` files on the next routing decision after a successful refresh from the UI.

## Summary

- **Separation of concerns**: The Clash core handles traffic matching while Clash Nyanpasu provides a management interface.
- **Backend routes**: [`backend/tauri/src/server/mod.rs`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/backend/tauri/src/server/mod.rs) registers `/providers/rules` endpoints for fetching and updating providers.
- **Frontend state**: `useClashRulesProvider` in [`frontend/interface/src/ipc/use-clash-rules-provider.ts`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/frontend/interface/src/ipc/use-clash-rules-provider.ts) uses React Query to cache provider data and expose mutation functions.
- **UI rendering**: The `RulesProvider` component in [`frontend/nyanpasu/src/components/providers/rules-provider.tsx`](https://github.com/libnyanpasu/clash-nyanpasu/blob/main/frontend/nyanpasu/src/components/providers/rules-provider.tsx) displays metadata and triggers refreshes via `provider.mutate()`.
- **Data flow**: User clicks trigger `putProvidersRules()` → backend downloads remote rule sets → core reloads automatically → UI refetches via `query.refetch()`.

## Frequently Asked Questions

### How does Clash Nyanpasu update rule providers?

When a user clicks the refresh button in the `RulesProvider` component, the `mutate` function calls `putProvidersRules(key)`, which sends a `PUT` request to `/providers/rules/:name` on the Tauri backend. The backend then downloads the remote rule file, updates the provider's `ruleCount` and `updatedAt` metadata, and writes the new rules to disk for the Clash core to load.

### What is the difference between rule-based routing and rule providers?

**Rule-based routing** refers to the Clash core's process of evaluating the `rules` array against each connection to determine the appropriate proxy. **Rule providers** are external data sources (like GeoIP or GeoSite databases) defined in `rule-providers` that supply large rule sets to the `RULE-SET` entries in the main rules array, allowing dynamic updates without editing the main configuration file.

### Where does the actual traffic matching logic execute?

The traffic matching logic executes entirely within the upstream Clash core (Rust), not in the Clash Nyanpasu GUI. Clash Nyanpasu only manages the metadata and refresh cycles for rule providers through the IPC layer, while the core handles real-time packet evaluation against the loaded rule sets.

### How does the UI reflect when a provider was last updated?

The UI reads the `updatedAt` timestamp from each provider object and renders it using `dayjs(provider.updatedAt).fromNow()` in the `RulesProvider` component. This displays a human-readable relative time (such as "3 hours ago") next to the provider name, and the `ruleCount` chip shows the current number of rules loaded from that provider.