06 · 配置、状态与覆盖层¶
Omarchy 最重要的隐性 API 不是函数,而是路径。读写错误的层,会造成“升级覆盖定制”“重启丢状态”或“生成结果永久污染配置”。
四类持久对象¶
flowchart LR
Default[发行默认值<br/>/usr/share/omarchy] --> Resolve[解析/合并/编译]
Intent[用户意图<br/>~/.config] --> Resolve
Resolve --> Generated[生成状态<br/>~/.local/state]
Generated --> Runtime[Hyprland / Quickshell]
Runtime --> Ephemeral[锁与握手<br/>runtime / tmp]
| 类型 | 谁拥有 | 可以覆盖吗 | 丢失后 |
|---|---|---|---|
| 发行默认值 | pacman | 不应原地改 | 重装包恢复 |
| 用户意图 | 用户 | 是,显式编辑 | 可能失去定制 |
| 生成状态 | Omarchy 命令 | 不宜手改 | 通常可重新生成 |
| 瞬态协调 | 运行进程 | 无持久语义 | 下次操作重建 |
/etc/skel 不是“默认值实时镜像”¶
它只在创建用户时 seed home。此后用户配置的升级应该通过迁移、hash-aware 替换或显式 reinstall 完成,不能假设重新复制 skel 安全。
这个区分让发行方可以继续改进 defaults,同时不把用户 home 当成包管理器的扩展目录。
不同子系统采用不同合并语义¶
“用户配置覆盖默认值”听起来统一,实际至少有四种策略。
策略 A:整体替换¶
Shell 配置先构造内置 fallback,再尝试 packaged defaults,最后读取合法的 ~/.config/omarchy/shell.json。用户文件一旦有效,替换整个配置对象,而不是深合并。
优点是语义简单、不会混入未来新增默认项;代价是用户配置需要包含自己依赖的完整结构。
策略 B:按 ID 字段覆盖¶
菜单用 dotted ID 标识条目。用户 extension 找到同 ID 后按字段覆盖,未写字段保留默认;新 ID 追加。它适合希望“只改一个标签或 command”的场景。
策略 C:模板叠加¶
主题先处理内置 themed templates,再处理用户 ~/.config/omarchy/themed。用户可以新增目标或覆盖模板,最终都从同一份 colors.toml 编译。
策略 D:模块加载顺序¶
Hyprland 用 Lua require 顺序形成覆盖:default module → 用户 module → 动态 toggle。这里没有 JSON merge,后加载代码直接修改同一配置对象。
flowchart TD
Question{配置类型?}
Question -->|Shell JSON| Replace[有效用户对象整体替换]
Question -->|Menu JSONC| Field[同 ID 字段级覆盖]
Question -->|Theme template| Overlay[目录/模板叠加]
Question -->|Hypr Lua| Order[按 require 顺序覆盖]
因此不要把一个子系统的直觉套到另一个。排障第一步应确认“这类配置到底怎么合并”。
done marker 与 migration marker¶
两者都常是空文件,但承诺不同:
| marker | 典型位置 | 表示 |
|---|---|---|
| done | ~/.local/state/omarchy/done/* |
某个生命周期动作对该用户已完成 |
| migration | ~/.local/state/omarchy/migrations/<filename> |
这个具体版本迁移曾成功退出 |
删除 done marker 可能重跑首登行为;删除 migration marker 会重放状态变更脚本。后者风险更高,尤其迁移没有做到完全幂等时。
current 是活动生成视图¶
~/.local/state/omarchy/current 汇集当前应该被运行时读取的产物,例如当前主题与动态 Hyprland 状态。主题切换会先在 sibling staging 目录构建,再原子替换 current/theme,避免运行时看到半套文件。
这种“活动视图”把读取者简化为固定路径:Shell/Hyprland 不需要知道用户选择来自内置主题还是外部主题,也不需要参与编译过程。
瞬态状态为什么不放 home¶
更新锁、Shell restart lock、dmenu 选择握手和临时 transcript 不应成为跨启动事实。把它们放 $XDG_RUNTIME_DIR 或 /tmp 有两个作用:
- 生命周期与 session/boot 对齐,陈旧状态更少;
- 权限和并发语义比随意写 home 更清晰。
不过 /tmp 文件仍要使用安全创建、专属名称和 trap 清理;“临时”不自动等于“安全”。
系统状态单独处理¶
系统级事实落到 /etc、/usr/lib、/var/lib 或 Btrfs/Snapper 元数据,需要 root。Quattro 通过三种方式降低用户层误触:
- root 入口检查 EUID;
- 普通终端用 sudo,GUI/无终端路径可用 polkit;
- CLI 元数据把 requires-sudo 暴露在帮助中。
权限提示不是安全边界,真正边界仍由目标脚本、sudo/pkexec 和文件所有权执行。
修改前的决策表¶
| 需求 | 正确位置/机制 |
|---|---|
| 永久改变自己的菜单 | ~/.config/omarchy/extensions/omarchy-menu.jsonc |
| 自己的主题模板 | ~/.config/omarchy/themed |
| 临时切换窗口间距 | 让 omarchy-hyprland-toggle 写 state |
| 改进所有用户的发行默认值 | 上游 default/ 或 config/ + migration |
| 修复已安装用户配置 | 新 migration,成功后 marker |
| 开发 checkout | omarchy-dev-link / /etc/omarchy.conf |
| 重置 home 配置 | 明确运行 reinstall,并先确认破坏性影响 |
关键源码索引¶
docs/file-layout.md— 路径所有权基线shell/shell.qml配置 fallbackdefault/omarchy/omarchy-menu.jsonc— 菜单默认数据bin/omarchy-theme-set— 主题 staging/current 原子状态bin/omarchy-migrate— migration markersbin/omarchy-done— done marker helper
有了状态地图,接下来进入最主要的常驻消费者:07 · Quickshell 运行时。