diff --git a/src/components/guard-state.tsx b/src/components/guard-state.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f17fd51634af8d3b8f03718e7b8bd5551f54e2ca
--- /dev/null
+++ b/src/components/guard-state.tsx
@@ -0,0 +1,58 @@
+import { cloneElement, isValidElement, ReactNode, useRef } from "react";
+import noop from "../utils/noop";
+
+interface Props<Value> {
+  value?: Value;
+  valueProps?: string;
+  onChangeProps?: string;
+  onChange?: (value: Value) => void;
+  onFormat?: (...args: any[]) => Value;
+  onGuard?: (value: Value) => Promise<void>;
+  onCatch?: (error: Error) => void;
+  children: ReactNode;
+}
+
+function GuardState<T>(props: Props<T>) {
+  const {
+    value,
+    children,
+    valueProps = "value",
+    onChangeProps = "onChange",
+    onGuard = noop,
+    onCatch = noop,
+    onChange = noop,
+    onFormat = (v: T) => v,
+  } = props;
+
+  const lockRef = useRef(false);
+
+  if (isValidElement(children)) {
+    const childProps = { ...children.props };
+
+    childProps[valueProps] = value;
+    childProps[onChangeProps] = async (...args: any[]) => {
+      // 多次操作无效
+      if (lockRef.current) return;
+
+      lockRef.current = true;
+      const oldValue = value;
+
+      try {
+        const newValue = (onFormat as any)(...args);
+        // 先在ui上响应操作
+        onChange(newValue);
+        await onGuard(newValue);
+      } catch (err: any) {
+        // 状态回退
+        onChange(oldValue!);
+        onCatch(err);
+      }
+      lockRef.current = false;
+    };
+    return cloneElement(children, childProps);
+  }
+
+  return children as any;
+}
+
+export default GuardState;
diff --git a/src/components/setting-clash.tsx b/src/components/setting-clash.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9fa9b324cc11263be0adfc584370b7e50b2350f8
--- /dev/null
+++ b/src/components/setting-clash.tsx
@@ -0,0 +1,101 @@
+import useSWR, { useSWRConfig } from "swr";
+import {
+  List,
+  ListItemText,
+  ListSubheader,
+  TextField,
+  Switch,
+  Select,
+  MenuItem,
+} from "@mui/material";
+import { ConfigType, getClashConfig, updateConfigs } from "../services/common";
+import { patchClashConfig } from "../services/command";
+import GuardState from "./guard-state";
+import SettingItem from "./setting-item";
+
+interface Props {
+  onError?: (err: Error) => void;
+}
+
+const SettingClash = ({ onError }: Props) => {
+  const { mutate } = useSWRConfig();
+  const { data: clashConfig } = useSWR("getClashConfig", getClashConfig);
+
+  const {
+    ipv6 = false,
+    "allow-lan": allowLan = false,
+    "log-level": logLevel = "silent",
+    "mixed-port": mixedPort = 7890,
+  } = clashConfig ?? {};
+
+  const onSwitchFormat = (_e: any, value: boolean) => value;
+
+  const onChangeData = (patch: Partial<ConfigType>) => {
+    mutate("getClashConfig", { ...clashConfig, ...patch }, false);
+  };
+
+  const onUpdateData = async (patch: Partial<ConfigType>) => {
+    await updateConfigs(patch);
+    await patchClashConfig(patch);
+  };
+
+  return (
+    <List sx={{ borderRadius: 1, boxShadow: 2, mt: 3 }}>
+      <ListSubheader>Clash设置</ListSubheader>
+
+      <SettingItem>
+        <ListItemText primary="局域网连接" />
+        <GuardState
+          value={allowLan}
+          valueProps="checked"
+          onCatch={onError}
+          onFormat={onSwitchFormat}
+          onChange={(e) => onChangeData({ "allow-lan": e })}
+          onGuard={(e) => onUpdateData({ "allow-lan": e })}
+        >
+          <Switch edge="end" />
+        </GuardState>
+      </SettingItem>
+
+      <SettingItem>
+        <ListItemText primary="IPv6" />
+        <GuardState
+          value={ipv6}
+          valueProps="checked"
+          onCatch={onError}
+          onFormat={onSwitchFormat}
+          onChange={(e) => onChangeData({ ipv6: e })}
+          onGuard={(e) => onUpdateData({ ipv6: e })}
+        >
+          <Switch edge="end" />
+        </GuardState>
+      </SettingItem>
+
+      <SettingItem>
+        <ListItemText primary="日志等级" />
+        <GuardState
+          value={logLevel}
+          onCatch={onError}
+          onFormat={(e: any) => e.target.value}
+          onChange={(e) => onChangeData({ "log-level": e })}
+          onGuard={(e) => onUpdateData({ "log-level": e })}
+        >
+          <Select size="small" sx={{ width: 120 }}>
+            <MenuItem value="info">Info</MenuItem>
+            <MenuItem value="warning">Warning</MenuItem>
+            <MenuItem value="error">Error</MenuItem>
+            <MenuItem value="debug">Debug</MenuItem>
+            <MenuItem value="silent">Silent</MenuItem>
+          </Select>
+        </GuardState>
+      </SettingItem>
+
+      <SettingItem>
+        <ListItemText primary="混合代理端口" />
+        <TextField size="small" defaultValue={mixedPort!} sx={{ width: 120 }} />
+      </SettingItem>
+    </List>
+  );
+};
+
+export default SettingClash;
diff --git a/src/components/setting-item.tsx b/src/components/setting-item.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..52a05843579988faf19758f733413fd0da3448d4
--- /dev/null
+++ b/src/components/setting-item.tsx
@@ -0,0 +1,8 @@
+import { ListItem, styled } from "@mui/material";
+
+const SettingItem = styled(ListItem)(() => ({
+  paddingTop: 5,
+  paddingBottom: 5,
+}));
+
+export default SettingItem;
diff --git a/src/components/setting-verge.tsx b/src/components/setting-verge.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..fa4794b0f1f1befe75fd626e07dec2d8428b1b0c
--- /dev/null
+++ b/src/components/setting-verge.tsx
@@ -0,0 +1,89 @@
+import useSWR, { useSWRConfig } from "swr";
+import { List, ListItemText, ListSubheader, Switch } from "@mui/material";
+import {
+  getVergeConfig,
+  patchVergeConfig,
+  setSysProxy,
+  VergeConfig,
+} from "../services/command";
+import GuardState from "./guard-state";
+import SettingItem from "./setting-item";
+import PaletteSwitch from "./palette-switch";
+
+interface Props {
+  onError?: (err: Error) => void;
+}
+
+const SettingVerge = ({ onError }: Props) => {
+  const { mutate } = useSWRConfig();
+  const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
+
+  const {
+    theme_mode: mode = "light",
+    enable_self_startup: startup = false,
+    enable_system_proxy: proxy = false,
+  } = vergeConfig ?? {};
+
+  const onSwitchFormat = (_e: any, value: boolean) => value;
+
+  const onChangeData = (patch: Partial<VergeConfig>) => {
+    mutate("getVergeConfig", { ...vergeConfig, ...patch }, false);
+  };
+
+  return (
+    <List sx={{ borderRadius: 1, boxShadow: 2 }}>
+      <ListSubheader>通用设置</ListSubheader>
+
+      <SettingItem>
+        <ListItemText primary="外观主题" />
+        <GuardState
+          value={mode === "dark"}
+          valueProps="checked"
+          onCatch={onError}
+          onFormat={onSwitchFormat}
+          onChange={(e) => onChangeData({ theme_mode: e ? "dark" : "light" })}
+          onGuard={async (c) => {
+            await patchVergeConfig({ theme_mode: c ? "dark" : "light" });
+          }}
+        >
+          <PaletteSwitch edge="end" />
+        </GuardState>
+      </SettingItem>
+
+      <SettingItem>
+        <ListItemText primary="开机自启" />
+        <GuardState
+          value={startup}
+          valueProps="checked"
+          onCatch={onError}
+          onFormat={onSwitchFormat}
+          onChange={(e) => onChangeData({ enable_self_startup: e })}
+          onGuard={async (e) => {
+            await patchVergeConfig({ enable_self_startup: e });
+          }}
+        >
+          <Switch edge="end" />
+        </GuardState>
+      </SettingItem>
+
+      <SettingItem>
+        <ListItemText primary="设置系统代理" />
+        <GuardState
+          value={proxy}
+          valueProps="checked"
+          onCatch={onError}
+          onFormat={onSwitchFormat}
+          onChange={(e) => onChangeData({ enable_system_proxy: e })}
+          onGuard={async (e) => {
+            await setSysProxy(e);
+            await patchVergeConfig({ enable_system_proxy: e });
+          }}
+        >
+          <Switch edge="end" />
+        </GuardState>
+      </SettingItem>
+    </List>
+  );
+};
+
+export default SettingVerge;
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
index 143871e1c7ced12e835c6146eab0b32118d9cc2f..61beaaec8ed8294f935dc0b7832743a0205517a8 100644
--- a/src/pages/_layout.tsx
+++ b/src/pages/_layout.tsx
@@ -1,9 +1,10 @@
-import { useMemo } from "react";
-import { SWRConfig } from "swr";
+import { useEffect, useMemo } from "react";
+import useSWR, { SWRConfig } from "swr";
 import { Route, Routes } from "react-router-dom";
