通知汇总与日报

把一台机器收到的每一条通知实时抄进本地库,每天汇成一页「这一天发生了什么」。 它不提醒你 —— 它是给你回头看的。

这是可操作的演示:下面这一天的 29 条通知全是编的,人名、号码、内容都不对应任何真人真事,随便点。 真实系统跑在一台 Mac 上,库里是真实聊天正文,那台机器之外谁也拿不到(见第 3 节)。 本页不向任何服务器发送数据,改动只存在你自己的浏览器里。

1 · 这套系统解决什么问题

你每天被几十上百条通知划过屏幕。三天后想不起来「周四下午到底跟谁定了什么」—— 翻聊天记录要一个 app 一个 app 翻,而且那条你当时没点开的通知已经不存在了

系统没有通知历史库 macOS 的通知中心只存「你还没点掉的那些」,点一下就消失。要能回查,只能在通知到达的那一刻抄走 —— 这就是为什么必须有一个常驻进程,而不是每天跑一次的脚本。
一天七十条流水看不出发生了什么 同一个人十分钟里发六条,在流水里是六行,在你脑子里是一件事。所以入库是逐条,展示按「同一个人 15 分钟内连续消息并成一段」,一天七十条塌成十几件事。
同一条通知会来两遍 手机转发过来的和电脑上原生弹的是同一条,但 bundle id 不同(iOS 一个、macOS 一个)。不归一化就会双份入库,日报里每件事都说两遍。
噪音和正事混在一起 脚本巡检、构建结果、营销短信照样入库(漏了就再也补不回来),但默认在视图里折叠,一键可以放回来。「入库」和「展示」是两个判断,别混成一个。
验证码是唯一需要即时性的 只有它有一条静默动作:识别到就进剪贴板,不弹窗、不推送。其余一律只记录。会打扰你的功能被整段删掉了 —— 那是这个工具存在理由的反面。
通知正文 = 聊天内容 这是整个系统最敏感的地方,也决定了它的形状:库不出本机,只有日报页离开这台机器(第 3 节详述)。

下面演示里跑的合并、去重、折叠、验证码抽取,都是真实系统里那几段规则,不是画的。

2 · 亲手点一点

合成的一天 · 2026-08-14(周五)
来源
时间
合并 同一个人间隔 ≤ 15 分钟并成一段(真实默认 15)
开关
随手记

3 · 为什么只有日报上传,原始库一步不出本机

通知正文里有微信聊天、短信、邮件主题。这一条决定了整个系统的形状 —— 不是先做系统再补隐私,是隐私先定形状

本机 · 采集常驻进程守着系统通知库,到达即抄。进程空闲 0% CPU、约 12 MB 内存
本机 · SQLite权限 0600,不进任何 git 仓库,不同步、不备份到云。这是全系统唯一存正文的地方
本机 · 出静态 HTML每小时生成一次日报页。页面上的内容是正文的摘要与时间线,不是数据库
→ rsync →
服务器 · 只放静态件没有数据库、没有生成逻辑、没有 API 能查历史。站点在密码闸后,且 noindex
为什么不上传库 服务器上放一份聊天正文,风险面是永久的(快照、备份、镜像、任何一次配置失误)。而收益只是「换台机器也能查」—— 这个收益远配不上那个代价,所以直接不做。
为什么服务器不跑生成逻辑 只要服务器要生成日报,它就得能读库。纯静态件是唯一能让服务器「无从泄露」的形态 —— 它手里根本没有原始数据。
为什么用 rsync 而不是接口推送 方向是单向的:本机推、服务器收。服务器没有任何一条能反向拉本机数据的路径。--delete 让过了保留期的旧页在站上也一起消失,避免「本机已抹除、站上还留着」。
保留期怎么处理 超过保留期只抹标题/正文/副标题,保留元数据 —— 长周期的「谁最常找我、几点最吵」这类统计照样能算,正文却已经不在了。
那条摘要是谁写的 日报正文由大模型总结,这意味着当天通知正文会发给它。不接受就一个开关关掉,采集和时间线照常 —— 但要说在前面,不能藏。走的是本机已有的订阅通道,不经第三方 API key。
怎么防它编 抽出来的每一条时间节点必须带原文片段,这是硬要求。带了片段,「它是不是编的」当场能核 —— 核不上的宁可不抽。

