首页
/ Omarchy 崩溃诊断实战:基于 systemd-coredump 的证据链、符号化与 AI 技能化归因

Omarchy 崩溃诊断实战:基于 systemd-coredump 的证据链、符号化与 AI 技能化归因

2026-09-05 16:15:44作者:田桥桑Industrious

Omarchy 将“崩溃为什么发生”这件事做成了一个可复用、可执行、可被 AI Agent 直接遵循的技能:default/agents/skills/diagnose-crash/SKILL.md 定义了从 coredumpctl 取证、排除资源耗尽、时间线关联、core dump 符号化,到最终撰写归因报告与静音通知的完整方法论。读完本文,你将掌握在 Omarchy(Arch Linux 之上的配置层)上排查 segfault / SIGABRT / OOM 类崩溃的标准流程,并理解其背后 omarchy-crash-watch 通知管线与 omarchy crash mute 静音机制的实现细节。

1. 这套“崩溃诊断”在 Omarchy 中是什么

diagnose-crash 不是人读的运维手册,而是给编码 Agent(编码代理)执行的方法论文件,由 YAML frontmatter 声明触发条件:

name: diagnose-crash
description: >
  Diagnose why a program crashed on this machine, from a systemd-coredump core dump.
  Use when a process has segfaulted, aborted, or otherwise dumped core, ...
  Triggers: crash, segfault, SIGSEGV, SIGABRT, core dump, coredumpctl,
  "why did X crash", "X keeps crashing", backtrace symbolization.