-import { useRecoilValue } from "recoil";
+import { useRecoilState } from "recoil";
 import { createTheme, List, Paper, ThemeProvider } from "@mui/material";
 import { atomPaletteMode } from "../states/setting";
+import { getVergeConfig } from "../services/command";
 import LogoSvg from "../assets/image/logo.svg";
 import LogPage from "../pages/log";
 import HomePage from "../pages/home";
@@ -14,34 +15,39 @@ import ConnectionsPage from "../pages/connections";
 import ListItemLink from "../components/list-item-link";
 import Traffic from "../components/traffic";
 
+const routers = [
+  {
+    label: "代理",
+    link: "/proxy",
+  },
+  {
+    label: "规则",
+    link: "/rules",
+  },
+  {
+    label: "连接",
+    link: "/connections",
+  },
+  {
+    label: "日志",
+    link: "/log",
+  },
+  {
+    label: "设置",
+    link: "/setting",
+  },
+];
+
 const Layout = () => {
-  const paletteMode = useRecoilValue(atomPaletteMode);
+  const [mode, setMode] = useRecoilState(atomPaletteMode);
+  const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
 
-  const routers = [
-    {
-      label: "代理",
-      link: "/proxy",
-    },
-    {
-      label: "规则",
-      link: "/rules",
-    },
-    {
-      label: "连接",
-      link: "/connections",
-    },
-    {
-      label: "日志",
-      link: "/log",
-    },
-    {
-      label: "设置",
-      link: "/setting",
-    },
-  ];
+  useEffect(() => {
+    setMode(vergeConfig?.theme_mode ?? "light");
+  }, [vergeConfig?.theme_mode]);
 
   const theme = useMemo(() => {
-    if (paletteMode === "light") {
+    if (mode === "light") {
       document.documentElement.style.background = "#f5f5f5";
       document.documentElement.style.setProperty(
         "--selection-color",
@@ -66,7 +72,7 @@ const Layout = () => {
         },
       },
       palette: {
-        mode: paletteMode,
+        mode,
         primary: {
           main: "#5b5c9d",
         },
@@ -76,7 +82,7 @@ const Layout = () => {
         },
       },
     });
-  }, [paletteMode]);
+  }, [mode]);
 
   return (
     <SWRConfig value={{}}>
diff --git a/src/pages/setting.tsx b/src/pages/setting.tsx
index 0770a2de4f5ef2c05e4c54b517daa816b6287b5b..c15bc085da5cd3f2b4543ed58da02fd0ce8374ef 100644
--- a/src/pages/setting.tsx
+++ b/src/pages/setting.tsx
@@ -1,101 +1,17 @@
-import { useState } from "react";
-import { useRecoilState } from "recoil";
-import {
-  Box,
-  List,
-  ListItem,
-  ListItemText,
-  ListSubheader,
-  Typography,
-  TextField,
-  styled,
-  Switch,
-  Select,
-  MenuItem,
-} from "@mui/material";
-import { atomPaletteMode } from "../states/setting";
-import PaletteSwitch from "../components/palette-switch";
-import { setSysProxy } from "../services/command";
-
-const MiniListItem = styled(ListItem)(({ theme }) => ({
-  paddingTop: 5,
-  paddingBottom: 5,
-}));
+import { Box, Typography } from "@mui/material";
+import SettingVerge from "../components/setting-verge";
+import SettingClash from "../components/setting-clash";
 
 const SettingPage = () => {
-  const [mode, setMode] = useRecoilState(atomPaletteMode);
-  const [proxy, setProxy] = useState(false);
-
-  const onSysproxy = (enable: boolean) => {
-    const value = proxy;
-    setProxy(enable);
-    setSysProxy(enable)
-      .then(() => {
-        console.log("success");
-      })
-      .catch((err) => {
-        setProxy(value); // recover
-        console.log(err);
-      });
-  };
-
   return (
-    <Box sx={{ width: 0.9, maxWidth: "850px", mx: "auto", mb: 2 }}>
+    <Box sx={{ width: 0.9, maxWidth: 850, mx: "auto", mb: 2 }}>
       <Typography variant="h4" component="h1" sx={{ py: 2 }}>
         Setting
       </Typography>
 
-      <List sx={{ borderRadius: 1, boxShadow: 2 }}>
-        <ListSubheader>通用设置</ListSubheader>
-
-        <MiniListItem>
-          <ListItemText primary="外观主题" />
-          <PaletteSwitch
-            edge="end"
-            checked={mode !== "light"}
-            onChange={(_e, c) => setMode(c ? "dark" : "light")}
-          />
-        </MiniListItem>
-
-        <MiniListItem>
-          <ListItemText primary="开机自启" />
-          <Switch edge="end" />
-        </MiniListItem>
-
-        <MiniListItem>
-          <ListItemText primary="设置系统代理" />
-          <Switch
-            edge="end"
-            checked={proxy}
-            onChange={(_e, c) => onSysproxy(c)}
-          />
-        </MiniListItem>
-
-        <MiniListItem>
-          <ListItemText primary="局域网连接" />
-          <Switch edge="end" />
-        </MiniListItem>
-
-        <MiniListItem>
-          <ListItemText primary="IPv6" />
-          <Switch edge="end" />
-        </MiniListItem>
-
-        <MiniListItem>
-          <ListItemText primary="日志等级" />
-          <Select size="small" sx={{ width: 120 }}>
-            <MenuItem value="debug">Debug</MenuItem>
-            <MenuItem value="info">Info</MenuItem>
-            <MenuItem value="warning">Warning</MenuItem>
-            <MenuItem value="error">Error</MenuItem>
-          </Select>
-        </MiniListItem>
+      <SettingVerge />
 
-        <MiniListItem>
-          <ListItemText primary="混合代理端口" />
-          <TextField size="small" defaultValue={7890} sx={{ width: 120 }} />
-        </MiniListItem>
-      </List>
+      <SettingClash />
     </Box>
   );
 };
diff --git a/src/services/command.ts b/src/services/command.ts
index 84045b2612f431d8c62258537966d003f3709b8f..5fcb97fa5cb1db0bd9c5d098f57214bc51f8a71e 100644
--- a/src/services/command.ts
+++ b/src/services/command.ts
@@ -1,4 +1,5 @@
 import { invoke } from "@tauri-apps/api/tauri";
+import { ConfigType } from "./common";
 
 export async function restartSidecar() {
   return invoke<void>("restart_sidecar");
@@ -14,6 +15,10 @@ export async function getClashInfo() {
   return invoke<ClashInfo | null>("get_clash_info");
 }
 
+export async function patchClashConfig(payload: Partial<ConfigType>) {
+  return invoke<void>("patch_clash_config", { payload });
+}
+
 export async function importProfile(url: string) {
   return invoke<void>("import_profile", { url });
 }
@@ -56,3 +61,17 @@ export async function putProfiles(current: number) {
 export async function setSysProxy(enable: boolean) {
   return invoke<void>("set_sys_proxy", { enable });
 }
+
+export interface VergeConfig {
+  theme_mode?: "light" | "dark";
+  enable_self_startup?: boolean;
+  enable_system_proxy?: boolean;
+}
+
+export async function getVergeConfig() {
+  return invoke<VergeConfig>("get_verge_config");
+}
+
+export async function patchVergeConfig(payload: VergeConfig) {
+  return invoke<void>("patch_verge_config", { payload });
+}
diff --git a/src/services/common.ts b/src/services/common.ts
index 6ab0d3fc7d772bc9f7a85a2cfabf5ac8923bf1c5..604a85eeb5ab49ecb58925c8ebf64159e52565c2 100644
--- a/src/services/common.ts
+++ b/src/services/common.ts
@@ -12,14 +12,18 @@ export async function getVersion() {
 export interface ConfigType {
   port: number;
   mode: string;
+  ipv6: boolean;
   "socket-port": number;
   "allow-lan": boolean;
   "log-level": string;
   "mixed-port": number;
+  "redir-port": number;
+  "socks-port": number;
+  "tproxy-port": number;
 }
 
 /// Get current base configs
-export async function getConfigs() {
+export async function getClashConfig() {
   return (await getAxios()).get("/configs") as Promise<ConfigType>;
 }
 
diff --git a/src/utils/noop.ts b/src/utils/noop.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca6a744710d3ca4435f577fa0dfff4550d0f893f
--- /dev/null
+++ b/src/utils/noop.ts
@@ -0,0 +1 @@
+export default function noop() {}