上面演示里的日报排序是确定性打分(规则写在日报面板里), 不调用任何模型 —— 本页零外部请求。真实系统的摘要文字才是模型写的。

4 · 技术上怎么做的

为什么必须常驻 文件系统事件(FSEvents / launchd WatchPaths)对系统通知库的容器实测 0 次上报;换成 kqueue(进程持 fd 阻塞在内核事件上)实测 10/10 唤醒、延迟 1–5 秒。「零常驻」和「覆盖到微信这类 app」互斥,这是量出来的,不是取舍偏好。
四个采集源 系统通知库(覆盖本机所有 app)、手机转发的推送归档、短信库、邮件原始文件。四个源产出同一个归一化事件结构,去重和展示只认这个结构。
去重 键 = SHA-256(归一化 bundle | 标题 | 正文 | 60 秒桶),写库时 INSERT OR IGNORE。iOS 与 macOS 的两个 bundle id 先映射到同一个规范名,否则等于没去重。
合并成「事」 同一 app + 同一发信人 + 间隔 ≤ 15 分钟 → 并成一段。合并只发生在展示层,库里永远是逐条 —— 合并规则以后要改,历史数据不用动。
「你当时没看见」这一位 判据不靠猜:通知还在系统队列里 = 你没点掉它。纯读元数据,不因此提醒你。复盘时这一位最有价值 —— 它标出的正是你漏掉的那几条。
一天怎么划 只认这台机器的系统时区,不认 TZ 环境变量。踩过:这台机器的 TZ 表示「人在哪」而不是时间口径,两把尺子各走各的,结果站上每个「日期」装的其实是「昨天下午到今天下午」,而页面看起来完全正常。现在程序侧和数据库侧共用同一把尺子,且代码里不写任何时区名字面量
全文检索 SQLite FTS5 + trigram 分词(中文可搜)。坑:trigram 对 < 3 字符的查询永远返回空且不报错 —— 短查询自动降级模糊匹配,并把降级这件事打印出来,不静默假装检索还在。
自反馈环闸门 实测事故:弹一条「验证码已复制 ××××××」→ 这条通知自己被采集 → 又命中验证码规则 → 再弹,12 秒滚三代。时间桶去重挡不住(每代桶不同)。解法是弹之前把内容哈希落库登记,采集时命中即跳过 —— 落库不放内存,因为进程重启后那条还没被消费的通知仍会被采到。
模型输出的容错 模型漏右方括号是稳定复现不是偶发(同一输入连试三次同样畸形)。所以严格解析失败后过一遍括号修补:扫描时维护容器栈,只补收尾符号、绝不猜内容,修不动就照常报错。不用「重试一次」当解法 —— 同样的输入给同样的畸形,重试只是把同一个错再烧一遍。
网页按钮怎么够到本机 日报是静态件,浏览器点一下没法调本机命令。自定义 URL scheme 是错的方向(在手机上是死的)。走队列:网页只下单 → 本机每分钟领单执行 → 回写状态。并且退出码 0 ≠ 真做成了,只认真正成功那一路打出的标记,否则会出现「页面全绿、实际一条没加」的空转。
回归测试 66 条自检覆盖规则匹配、去重、保留期、自反馈环闸门、时间解析、划天口径、幂等、系统集成传参。每一条都对应一次真事故 —— 拆掉哪道闸就红哪几条,反向验证过
演示数据全部合成,仅存在于你的浏览器(localStorage)。本页不向任何服务器发送数据,也不加载任何外部资源。