(见 SKILL.md

它有两个入口,都最终汇聚到同一份方法论:

  1. 通知入口omarchy-crash-watch 守护进程监听 systemd-coredump 的 journal 事件,进程崩溃后弹出 "Process crashed:" 通知,点击即调用 omarchy agent crash <pid>
  2. 手动入口:对 coredumpctl list 中的任意 PID 直接运行 omarchy agent crash <pid>

bin/omarchy-agent-crash 负责“收集事实 + 指向技能”:它校验 PID 为纯数字,用 coredumpctl list "$pid" 补一个时间戳,然后把 process / PID / binary / signal / time 五要素拼成一段 prompt,exec omarchy-agent --prompt "$prompt" 交给默认 Agent 执行。其注释明确说明设计意图:“方法论住在 diagnose-crash 技能里,这样只需在一处编辑,且对任何默认 Agent 都有效;本脚本只负责采集事实并指向技能”。

官方手册 manual/17-ai.md 对这套机制的表述是:watching 默认开启,可在 Trigger > Toggle > Crash Capture(等价于 omarchy toggle crash-capture)整体关闭,关闭后手动入口仍然可用。

2. 诊断方法论:从证据出发,而不是编一个像样的故事

技能开篇的总原则只有两句话:“Work from evidence. The goal is an honest account of what happened, not a plausible-sounding story.”(基于证据工作;目标是诚实地交代发生了什么,而不是讲一个听起来合理的故事。)以下逐节展开其要求。

2.1 确立事实:coredumpctl 是起点

  • coredumpctl info <pid> 是第一个要跑的命令。除了调用栈(backtrace),必须注意进程的命令行(command line)——它通常揭示了程序死亡时在做什么,而“它在做什么”往往就是全部答案。
  • coredumpctl list 用于判断这次崩溃是孤立事件还是模式。同一个程序反复崩溃、或多个程序同时死亡,指向的方向与单次失败完全不同(例如系统级资源问题而非某程序缺陷)。

2.2 先排除“无聊的原因”

技能要求在指责程序之前先检查资源耗尽

free -h        # 内存是否见底
# 再到 journal 中查 OOM kill 记录

核心结论:被 OOM killer 杀掉的进程不是该进程的 bug。这是整篇方法论中优先级最高的排除项。

2.3 与时间线关联:最被低估的证据

崩溃时间戳要与三类外部证据对照:

  • 文件系统 mtime:某个目录或文件的 mtime 与崩溃落在同一秒,强烈暗示它就是触发源;
  • journal:崩溃时刻前后、来自同进程或相邻进程的相关告警;
  • 近期软件包更新:崩溃恰好始于一次更新之后,矛头就指向该更新。

2.4 读整个 core,而不只是 frame 0

崩溃线程之外的线程栈展示了哪些工作正在进行中(in flight)——缩略图生成器(thumbnailer)、图像加载器、IPC 读取器、GPU 队列等。这种上下文常常能在崩溃帧本身无法符号化时解释触发原因。

同时记录地址空间中的第三方代码:文件管理器或浏览器扩展、插件、树外驱动。进程内第三方代码是常见的崩溃来源,值得标记——但没有证据表明它被牵连时,不得把锅钉死在它头上。

2.5 能符号化就符号化:Arch 的 debuginfod 公开服务器

Omarchy 基于 Arch Linux,而 Arch 运行着公开的 debuginfod 服务器。技能给出的完整符号化流程:

core=$(mktemp -t crash-XXXXXX.core)
trap 'rm -f "$core"' EXIT
coredumpctl dump <pid> --output="$core"
DEBUGINFOD_URLS="https://debuginfod.archlinux.org" \
  gdb -q <executable> "$core" \
  -batch -ex 'set debuginfod enabled on' -ex 'bt'

这段命令有三个值得注意的工程细节:

  1. mktemp + trap ... EXIT:core dump 是进程内存的逐字节拷贝,可能包含口令、token 与私密文档。写入全新的临时路径而非可预测的共享路径,并在退出时自动删除——绝不留在 /tmp 过夜。
  2. DEBUGINFOD_URLS 环境变量:让 GDB 在线从 Arch 的 debuginfod 拉取调试信息,无需本地安装 debug 包。
  3. -batch -ex 'bt':非交互模式,只取回溯,适合脚本化。

技能同时强调了诚实边界:很多包不发布调试符号,帧无法解析时就要明说,绝不允许编造函数名来填空。即使无法符号化,堆栈仍有“形状”:每帧属于哪个库、崩溃来自信号处理器 / 主循环 / 工作线程中的哪一层,这些仍可陈述。

2.6 报告四要素与“系统原样离开”

诊断完成后,报告必须回答四点:

  1. 什么东西崩溃了,崩溃时它在做什么;
  2. 最可能的机制——明确区分证据“证明”了什么与你在“推断”什么
  3. 是否有用户数据丢失,以及从哪里可恢复——在下结论之前先检查回收站;
  4. 是否可能复发,以及什么能避免或修复它。

如果原因确实含糊,就说含糊,不要用猜测拼凑出自信的语气。

技能还立了一条硬约束:“Leave the system as you found it.”(把系统留成你发现它的样子。)诊断只读,不修复、不清理、不重配置。唯一需要清理的是自己产生的东西——即上面抽取出来的 core 副本;诊断唯一允许做的“变更”是用户主动要求时的那次静音(mute)。

3. 静音机制:omarchy crash mute 的语义与实现

诊断解释了崩溃,但崩溃可能继续发生。技能的收尾动作是主动提议为该程序单独关闭通知——且绝不允许 Agent 未经请求就执行静音,并要在同一句话里说明如何恢复,避免成为单行道:

omarchy-crash-mute '<program>'        # 静音
omarchy-crash-mute '<program>' off    # 恢复通知
omarchy-crash-mute                    # 列出当前静音了谁

bin/omarchy-crash-mute 的实现印证了技能中的三条告诫:

  • 名称归约program=${program##*/} 把传入的二进制路径(如 /usr/bin/hyprland)归约为 basename,与 watcher 读取的键保持一致;
  • 注入防护:拒绝空名、...、纯路径成分,防止静音标记写到 crash-ignore/ 目录之外;
  • 真实状态回报:执行 omarchy-toggle "crash-ignore/$program" 后再用 omarchy-toggle-enabled 复查,报告的是“现在真实如此”而非“你要求如此”;
  • 状态落盘为每程序一个标记文件:$HOME/.local/state/omarchy/toggles/crash-ignore/<program>readonly MUTES=...),每程序一个文件而非一份列表,是为了让取消某一个时无需读改写并重新解析其余条目。

技能中针对静音的三个陷阱,均可在源码或测试中找到对应:

陷阱 技能告诫 仓库佐证
传截断名 进程名被截断到 15 字符,而 basename 不会;用截断名静音将“看起来生效”却永远匹配不到 omarchy-crash-watch 注释 “comm is truncated to 15 characters, so prefer the executable's basename”
不引用 程序名里一个单引号会闭合你的引号并把剩余部分当 shell 执行 crash-capture-test.sh 对路径穿越、-h 等边界名的成组断言
解释器前缀 键是裸名,经解释器运行的程序以解释器为键——静音 python3.13 会静音本机所有 Python 程序,必须明说 测试 “a mute that could not be written is not reported as one” 等对语义边界的覆盖

另外两点整体性说明:对全部程序(而非某一个)的开关在 Trigger > Toggle > Crash Capture;而且“用静音替代本可达成的修复”本身就是错误答案。

4. 底层管线:omarchy-crash-watch 如何把崩溃变成通知

bin/omarchy-crash-watch 是通知侧的完整实现,读懂它能验证技能所依赖的每一条“事实”从哪来:

  • 事件源journalctl -f -n 0 -o json "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"——systemd-coredump 用固定 MESSAGE_ID 在 journal 中记录每个 core dump,携带结构化的 COREDUMP_* 字段(比文件名信息更多);-n 0 保证重启不会重复播报已处理的崩溃。
  • 字段解析防坑jq 把空字段与缺失字段统一替换为 -,再按制表符切出 uid/comm/pid/exe/signal——注释指出 tab 是 IFS 空白,空字段会折叠导致后续字段整体错位,曾有进程自设空 comm 导致崩溃被误读为别的进程而被丢弃。
  • 安全过滤链:只播报当前用户(uid == UID)的崩溃;名字归约后必须是单一成分(防止 prctl 伪造含斜杠的 comm 把静音标记写到目录外);omarchy-crash-* / omarchy-agent-* 自身永不播报;OMARCHY_CRASH_IGNORE 可扩展正则黑名单。
  • 去重窗口:每个程序在 OMARCHY_CRASH_DEDUPE_SECONDS(默认 60 秒)内至多播报一次,防止崩溃循环刷屏;且只有成功送达的通知才启动窗口,发送失败不会抑制后续一分钟的循环。
  • shell 崩溃的投递补偿:通知服务器(org.freedesktop.Notifications)由 shell 持有,shell 自己崩溃时 toast 无处可送——watcher 会等重启后的 shell 重新认领 D-Bus 名称再发送,因为“最难送达的崩溃恰恰最值得报告”。
  • 点击动作--exec omarchy-agent-crash "$pid" "$comm" "$exe" "$signal",崩溃详情作为独立的 argv 词传递,恶意进程名无法被重新解析为命令。

5. 何时这是 Omarchy 的 bug:上报边界

技能末节把“向 Omarchy 上游报告”收窄为少数情形,细节写在同目录的 reporting.md

  • 责任域判定:Omarchy 是 Arch Linux 之上的配置层,第三方应用(文件管理器、浏览器、GNOME/Qt 库)内部的崩溃几乎总是那个项目的上游 bug。Omarchy 的控制域大致是:omarchy-* 命令、Quickshell shell 及其插件、随附的 Hyprland 与终端配置、主题、安装与迁移脚本,以及它对所装之物的打包与配置方式。“Omarchy 只是安装了一个程序”不构成 Omarchy bug,除非 Omarchy 自身的打包或配置被牵连。
  • 三条件缺一不可:是 Omarchy 责任域内、有证据验证的 bug;用户已明确同意(先展示确切的标题与正文并等待确认,绝不代用户提交);机器具备提交能力(gh auth status 必须通过;gh 缺失或未认证时,把写好的文本交给用户自行提交,不代为安装或认证)。
  • 先搜后报:按崩溃程序、信号、回溯中的特征符号(而非你即将写的标题措辞)搜索,且要包含 closed issue——已按 fixed 关闭但当前系统仍复现的,是回归,比再开一个重复 issue 更有价值。
  • 签名:issue 或评论结尾署明产生它的模型与 agent harness,让人类读者知道这是机器撰写的内容。

6. 上手路径与验证

  • 查看方法论全文:default/agents/skills/diagnose-crash/SKILL.md;上游报告流程见 reporting.md
  • 实际排查:coredumpctl list 找到 PID → coredumpctl info <pid> → 按 2.2–2.5 节取证 → omarchy agent crash <pid> 让默认 Agent 走完整技能。
  • 行为回归验证:test/shell.d/crash-capture-test.sh 用 fixture 驱动 omarchy-crash-watchomarchy-crash-mute 全链路,断言涵盖:路径归约到与 watcher 相同的键、off 可撤销(“不是单行道”)、重复静音不反转为恢复、点号名可见可撤销、拒绝越界写入与未知 action、-- 可静音名为 -h 的程序、toggle 双向翻转、只统计 watcher 真正承认的常规文件标记,以及“技能文本必须仍写明静音命令”这类跨文件一致性检查。
  • 相关文档:manual/17-ai.md(AI 章节,含手动运行与静音说明)、manual/13-toggles-idle-screensaver.md(Crash Capture 开关表项)。

适用前提与限制:符号化依赖 Arch 公开 debuginfod 与目标包发布调试符号,帧无法解析属预期现象而非流程失败;整套通知管线只在已选择默认 Agent 时投递(watcher 逐条检查 omarchy-default-agent),且仅覆盖当前用户的崩溃;core dump 含敏感数据,临时文件必须即用即删。

登录后查看全文
热门项目推荐
相关项目推荐