[{"content":"这是一篇持续更新的踩坑笔记，记录我在 Guix System 上遇到的问题、原因分析和解决办法。\n1. bash 的 PATH 被 search path 机制重置，codex 注入的 apply_patch 也跟着失踪 现象\n在 home.scm 里用 home-environment-variables-service-type 定义的 PATH（比如 $HOME/.local/bin:$PATH），对 bash 压根不生效：\n(simple-service \u0026#39;local-bin-path home-environment-variables-service-type \u0026#39;((\u0026#34;PATH\u0026#34; . \u0026#34;$HOME/.local/bin:$PATH\u0026#34;))) 就是这段，bash 表示没见过。\n更麻烦的是 codex：它会把 apply_patch 之类的工具注入 PATH 来暴露给 agent，而它执行命令的 functions.exec_command 默认用 login bash。search path 机制顺手把 codex 刚注入的那段 PATH 清理干净，apply_patch 等重要工具当场找不到。\n原因\nGuix 的 search path 机制重置 PATH 的时机或方法可能不太对：它在 profile / 会话加载时重新生成 PATH，把已有的 PATH 覆盖掉——不管那是你写在 home.scm 里的，还是 codex 刚刚塞进去的。\n解决办法\n正经解法还不知道，目前只能绕。我干脆换 fish 了（：\nbash：在 .profile、.bashrc 之类的文件里补 export PATH=...，注意要写在 search path 触发之后。 codex：告诉 codex，exec_command 必须加上 login: false。 2. 环境变量带着 /gnu/store 漏进 flatpak 沙盒 distrobox 同理。\n现象\nGuix System 有一堆环境变量的值本身就是 /gnu/store/... 路径，它们跟着进程环境漏进 flatpak 沙盒，而沙盒里看不到 /run/current-system/ 和 /gnu/store/。\n比如 SSL_CERT_FILE：\n❯ set -S SSL_CERT_FILE SSL_CERT_FILE: 设定在 global 作用域，导出，包含 1 个元素 $SSL_CERT_FILE[1]: |/run/current-system/profile/etc/ssl/certs/ca-certificates.crt| ❯ ls -al /run/current-system/profile/etc/ssl/certs/ca-certificates.crt lrwxrwxrwx 1 root root 99 1970年 1月 1日 /run/current-system/profile/etc/ssl/certs/ca-certificates.crt -\u0026gt; /gnu/store/5q06g15na23kmjy2c2hbwxynpm44vpvq-ca-certificate-bundle/etc/ssl/certs/ca-certificates.crt 变量进去了，文件却看不到，于是 SSL 报错，表现就是没有网络。\nVDPAU_DRIVER_PATH 同理：\n❯ set -S VDPAU_DRIVER_PATH VDPAU_DRIVER_PATH: 设定在 global 作用域，导出， 路径变量，包含 1 个元素 $VDPAU_DRIVER_PATH[1]: |/home/sorubedo/.guix-home/profile/lib/vdpau| ❯ ls -al /home/sorubedo/.guix-home/profile/lib/vdpau/ libvdpau_nvidia.so -\u0026gt; /gnu/store/sxwdaplgifxfhdv8rhv66ppyrq9nrxij-nvda-610.57/lib/vdpau/libvdpau_nvidia.so* libvdpau_trace.so -\u0026gt; /gnu/store/hc832ii502wxdg6h4kdcmr7ysn9b1ix6-libvdpau-1.5/lib/vdpau/libvdpau_trace.so* 目录里全是指向 /gnu/store/ 的符号链接。\n原因\n宿主的环境变量透传进了沙盒，值却指向沙盒里不存在的 /gnu/store 路径。\n放行 /gnu/store 之后的衍生问题\n我忽视沙盒安全性，给 flatpak 添加了这些目录的权限。SSL 是解决了，但原本「看得到环境变量、找不到文件、于是安全回退默认」从而正常的现象，反倒因为找到了文件而不正常了。\n比如用 PrismLauncher 玩 MC：它原本找不到 /gnu/store 里的图形驱动文件，从而回退到沙盒内自带的运行时，正常游玩；对它开放 /gnu/store 后，反而驱动对不上，导致 MC 启动失败。\n解决办法\n显式 unset 掉这些环境变量（用 flatpak override --user --unset-env=名字），变量直接不进沙盒，各软件一律用沙盒自带的默认值。这样也就没必要给沙盒开 /gnu/store 的权限了。\n我这里的 flatpak override --user --show，重点是这一长串 unset-environment：\n❯ flatpak override --user --show [Context] filesystems=~/Develop;xdg-templates;xdg-config/gtk-4.0:ro;xdg-videos;~/.icons:ro;xdg-public-share;xdg-pictures;xdg-download;xdg-music;xdg-config/gtk-3.0:ro;xdg-documents;~/.themes:ro;~/Projects;~/VMS unset-environment=LIBVA_DRIVERS_PATH;OBS_PLUGINS_DATA_DIRECTORY;VK_ADD_IMPLICIT_LAYER_PATH;DICPATH;GBM_BACKENDS_PATH;BASH_LOADABLES_PATH;UDEV_HWDB_PATH;GTK_DATA_PREFIX;GUIX_GDK_PIXBUF_MODULE_FILES;INFOPATH;FLATPAK_BINARY;TERMINFO;GIT_SSL_CAINFO;OBS_PLUGINS_DIRECTORY;VDPAU_DRIVER_PATH;P11_MODULE_PATH;MANPATH;GUIX_GTK3_PATH;GUIX_LOCPATH;GUILE_LOAD_COMPILED_PATH;GHOSTTY_RESOURCES_DIR;GUIX_LUA_CPATH;GIT_EXEC_PATH;LINUX_MODULE_DIRECTORY;CURL_CA_BUNDLE;SSL_CERT_DIR;TERMINFO_DIRS;GSETTINGS_SCHEMA_DIR;SSL_CERT_FILE;GUIX_GTK3_IM_MODULE_FILE;GUILE_LOAD_PATH;GHOSTTY_BIN_DIR;FCITX_ADDON_DIRS;GUIX_LUA_PATH;GUILE_EXTENSIONS_PATH [Environment] 段会把同一批变量再设成空值，作用是一样的，这里就不重复贴了。\n3. flatpak.sh 不生效，启动器发现不了 flatpak 应用 现象\n装好 flatpak 后，~/.guix-home/profile/etc/profile.d/flatpak.sh 不会生效。少了它设置的那几个变量，启动器就发现不了 flatpak 应用。\n原因\nflatpak.sh 走的是 profile.d 那套机制，但没人会去 source 它，所以脚本里往 XDG_DATA_DIRS 里加的 flatpak exports/share 路径从来没进过环境。\n解决办法\n自己在 home 里把这些变量补上（home.scm 里的 flatpak-environment）：\n(simple-service \u0026#39;flatpak-environment home-environment-variables-service-type \u0026#39;((\u0026#34;XDG_DATA_DIRS\u0026#34; . \u0026#34;$HOME/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:$XDG_DATA_DIRS\u0026#34;))) 4. home 侧 nvidia 驱动不生效，仍然链 mesa 驱动装是装了，就是不用。\n现象\n系统侧用 nonguix 的 nvidia 变换装驱动很方便：\n((nonguix-transformation-nvidia #:driver nvda-new-feature #:open-source-kernel-module? #t) %base-os) 但 home 侧的软件还是只链 mesa——nvidia 驱动和库明明在，就是不用。\n原因\nguix home reconfigure 和 guix system reconfigure 是两次独立的求值。\n系统侧的变换只作用于那份 operating-system 的 packages / services，管不到 home 那份 home-environment；home 侧的包在求值时从没被替换过 mesa，于是照旧链 mesa。\n解决办法\nhome 侧也要替换一遍：用 replace-mesa 包住 home 的 packages，或者干脆把整个 home-environment 包起来。\n参考配置（整个 home 一起包）：\n(replace-mesa (home-environment (packages (list nvda-new-feature ...)) (services (append (list ...) %base-home-services))) #:driver nvda-new-feature) 5. greetd 接管全部 tty 且删掉 login 服务模块：登录只剩 bash，锁屏无法解锁 现象\n按手册把 tty1-6 全部改成 greetd、去掉自带的 login 服务模块和 tty1-6 原本的 mingetty 服务模块后：\ngreetd 的 agetty 不管你登录 shell 配的是什么，登录进去只有 bash。 锁屏解不开。 原因\nagetty 那一层不读你在系统里配的登录 shell，所以只给 bash。 login 服务模块包含 /etc/pam.d/login。greetd 用的是自己的 /etc/pam.d/greetd，但一定会有别的软件依赖 login，比如 Noctalia shell 的锁屏就用它，没有就解锁不了。 解决办法\n只去掉 tty1 的 mingetty，改为 greetd + 自己喜欢的 greeter（我用 tuigreet）；tty2-tty6 保留原本的 mingetty，并保留 login 服务模块。\n参考配置：\n;; greetd 使用 tty1，其余终端由 mingetty 提供登录提示。 (define tuigreet-command #~(string-append #$tuigreet \u0026#34;/bin/tuigreet\u0026#34; \u0026#34; --time\u0026#34; \u0026#34; --remember\u0026#34; \u0026#34; --asterisks\u0026#34; \u0026#34; --power-shutdown \u0026#39;loginctl poweroff\u0026#39;\u0026#34; \u0026#34; --power-reboot \u0026#39;loginctl reboot\u0026#39;\u0026#34; \u0026#34; --cmd \u0026#39;niri --session\u0026#39;\u0026#34;)) (define greetd-service (service greetd-service-type (greetd-configuration (terminals (list (greetd-terminal-configuration (terminal-vt \u0026#34;1\u0026#34;) (terminal-switch #t) (default-session-command tuigreet-command))))))) (define mingetty-services (map (lambda (tty) (service mingetty-service-type (mingetty-configuration (tty tty)))) \u0026#39;(\u0026#34;tty2\u0026#34; \u0026#34;tty3\u0026#34; \u0026#34;tty4\u0026#34; \u0026#34;tty5\u0026#34; \u0026#34;tty6\u0026#34;))) (services (append (list greetd-service ...) mingetty-services (modify-services %base-services ;; 保留 login-service-type，供 Noctalia 生成 /etc/pam.d/login。 (delete mingetty-service-type)))) 6. home-niri-service-type 会自动拉起 niri，xdg-desktop-portal 配置也不生效 现象一：niri 会随登录自动拉起\n在 home-environment 里用 (service home-niri-service-type)，niri 并没有变成「登录界面里可选的一个会话」，而是成了个用户 shepherd 服务，用户一登录就被自动拉起来。\n解决办法\n不用这个服务，改为只把 niri 放进 home 的软件包列表：\n(home-environment (packages (list niri ...))) 现象二：xdg-desktop-portal 配置不生效\nniri 包自带的配置在 ~/.guix-home/profile/share/xdg-desktop-portal/niri-portals.conf，似乎没生效，OBS 等软件不知道怎么捕获屏幕：\n❯ cat .guix-home/profile/share/xdg-desktop-portal/niri-portals.conf [preferred] default=gnome;gtk; org.freedesktop.impl.portal.Access=gtk; org.freedesktop.impl.portal.Notification=gtk; org.freedesktop.impl.portal.Secret=gnome-keyring; 解决办法\nhome 配置里加上一份自己的：\n(simple-service \u0026#39;xdg-desktop-portal-config home-xdg-configuration-files-service-type `((\u0026#34;xdg-desktop-portal/niri-portals.conf\u0026#34; ,(plain-file \u0026#34;niri-portals.conf\u0026#34; \u0026#34;[preferred] default=gnome;gtk; org.freedesktop.impl.portal.Access=gtk; org.freedesktop.impl.portal.Notification=gtk; org.freedesktop.impl.portal.Secret=gnome-keyring; org.freedesktop.impl.portal.FileChooser=gtk; org.freedesktop.impl.portal.ScreenCast=gnome; org.freedesktop.impl.portal.Screenshot=gnome; \u0026#34;)))) FileChooser=gtk 是因为我用 pcmanfm-qt 而不是 nautilus。\n7. 自组装桌面缺少 x11-socket-directory-service-type，Xwayland-satellite 二次启动失败 现象\nniri 会话 + Xwayland-satellite：\n首次开机登录 niri，Xwayland 正常。 注销（不重启）后再次登录，Xwayland-satellite 启动失败，报 /tmp/.X11-unix 权限不对。 原因\n没有用 Guix 通用的 desktop 服务模块，而是自己拼各种模块，漏掉了 x11-socket-directory-service-type——它才负责创建并摆正 /tmp/.X11-unix 的权限。\n首次登录时该目录不存在，由 Xwayland-satellite 自行创建；在 umask 022 下权限被削成 755，此时还能凑合用。 注销再登录时目录已存在但权限不是它要求的 1777，校验不通过，直接报错退出。 解决办法\n导入模块并加入服务：\n(use-service-modules desktop) ;; … (service x11-socket-directory-service-type) 该服务是一个 one-shot shepherd 服务（依赖 file-systems），启动时执行 mkdir -p /tmp/.X11-unix 并 chmod 1777，权限在首次登录前就已就位，之后反复登录不再出错。\n8. Qt 图标不显示 现象\n启动器的应用图标、文件夹图标等都不显示。\n原因\n那些是 svg 图标，需要 qtsvg 才能渲染。\n解决办法\npackages 列表里加上 qtsvg：\n(packages (list qtsvg ...)) 9. pcmanfm-qt：打开方式里应用列表为空、没有垃圾桶 现象\n右键 → 打开方式 → 其他应用程序，里面的「已安装的应用程序」列表是空的。 没有垃圾桶。 解决办法\npackages 列表里补上 lxqt-menu-data 和 (list glib \u0026quot;bin\u0026quot;)：\n(packages (list pcmanfm-qt lxqt-menu-data ; 打开方式里的应用列表 (list glib \u0026#34;bin\u0026#34;) ; gio，垃圾桶要它 ...)) 10. virt-manager 默认 NAT 下虚拟机没网，改为自己声明的网桥 现象\n用 virt-manager 默认的 NAT 网络，虚拟机就是没网。\n原因\n不确定。怀疑是 virt-manager 的 NAT 插入的路由规则在 Guix 上和 docker0 等起了冲突。\n解决办法\n别用默认 NAT，自己声明一个网桥（我这里是 vmnat0，网段 192.168.240.0/24），虚拟机改用这个网桥。\n配置要点都在 system.scm 里：\n建桥并给宿主机地址： (service static-networking-service-type (list (static-networking (provision \u0026#39;(vmnat-networking)) (links (list (network-link (name \u0026#34;vmnat0\u0026#34;) (type \u0026#39;bridge) (arguments \u0026#39;())))) (addresses (list (network-address (device \u0026#34;vmnat0\u0026#34;) (value \u0026#34;192.168.240.1/24\u0026#34;))))))) 在这个桥上发 DHCP / DNS： (service dnsmasq-service-type (dnsmasq-configuration (shepherd-provision \u0026#39;(dnsmasq-vmnat0)) (shepherd-requirement \u0026#39;(vmnat-networking)) (extra-options (list \u0026#34;--except-interface=lo\u0026#34; \u0026#34;--interface=vmnat0\u0026#34; \u0026#34;--bind-dynamic\u0026#34; \u0026#34;--dhcp-range=192.168.240.100,192.168.240.254,255.255.255.0,12h\u0026#34; \u0026#34;--dhcp-option=option:router,192.168.240.1\u0026#34; \u0026#34;--dhcp-option=option:dns-server,192.168.240.1\u0026#34;)))) 打开 IPv4 转发，并装 NAT 规则（vmnat0-firewall-service：INPUT 放行 vmnat0 的 DHCP/DNS，FORWARD 放行 vmnat0，POSTROUTING 对 192.168.240.0/24 做 MASQUERADE）： (modify-services %base-services (sysctl-service-type config =\u0026gt; (sysctl-configuration (settings (cons \u0026#39;(\u0026#34;net.ipv4.ip_forward\u0026#34; . \u0026#34;1\u0026#34;) %default-sysctl-settings))))) 让 dhcpcd 别管这个桥： (service dhcpcd-service-type (dhcpcd-configuration (extra-content \u0026#34;denyinterfaces vmnat0\\n\u0026#34;))) 最后把虚拟机的网卡接到 vmnat0。 ","permalink":"https://site.sorubedo.xyz/posts/guix-pitfalls/","summary":"使用 Guix System 过程中踩过的坑：本文持续更新。","title":"Guix 踩坑记录以及解决办法"},{"content":"本站用到的东西：\nHugo — 静态站点生成器 PaperMod — Hugo主题 Tailwind CSS — 补样式 FastAPI — 后端 Twikoo — 评论系统 Simple Icons — 发行版图标 服务器 正在读取系统信息… — · — · — CPU — — — 内存 — — Swap — 磁盘 — — 读取系统信息失败。 重试 运行时间 — 启动于 — 更新于 — （需要 JavaScript 才能显示实时数据） 磁盘 / — — ","permalink":"https://site.sorubedo.xyz/site/","summary":"\u003cp\u003e本站用到的东西：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e — 静态站点生成器\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/adityatelange/hugo-PaperMod\"\u003ePaperMod\u003c/a\u003e — Hugo主题\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://tailwindcss.com/\"\u003eTailwind CSS\u003c/a\u003e — 补样式\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://fastapi.tiangolo.com/\"\u003eFastAPI\u003c/a\u003e — 后端\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://twikoo.js.org/\"\u003eTwikoo\u003c/a\u003e — 评论系统\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://simpleicons.org/\"\u003eSimple Icons\u003c/a\u003e — 发行版图标\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"服务器\"\u003e服务器\u003c/h2\u003e\n\u003cdiv id=\"sysinfo-0\" class=\"sysinfo my-6 overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)]\" data-endpoint=\"/api/system/info\" data-interval=\"15000\"\u003e\n  \u003cdiv class=\"flex items-center gap-4 border-b border-[color:var(--tertiary)] p-4 sm:p-5\"\u003e\u003cdiv data-field=\"os-icon-wrap\" class=\"grid h-14 w-14 shrink-0 place-items-center rounded-2xl border border-[color:var(--tertiary)] bg-[var(--code-bg)] transition-colors\"\u003e\u003cimg data-field=\"os-icon\" alt=\"\" width=\"36\" height=\"36\" decoding=\"async\" class=\"h-9 w-9 opacity-0 transition-opacity duration-300\" style=\"margin:0;border-radius:0\"\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"min-w-0 flex-1\"\u003e\n      \u003cdiv class=\"flex min-w-0 items-center gap-2\"\u003e\n        \u003cspan data-field=\"os-name\" class=\"animate-pulse truncate text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003e正在读取系统信息…\u003c/span\u003e\n        \u003cspan data-field=\"os-version\" style=\"display:none\" class=\"shrink-0 rounded-full border border-[color:var(--tertiary)] px-2 py-0.5 font-mono text-[11px] leading-none text-[color:var(--secondary)]\"\u003e\u003c/span\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"mt-1 flex min-w-0 items-center gap-1.5 font-mono text-xs text-[color:var(--secondary)]\"\u003e\n        \u003cspan data-field=\"os-host\" class=\"animate-pulse truncate\"\u003e—\u003c/span\u003e\n        \u003cspan class=\"shrink-0 select-none\" aria-hidden=\"true\"\u003e·\u003c/span\u003e\n        \u003cspan data-field=\"os-kernel\" class=\"animate-pulse truncate\"\u003e—\u003c/span\u003e\n        \u003cspan class=\"shrink-0 select-none\" aria-hidden=\"true\"\u003e·\u003c/span\u003e\n        \u003cspan data-field=\"os-arch\" class=\"animate-pulse shrink-0\"\u003e—\u003c/span\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n    \u003cbutton type=\"button\" data-action=\"refresh\" title=\"刷新\" aria-label=\"刷新系统信息\" class=\"shrink-0 rounded-full border border-[color:var(--tertiary)] p-2 text-[color:var(--secondary)] transition-colors hover:border-[color:var(--secondary)] hover:text-[color:var(--primary)] disabled:opacity-50 disabled:cursor-progress\"\u003e\n      \u003csvg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"h-4 w-4\" aria-hidden=\"true\"\u003e\n        \u003cpath d=\"M20 11a8 8 0 1 0-2.34 5.66\"\u003e\u003c/path\u003e\n        \u003cpath d=\"M20 4v7h-7\"\u003e\u003c/path\u003e\n      \u003c/svg\u003e\n    \u003c/button\u003e\n  \u003c/div\u003e\n  \u003cdiv data-field=\"body\" class=\"grid gap-3 p-4 sm:grid-cols-2 sm:p-5\"\u003e\n    \u003cdiv class=\"rounded-lg bg-[var(--code-bg)] p-4 sm:col-span-2\"\u003e\n      \u003cdiv class=\"flex items-baseline justify-between gap-3\"\u003e\n        \u003cspan class=\"text-xs font-medium tracking-wide text-[color:var(--secondary)]\"\u003eCPU\u003c/span\u003e\n        \u003cspan data-field=\"cpu-percent\" class=\"animate-pulse font-mono text-sm text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"mt-2.5 h-2 w-full overflow-hidden rounded-full bg-[color:var(--tertiary)]\" role=\"progressbar\" aria-label=\"CPU 占用率\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\"\u003e\n        \u003cdiv data-field=\"cpu-bar\" class=\"h-full rounded-full transition-[width] duration-700 ease-out motion-reduce:transition-none bg-emerald-500 dark:bg-emerald-400\" style=\"width:0%\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv data-field=\"cpu-model\" class=\"mt-2.5 animate-pulse truncate text-xs text-[color:var(--primary)]\"\u003e—\u003c/div\u003e\n      \u003cdiv data-field=\"cpu-meta\" class=\"mt-1 animate-pulse font-mono text-[11px] text-[color:var(--secondary)]\"\u003e—\u003c/div\u003e\n      \u003cdiv data-field=\"cpu-load\" class=\"mt-0.5 animate-pulse font-mono text-[11px] text-[color:var(--secondary)]\"\u003e\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"rounded-lg bg-[var(--code-bg)] p-4\"\u003e\n      \u003cdiv class=\"flex items-baseline justify-between gap-3\"\u003e\n        \u003cspan class=\"text-xs font-medium tracking-wide text-[color:var(--secondary)]\"\u003e内存\u003c/span\u003e\n        \u003cspan data-field=\"mem-value\" class=\"animate-pulse font-mono text-sm text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"mt-2.5 h-2 w-full overflow-hidden rounded-full bg-[color:var(--tertiary)]\" role=\"progressbar\" aria-label=\"内存占用率\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\"\u003e\n        \u003cdiv data-field=\"mem-bar\" class=\"h-full rounded-full transition-[width] duration-700 ease-out motion-reduce:transition-none bg-emerald-500 dark:bg-emerald-400\" style=\"width:0%\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n      \u003cdiv data-field=\"mem-meta\" class=\"mt-2.5 animate-pulse text-[11px] text-[color:var(--secondary)]\"\u003e—\u003c/div\u003e\u003cdiv data-field=\"swap\" style=\"display:none\" class=\"mt-3 border-t border-[color:var(--tertiary)] pt-3\"\u003e\n        \u003cdiv class=\"flex items-baseline justify-between gap-3\"\u003e\n          \u003cspan class=\"text-[11px] tracking-wide text-[color:var(--secondary)]\"\u003eSwap\u003c/span\u003e\n          \u003cspan data-field=\"swap-value\" class=\"font-mono text-[11px] text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-[color:var(--tertiary)]\" role=\"progressbar\" aria-label=\"Swap 占用率\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\"\u003e\n          \u003cdiv data-field=\"swap-bar\" class=\"h-full rounded-full transition-[width] duration-700 ease-out motion-reduce:transition-none bg-emerald-500 dark:bg-emerald-400\" style=\"width:0%\"\u003e\u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\u003cdiv data-field=\"disks\" class=\"contents\"\u003e\u003cdiv class=\"flex flex-col rounded-lg bg-[var(--code-bg)] p-4\"\u003e\n        \u003cdiv class=\"flex items-baseline justify-between gap-3\"\u003e\n          \u003cspan class=\"text-xs font-medium tracking-wide text-[color:var(--secondary)]\"\u003e磁盘\u003c/span\u003e\n          \u003cspan class=\"animate-pulse font-mono text-sm text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"mt-auto\"\u003e\n          \u003cdiv class=\"mt-2.5 h-2 w-full overflow-hidden rounded-full bg-[color:var(--tertiary)]\" role=\"progressbar\" aria-label=\"磁盘占用率\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\"\u003e\n            \u003cdiv class=\"h-full rounded-full transition-[width] duration-700 ease-out motion-reduce:transition-none bg-emerald-500 dark:bg-emerald-400\" style=\"width:0%\"\u003e\u003c/div\u003e\n          \u003c/div\u003e\n          \u003cdiv class=\"mt-2.5 animate-pulse text-[11px] text-[color:var(--secondary)]\"\u003e—\u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv data-field=\"error\" style=\"display:none\" class=\"mx-4 mb-4 rounded-lg border border-rose-500/40 bg-rose-500/10 px-4 py-3 text-sm text-rose-700 dark:text-rose-300 sm:mx-5 sm:mb-5\"\u003e\n    \u003cdiv class=\"flex flex-wrap items-center gap-3\"\u003e\n      \u003cspan data-field=\"error-msg\"\u003e读取系统信息失败。\u003c/span\u003e\n      \u003cbutton type=\"button\" data-action=\"retry\" class=\"rounded-full border border-rose-500/40 px-3 py-1 text-xs transition-colors hover:bg-rose-500/10\"\u003e重试\u003c/button\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"flex flex-wrap items-center gap-x-4 gap-y-1.5 border-t border-[color:var(--tertiary)] px-4 py-3 text-xs text-[color:var(--secondary)] sm:px-5\"\u003e\n    \u003cspan\u003e运行时间 \u003cspan data-field=\"uptime\" class=\"animate-pulse font-mono text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\u003c/span\u003e\n    \u003cspan\u003e启动于 \u003cspan data-field=\"boot\" class=\"animate-pulse font-mono text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\u003c/span\u003e\n    \u003cspan class=\"ml-auto inline-flex items-center gap-1.5\"\u003e\n      \u003cspan data-field=\"live-dot\" class=\"h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500 dark:bg-emerald-400\" aria-hidden=\"true\"\u003e\u003c/span\u003e\n     更新于 \u003cspan data-field=\"updated\" class=\"animate-pulse font-mono text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n      \u003cspan data-field=\"interval-hint\"\u003e\u003c/span\u003e\n      \u003cnoscript\u003e（需要 JavaScript 才能显示实时数据）\u003c/noscript\u003e\n    \u003c/span\u003e\n  \u003c/div\u003e\u003ctemplate data-template=\"disk\"\u003e\n    \u003cdiv class=\"flex flex-col rounded-lg bg-[var(--code-bg)] p-4\"\u003e\n      \u003cdiv class=\"flex items-baseline justify-between gap-3\"\u003e\n        \u003cspan class=\"text-xs font-medium tracking-wide text-[color:var(--secondary)]\"\u003e磁盘 \u003cspan data-field=\"disk-path\" class=\"font-mono text-[color:var(--primary)]\"\u003e/\u003c/span\u003e\u003c/span\u003e\n        \u003cspan data-field=\"disk-value\" class=\"font-mono text-sm text-[color:var(--primary)]\"\u003e—\u003c/span\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"mt-auto\"\u003e\n        \u003cdiv class=\"mt-2.5 h-2 w-full overflow-hidden rounded-full bg-[color:var(--tertiary)]\" role=\"progressbar\" aria-label=\"磁盘占用率\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\"\u003e\n          \u003cdiv data-field=\"disk-bar\" class=\"h-full rounded-full transition-[width] duration-700 ease-out motion-reduce:transition-none bg-emerald-500 dark:bg-emerald-400\" style=\"width:0%\"\u003e\u003c/div\u003e\n        \u003c/div\u003e\n        \u003cdiv data-field=\"disk-meta\" class=\"mt-2.5 text-[11px] text-[color:var(--secondary)]\"\u003e—\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/template\u003e\n\u003c/div\u003e\n\u003cscript crossorigin=\"anonymous\" defer src=\"/js/system-info.min.d975f34b27c04f23ebb1b50aad9f37758ed62cc2b534ec49b2fc8773dacea236.js\" integrity=\"sha256-2XXzSyfATyPrsbUKrZ83dY7WLMK1NOxJsvyHc9rOojY=\"\u003e\u003c/script\u003e","title":"关于本站"},{"content":" Oh! Guix! 传说中 GNU/Linux 发行版的终极答案——原子、声明式、完全自由。我用上了，大概两个月。下面这些算不上评测，更像一份折腾笔记。\n一、坑多 最大的感受就一个字：坑。比如 Guix 的 search path 机制会把 login bash 的 PATH 重置掉，导致 codex 的 exec_command 找不到它刚注入的 apply_patch；又比如一堆指向 /gnu/store 的环境变量漏进 flatpak 沙盒，让沙盒里的应用直接没网。\nGuix 的文档质量其实相当高，但社区人少，很多问题根本搜不到答案。说实话，如果没有 LLM agent，这里面很多坑我是解决不了的。\n具体的现象、原因和解决办法我都记在了《Guix 踩坑记录以及解决办法》里，那篇会持续更新。\n二、非 FHS 非 FHS 这一点我早有准备，毕竟之前用过 NixOS。而且现在能给 FHS 环境的东西太多了：flatpak、docker/podman、distrobox，Guix 自己的 guix shell 也有 -C、-F 选项可以起一个 FHS 容器环境。所以在开发上其实没什么问题。\n但是——AppImage 不能正常用，这就相当难受了。\n在 NixOS 上，有这些东西：\nprograms.appimage.enable = true; programs.appimage.binfmt = true; 还有 appimage-run。而在 Guix 上这些统统没有，官方和社区给出的答案是 guix shell -C -F，再把 dbus、Wayland 之类挂进去，大概长这样：\nguix shell \\ --container --network --emulate-fhs \\ --development ungoogled-chromium gcc:lib \\ --preserve=\u0026#39;^WAYLAND_DISPLAY$|^XDG_\u0026#39; --expose=$XDG_RUNTIME_DIR \\ --preserve=\u0026#39;^DBUS_\u0026#39; --expose=/var/run/dbus \\ -- ./xyz.AppImage 实际使用体验相当糟糕，每次都要手写一长串参数。\n顺带一提，guix pack -f appimage 本身也能打包 AppImage，加上 -RR 之后得到的是完整闭包——所有依赖都塞进去，只要目标机器有 FUSE 和 user namespace，不管跑的是 Guix 还是别的发行版都能直接用。我试着打包了 NetEase_Cloud_Music_Gtk4，结果产物接近 1G 🤣，所有编解码器都被打进去了。\n三、开发体验： guix shell 是个很不错的开发工具。配合 direnv，cd 进工作区就能自动把开发工具和依赖注入 PATH。比如我写 Rust 的时候：\n❯ cd Projects/gh2tg direnv: loading ~/Projects/gh2tg/.envrc direnv: using guix --manifest=manifest.scm direnv: export +CARGO_HTTP_CAINFO +CPLUS_INCLUDE_PATH +C_INCLUDE_PATH +GUIX_ENVIRONMENT +LIBRARY_PATH +OBJCPLUS_INCLUDE_PATH +OBJC_INCLUDE_PATH +PKG_CONFIG_PATH +RUST_SRC_PATH ~GUIX_LOCPATH ~PATH ~SSL_CERT_DIR ~SSL_CERT_FILE ;; manifest.scm — Rust 开发环境 ;; ;; 用法： ;; guix shell -m manifest.scm ;; 或者把该文件放到项目根目录后直接运行： ;; guix shell (specifications-\u0026gt;manifest (list ;; Rust 工具链 \u0026#34;rust\u0026#34; ; out 输出：rustc 编译器 \u0026#34;rust:cargo\u0026#34; ; Cargo 包管理器 \u0026#34;rust:tools\u0026#34; ; rustfmt 等附加开发工具 \u0026#34;rust:rust-src\u0026#34; ; 标准库源码（rust-analyzer / IDE 跳转需要） ;; 编译链接所需系统工具：提供 cc、ld 等 \u0026#34;gcc-toolchain\u0026#34; ;; 常用开发依赖 \u0026#34;pkg-config\u0026#34; ; 供 -sys 类 crate 查找系统库 \u0026#34;openssl\u0026#34; ; 很多 crate（如 reqwest、git2）会用到 \u0026#34;nss-certs\u0026#34; ; CA 证书，让 cargo 能通过 HTTPS 拉取 crates ;; 调试器 \u0026#34;gdb\u0026#34;)) 体验类似于 Nix 的 nix-shell + flakes。另外 guix shell 还能用 -D 指定一个派生，拿到构建这个派生所需的环境，但不安装它本身，调试构建时很好用。\n四、GNU 原教旨主义： Guix 官方 channel 会拒绝打包不是完全自由的软件。比如 PrismLauncher：启动器本身开源，但它的功能只服务于 Minecraft 这个闭源游戏，这种就进不了官方频道。\n而且大多数人手里的硬件本来就不完全自由，网卡尤其如此。官方安装镜像只有 Linux-Libre 和 GNU/Hurd 两种内核：Hurd 就不说了，Linux-Libre 根本驱动不了我笔记本的网卡——如果只用官方镜像，我连安装都完不成。\n所以我用的是「Guix·萌」镜像，它内置了 nonguix 频道和 Linux 内核。\n五、channel 生态： 同样是人少的问题。官方频道打包数量极其有限，而且部分包缺少维护、很久不同步更新。用 Guix 的话，维护一个个人 channel 几乎是必选项——我的频道在 sorubedo/guix-channel。\n但代价是要添加很多 channel，滚动体验就很差了：各个 channel 之间不会同步，GNU 频道一旦有破坏性更新，大概率会连累其他 channel 的可用性，导致 guix pull 拉不下来或者 guix system reconfigure 直接报错。\n而且 Guix 真的很慢，并没有比 Nix 好多少。\n还有一个具体的痛点：Flutter 目前相当难用 Guix 打包。它没有对应的 build system，pub.dev 又很难做到不联网（Guix 要求构建阶段离线），我就没找到任何一个 channel 包含任何 Flutter 软件。想自己打包，结果用 AI 也没打出来。\n六、桌面体验： 我用的 niri 在官方 channel 有打包，noctalia 也自带 Guix 频道，所以桌面体验这块我感觉和其他发行版大差不差。区别在于，很多组件要去各个 channel 里找，或者自己打包。\n我的日常桌面：niri + Noctalia。左边终端是 fastfetch，底下那条命令是 sudo herd status——Guix 的服务管理器是 GNU Shepherd，herd 就是它的控制命令。\n过程中也踩了一些坑，比如 (plasma-desktop-service-type) 配出来的 DM 居然是 GDM？不太理解。所以最后我没用桌面服务模块，而是自己组装——这一点和很多元发行版的体验是一致的。组装下来，我对一个日用桌面/WM 到底需要什么，已经相当门清了（\n桌面相关的坑我都记在了踩坑记录里：niri 服务与 xdg-desktop-portal、Xwayland、Qt 图标、文件管理器，还有 home 侧的 N 卡驱动。\n七、情绪价值： Guix 虽然 GNU 血统最纯正，但称得上是一个相当冷门特殊的发行版，甚至被认为属于「灵车」。了解 Guix 的人发现我在用它，大概率会感叹一声「你居然用 Guix」；我也曾因此被误以为是运维大神（。遇到不了解 Guix 的人，我也能好好跟他说道说道声明式 OS 的好处。\n但说到底，对于喜欢折腾的人，尝试和折腾各种发行版本来就是一件开心的事。\n现代热门发行版已经被 systemd 占领，在 init 和 services 管理这一块几乎没有什么新鲜感。systemd 做得相当好，我也爱用，但不能因此忽视别的 init 的特色。在 non-systemd 发行版里，我用过的还有 Gentoo（OpenRC）、Void（runit）、Alpine 和 postmarketOS。\n最令我爽的一次是 Gentoo：通宵等着它编译，从下载镜像到登录 Plasma 花了 9 个小时。再让我来一次我会嫌麻烦，但那种快感很难用语言描述。Guix也是，在装到物理机前，我在虚拟机改了很久配置，装上后的一周又在不断改配置。\n结语 Guix 不是给所有人的答案，但它把「声明式」和「完全自由」这两件事推到了极致。这两个月里，我一边被坑得怀疑人生，一边又确实舍不得换掉它。\n目前正在考虑回到 Debian Testing，反正 Guix 只要配置声明还在，就能随时复现。\n如果你也在用 Guix，欢迎看看我的踩坑记录——那里持续更新我在上面遇到的各种问题和解决办法。\nguix system shepherd-graph\n","permalink":"https://site.sorubedo.xyz/posts/guix-experience/","summary":"Oh! Guix! 传说中 GNU/Linux 发行版的终极答案——原子、声明式、完全自由。用了大概两个月，聊聊它的坑、非 FHS 的代价、开发体验、GNU 原教旨主义、channel 生态、桌面组装，以及那点很难被替代的情绪价值。","title":"用 Guix 两个月：一个爱折腾的人的真实体验"},{"content":"这是我第n个博客（\n一定不删了（\n以前的慢慢搬回来\n","permalink":"https://site.sorubedo.xyz/posts/hello-world/","summary":"\u003cp\u003e这是我第n个博客（\u003c/p\u003e\n\u003cp\u003e一定不删了（\u003c/p\u003e\n\u003cp\u003e以前的慢慢搬回来\u003c/p\u003e","title":"Hello World"},{"content":"\n我是 sorubedo。\n温州大学 大四在读 目前在找实习 正在使用：Guix System Guix channel：guix-channel GitHub：sorubedo B 站：sorubedo 文章：posts 技术栈 sorubedo@guix: ~ — 技术栈 $ skillfetch # 真本事 vibecoding 全靠 LLM 续命 [██████████████░░░░░░] 70% # 也就会一点 Rust 编译器教我做事 [█░░░░░░░░░░░░░░░░░░░] 7% Go 从入门到 if err != nil [█░░░░░░░░░░░░░░░░░░░] 6% JS / TS 只会 npm install [█░░░░░░░░░░░░░░░░░░░] 6% Kotlin 写过一点 Android [█░░░░░░░░░░░░░░░░░░░] 6% Dart Flutter 抄过 demo [█░░░░░░░░░░░░░░░░░░░] 5% $ bodyctl sleep Zzzzz...... ","permalink":"https://site.sorubedo.xyz/about/","summary":"\u003cp\u003e\u003cimg alt=\"sorubedo 的头像\" loading=\"lazy\" src=\"https://github.com/sorubedo.png?size=200\"\u003e\u003c/p\u003e\n\u003cp\u003e我是 sorubedo。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e温州大学 大四在读\u003c/li\u003e\n\u003cli\u003e目前在找实习\u003c/li\u003e\n\u003cli\u003e正在使用：Guix System\u003c/li\u003e\n\u003cli\u003eGuix channel：\u003ca href=\"https://github.com/sorubedo/guix-channel\"\u003eguix-channel\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eGitHub：\u003ca href=\"https://github.com/sorubedo\"\u003esorubedo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eB 站：\u003ca href=\"https://space.bilibili.com/3537119790238250\"\u003esorubedo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e文章：\u003ca href=\"/posts/\"\u003eposts\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"技术栈\"\u003e技术栈\u003c/h2\u003e\n\u003cdiv class=\"tech-stack my-6 overflow-hidden rounded-[10px] border border-[color:var(--tertiary)] bg-[var(--entry)]\"\u003e\n  \u003cdiv class=\"flex items-center gap-1.5 border-b border-[color:var(--tertiary)] bg-[var(--code-bg)] px-4 py-2.5\"\u003e\n    \u003cspan class=\"h-3 w-3 rounded-full bg-[#ff5f57]\"\u003e\u003c/span\u003e\n    \u003cspan class=\"h-3 w-3 rounded-full bg-[#febc2e]\"\u003e\u003c/span\u003e\n    \u003cspan class=\"h-3 w-3 rounded-full bg-[#28c840]\"\u003e\u003c/span\u003e\n    \u003cspan class=\"ml-2 truncate font-mono text-xs text-[color:var(--secondary)]\"\u003esorubedo@guix: ~ — 技术栈\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"px-4 py-4 font-mono text-xs leading-[1.7] sm:px-5 sm:text-[13px]\"\u003e\n    \u003cdiv class=\"flex gap-2\"\u003e\n      \u003cspan class=\"shrink-0 select-none text-emerald-600 dark:text-emerald-400\"\u003e$\u003c/span\u003e\n      \u003cspan class=\"text-[color:var(--primary)]\"\u003eskillfetch\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"ts-row mt-5 mb-1.5 text-[color:var(--secondary)]\" style=\"animation-delay:0ms\"\u003e\n      \u003cspan class=\"select-none\"\u003e#\u003c/span\u003e 真本事\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:0ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003evibecoding\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003e全靠 LLM 续命\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-sky-600 dark:text-sky-400\" style=\"animation-delay:140ms\"\u003e██████████████\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e70%\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"ts-row mt-5 mb-1.5 text-[color:var(--secondary)]\" style=\"animation-delay:90ms\"\u003e\n      \u003cspan class=\"select-none\"\u003e#\u003c/span\u003e 也就会一点\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:90ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003eRust\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003e编译器教我做事\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-amber-600 dark:text-amber-400\" style=\"animation-delay:230ms\"\u003e█\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░░░░░░░░░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e7%\u003c/span\u003e\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:130ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003eGo\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003e从入门到 if err != nil\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-amber-600 dark:text-amber-400\" style=\"animation-delay:270ms\"\u003e█\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░░░░░░░░░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e6%\u003c/span\u003e\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:170ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003eJS / TS\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003e只会 npm install\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-amber-600 dark:text-amber-400\" style=\"animation-delay:310ms\"\u003e█\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░░░░░░░░░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e6%\u003c/span\u003e\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:210ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003eKotlin\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003e写过一点 Android\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-amber-600 dark:text-amber-400\" style=\"animation-delay:350ms\"\u003e█\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░░░░░░░░░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e6%\u003c/span\u003e\n    \u003c/div\u003e\u003cdiv class=\"ts-row flex flex-wrap items-center gap-x-3 gap-y-0.5\" style=\"animation-delay:250ms\"\u003e\n      \u003cspan class=\"w-full truncate text-[color:var(--primary)] sm:w-36 sm:shrink-0\"\u003eDart\u003c/span\u003e\n      \u003cspan class=\"max-sm:hidden min-w-0 flex-1 truncate text-[color:var(--secondary)]\"\u003eFlutter 抄过 demo\u003c/span\u003e\n      \u003cspan class=\"ml-auto inline-block\" aria-hidden=\"true\"\u003e\n        \u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e[\u003c/span\u003e\u003cspan class=\"ts-fill inline-block text-amber-600 dark:text-amber-400\" style=\"animation-delay:390ms\"\u003e█\u003c/span\u003e\u003cspan class=\"inline-block select-none text-[color:var(--tertiary)] dark:text-[color:var(--secondary)] dark:opacity-40\"\u003e░░░░░░░░░░░░░░░░░░░\u003c/span\u003e\u003cspan class=\"select-none text-[color:var(--tertiary)]\"\u003e]\u003c/span\u003e\n      \u003c/span\u003e\n      \u003cspan class=\"w-10 shrink-0 text-right text-[color:var(--secondary)]\"\u003e5%\u003c/span\u003e\n    \u003c/div\u003e\u003cdiv class=\"ts-row mt-5 flex gap-2\" style=\"animation-delay:390ms\"\u003e\n      \u003cspan class=\"shrink-0 select-none text-emerald-600 dark:text-emerald-400\"\u003e$\u003c/span\u003e\n      \u003cspan class=\"text-[color:var(--primary)]\"\u003ebodyctl sleep\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"ts-row text-[color:var(--secondary)]\" style=\"animation-delay:450ms\"\u003eZzzzz......\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e","title":"关于我"},{"content":" guix-channel ★ 1 个人的 Guix channel，收录还没进入 Guix 官方仓库的软件包和服务，比如 steamguard-cli、带 Lua 和 Octagram 插件的 librime，以及 virtiofsd 服务。 Scheme Guix 软件包打包 查看源码\u0026nbsp;\u0026rarr; GH2TG ★ 2 把 GitHub 的提交、Release 和 Actions 构建产物轮询推送到 Telegram 群组话题，不用自建服务器，也不用配置 webhook。 Rust GitHub Actions Telegram 查看源码\u0026nbsp;\u0026rarr; runsvdir-magisk ★ 3 把 Termux 预编译的 runsvdir、runsv、sv 等 runit 工具打包成 Magisk/KernelSU 模块，让 Android 开机后自动拉起并守护常驻服务。 Runit Magisk Android 查看源码\u0026nbsp;\u0026rarr; i-wzu-auth ★ 2 针对温州大学深澜网关的校园网认证 CLI，完整实现 XXTEA、Custom Base64 与 HMAC-MD5 协议，可在服务器、软路由或开机脚本里一键登录、查询在线状态和注销，并支持绑定物理网卡绕过 TUN 代理。 Rust CLI 校园网认证 查看源码\u0026nbsp;\u0026rarr; Obedur-OS ★ 3 基于 BlueBuild 构建的 Fedora Atomic 不可变系统镜像，开箱即用的 Niri 滚动平铺 Wayland 桌面，集成 CachyOS LTO 优化内核与 SecureBoot 签名。 已停止维护 BlueBuild Fedora Atomic Niri Wayland 访问文档站\u0026nbsp;\u0026rarr; ","permalink":"https://site.sorubedo.xyz/portfolio/","summary":"\u003cdiv class=\"columns-1 gap-6 sm:columns-2\"\u003e\n  \n\u003cdiv class=\"group mb-6 flex break-inside-avoid flex-col overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)] transition-colors hover:border-[color:var(--secondary)]\"\u003e\n  \u003cdiv class=\"flex flex-1 flex-col gap-2 p-5\"\u003e\n    \u003cdiv class=\"flex items-baseline justify-between gap-2\"\u003e\n      \u003cdiv class=\"text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003eguix-channel\u003c/div\u003e\n      \u003cdiv class=\"shrink-0 text-xs text-[color:var(--secondary)]\" title=\"GitHub stars\"\u003e★ 1\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"text-sm leading-relaxed text-[color:var(--secondary)]\"\u003e个人的 Guix channel，收录还没进入 Guix 官方仓库的软件包和服务，比如 steamguard-cli、带 Lua 和 Octagram 插件的 librime，以及 virtiofsd 服务。\u003c/div\u003e\n    \u003cdiv class=\"mt-auto flex flex-wrap gap-2 pt-3\"\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eScheme\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eGuix\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003e软件包打包\u003c/span\u003e\n    \u003c/div\u003e\n    \u003ca class=\"mt-3 inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--primary)] underline decoration-[color:var(--tertiary)] underline-offset-4 hover:decoration-[color:var(--secondary)]\" href=\"https://github.com/sorubedo/guix-channel\"\u003e查看源码\u0026nbsp;\u0026rarr;\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"group mb-6 flex break-inside-avoid flex-col overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)] transition-colors hover:border-[color:var(--secondary)]\"\u003e\n  \u003cdiv class=\"flex flex-1 flex-col gap-2 p-5\"\u003e\n    \u003cdiv class=\"flex items-baseline justify-between gap-2\"\u003e\n      \u003cdiv class=\"text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003eGH2TG\u003c/div\u003e\n      \u003cdiv class=\"shrink-0 text-xs text-[color:var(--secondary)]\" title=\"GitHub stars\"\u003e★ 2\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"text-sm leading-relaxed text-[color:var(--secondary)]\"\u003e把 GitHub 的提交、Release 和 Actions 构建产物轮询推送到 Telegram 群组话题，不用自建服务器，也不用配置 webhook。\u003c/div\u003e\n    \u003cdiv class=\"mt-auto flex flex-wrap gap-2 pt-3\"\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eRust\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eGitHub Actions\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eTelegram\u003c/span\u003e\n    \u003c/div\u003e\n    \u003ca class=\"mt-3 inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--primary)] underline decoration-[color:var(--tertiary)] underline-offset-4 hover:decoration-[color:var(--secondary)]\" href=\"https://github.com/sorubedo/gh2tg\"\u003e查看源码\u0026nbsp;\u0026rarr;\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"group mb-6 flex break-inside-avoid flex-col overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)] transition-colors hover:border-[color:var(--secondary)]\"\u003e\n  \u003cdiv class=\"flex flex-1 flex-col gap-2 p-5\"\u003e\n    \u003cdiv class=\"flex items-baseline justify-between gap-2\"\u003e\n      \u003cdiv class=\"text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003erunsvdir-magisk\u003c/div\u003e\n      \u003cdiv class=\"shrink-0 text-xs text-[color:var(--secondary)]\" title=\"GitHub stars\"\u003e★ 3\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"text-sm leading-relaxed text-[color:var(--secondary)]\"\u003e把 Termux 预编译的 runsvdir、runsv、sv 等 runit 工具打包成 Magisk/KernelSU 模块，让 Android 开机后自动拉起并守护常驻服务。\u003c/div\u003e\n    \u003cdiv class=\"mt-auto flex flex-wrap gap-2 pt-3\"\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eRunit\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eMagisk\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eAndroid\u003c/span\u003e\n    \u003c/div\u003e\n    \u003ca class=\"mt-3 inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--primary)] underline decoration-[color:var(--tertiary)] underline-offset-4 hover:decoration-[color:var(--secondary)]\" href=\"https://github.com/sorubedo/runsvdir-magisk\"\u003e查看源码\u0026nbsp;\u0026rarr;\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"group mb-6 flex break-inside-avoid flex-col overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)] transition-colors hover:border-[color:var(--secondary)]\"\u003e\n  \u003cdiv class=\"flex flex-1 flex-col gap-2 p-5\"\u003e\n    \u003cdiv class=\"flex items-baseline justify-between gap-2\"\u003e\n      \u003cdiv class=\"text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003ei-wzu-auth\u003c/div\u003e\n      \u003cdiv class=\"shrink-0 text-xs text-[color:var(--secondary)]\" title=\"GitHub stars\"\u003e★ 2\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"text-sm leading-relaxed text-[color:var(--secondary)]\"\u003e针对温州大学深澜网关的校园网认证 CLI，完整实现 XXTEA、Custom Base64 与 HMAC-MD5 协议，可在服务器、软路由或开机脚本里一键登录、查询在线状态和注销，并支持绑定物理网卡绕过 TUN 代理。\u003c/div\u003e\n    \u003cdiv class=\"mt-auto flex flex-wrap gap-2 pt-3\"\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eRust\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eCLI\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003e校园网认证\u003c/span\u003e\n    \u003c/div\u003e\n    \u003ca class=\"mt-3 inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--primary)] underline decoration-[color:var(--tertiary)] underline-offset-4 hover:decoration-[color:var(--secondary)]\" href=\"https://github.com/sorubedo/i-wzu-auth\"\u003e查看源码\u0026nbsp;\u0026rarr;\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"group mb-6 flex break-inside-avoid flex-col overflow-hidden rounded-[var(--radius)] border border-[color:var(--tertiary)] bg-[var(--entry)] transition-colors hover:border-[color:var(--secondary)]\"\u003e\n  \u003cdiv class=\"aspect-[16/9] w-full overflow-hidden border-b border-[color:var(--tertiary)] bg-[var(--code-bg)]\"\u003e\u003cimg src=\"/images/portfolio/obedur-os.webp\" alt=\"Obedur-OS\" loading=\"lazy\" style=\"margin:0;border-radius:0\" class=\"h-full w-full object-cover transition-transform duration-300 group-hover:scale-[1.03]\"\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"flex flex-1 flex-col gap-2 p-5\"\u003e\n    \u003cdiv class=\"flex items-baseline justify-between gap-2\"\u003e\n      \u003cdiv class=\"text-base font-semibold tracking-tight text-[color:var(--primary)]\"\u003eObedur-OS\u003c/div\u003e\n      \u003cdiv class=\"shrink-0 text-xs text-[color:var(--secondary)]\" title=\"GitHub stars\"\u003e★ 3\u003c/div\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"text-sm leading-relaxed text-[color:var(--secondary)]\"\u003e基于 BlueBuild 构建的 Fedora Atomic 不可变系统镜像，开箱即用的 Niri 滚动平铺 Wayland 桌面，集成 CachyOS LTO 优化内核与 SecureBoot 签名。\u003c/div\u003e\n    \u003cdiv class=\"mt-auto flex flex-wrap gap-2 pt-3\"\u003e\n      \u003cspan class=\"rounded-full border border-amber-500/60 bg-amber-500/15 px-2.5 py-0.5 text-xs font-medium text-amber-700 dark:border-amber-400/50 dark:bg-amber-400/15 dark:text-amber-300\"\u003e已停止维护\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eBlueBuild\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eFedora Atomic\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eNiri\u003c/span\u003e\n      \u003cspan class=\"rounded-full border border-[color:var(--tertiary)] px-2.5 py-0.5 text-xs text-[color:var(--secondary)]\"\u003eWayland\u003c/span\u003e\n    \u003c/div\u003e\n    \u003ca class=\"mt-3 inline-flex w-fit items-center gap-1 text-sm font-medium text-[color:var(--primary)] underline decoration-[color:var(--tertiary)] underline-offset-4 hover:decoration-[color:var(--secondary)]\" href=\"https://sorubedo.github.io/obedur-os/\"\u003e访问文档站\u0026nbsp;\u0026rarr;\u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\n\u003c/div\u003e","title":"作品集"}]