一、起点归纳:我现在的实际状况
- 桌面:NixOS + Plasma 6.6.6。
Ctrl+Alt+Shift+Q(我口头说的 Ctrl+Shift+Alt+Q)绑的是 KDE 便签 plasmoid(kglobalshortcutsrc 里 activate widget 231 / 716),便签正文存 ~/.local/share/plasma_notes/,是自由文本 HTML。 - 便签的问题:没有完成态、没有截止时间、没有分组、不能跨端、不能定时提醒 → 记完就烂在文本里,只能"翻旧账"。
- 已有 Google Tasks 数据:账号已 OAuth 授权(token 在
~/.hermes/google_token.json),8 个清单:AI电脑手机 / 跬步 / 启城 / 雅阁 / 钱库 / 同学 / 同道 / 飞度。 - Google Tasks 的问题(本机实测):经代理单次 API 3–6 s、discovery 文档 11.6 s;官方无 Linux 客户端;视图只有列表;重复任务没有工作日/农历规则;提醒能力弱。
- 手机:Android,需要在桌面放小部件随时看待办。
- 服务器:自有云服务器,可跑 docker-compose;只接受 docker-compose.yml 这一种私有化方式。
- 取舍:可以接受私有化运维,但不能为它付太多;最高频的动作必须 0 摩擦(一次按键 → 弹窗 → 回车)。
二、目标与需求清单(R01–R17,逐条验收)
| 编号 | 需求 | 硬/软 | 判据(怎么算满足) |
| R01 | NixOS 桌面全局快捷键 Ctrl+Shift+Alt+Q 一键唤醒弹窗 | 硬 | 按键到输入框可打字 < 200 ms,不打开浏览器 |
| R02 | 弹窗内可"快速操作":记一条 / 勾完成 / 改期 | 硬 | 三个动作都不需要切窗口、不需要登录 |
| R03 | 桌面视图强大:日 / 周 / 月 / 年 | 硬 | 四种时间尺度都能一眼看完负载 |
| R04 | 数据管理强大:分组 / 项目 / 标签 / 子任务 / 搜索 | 硬 | 能把 8 个清单的结构无损迁过去并继续用 |
| R05 | 组件调用轻便灵活(可被脚本/CLI/API 直接调用) | 硬 | 有稳定 HTTP API 或 CLI,我能写一行脚本就落库 |
| R06 | Android 桌面小部件快速查看待办 | 硬 | 桌面直接看到未完成清单,不用点开 App |
| R07 | Android 端可完整操作(增删改 / 完成 / 看大描述) | 硬 | 手机上能处理,不用回桌面 |
| R08 | 农历(农历日期 / 农历重复,如生日、祭日) | 硬(当前无解) | 能按农历每月/每年重复,且能看农历日期 |
| R09 | 工作日规则(工作日重复、含调休认知) | 硬 | 能设"每周一~周五",调休需能手工覆盖 |
| R10 | 周期性任务(天 / 周 / 月 / 自定义间隔) | 硬 | RRULE 级别或等价的自然语言重复 |
| R11 | 一次性定时提醒(指定日期时刻通知) | 硬 | 到点有通知(手机或桌面),不依赖我盯着 |
| R12 | 标题 + 大篇幅描述 | 硬 | 描述能写几百字,支持换行/简单排版 |
| R13 | 分组(清单 / 项目 / 子任务层级) | 硬 | 至少两级结构 + 标签或筛选 |
| R14 | 多端同步(NixOS ↔ Android) | 硬 | 任一端改动,另一端口径一致,延迟可接受 |
| R15 | 已有 Google Tasks 数据可迁移或共存 | 硬 | 8 个清单的标题/描述/完成态都能过去 |
| R16 | 私有化只接受 docker-compose.yml | 硬 | 一条 docker compose up -d 能起全栈 |
| R17 | 运维成本可控(备份 / 升级 / 证书) | 软 | 不引入多个常驻组件,升级不破数据 |
符号约定:✅ 已核实满足;⚠️ 部分满足 / 需自建桥接 / 未复核;❌ 不满足;— 不适用。
三、方案总表(一行一个方案)
| 方案 | 许可 / 托管 | 服务端 compose | NixOS 桌面形态 | 桌面热键弹窗 | Android 小组件 | 视图(日周月年) | 农历 | 工作日 / 周期重复 | 定时提醒 | 标题 + 大描述 | 分组 | 多端同步 | Google Tasks 迁移 | 结论 |
| Google Tasks(现状基线) | 商业云 | ❌ 不可自建 | Chrome 应用窗口 + 我的 todo 脚本 | ✅ 已实测 32 ms 落盘(本地 outbox) | ✅ 官方 App 有小部件 | ❌ 只有列表 | ❌ | ⚠️ 只有简单重复,工作日要手选 | ⚠️ 弱(到期日 + 基础提醒) | ✅ | ⚠️ 清单 + 子任务,无标签 | ✅ | —(数据就在这) | 留作基线:采集已解决,视图/农历是硬缺口 |
| Vikunja | AGPL / 自托管 | ✅ 官方 docker 镜像 | Web / PWA(无官方 Linux 原生客户端:go-vikunja/desktop 已 archived) | ✅ 走 REST API,采集逻辑与现脚本一致 | ✅ 代码证据:android/.../widget/AppWidget.kt + res/xml/widget.xml | ⚠️ 列表 / 看板 / 甘特(表格、日历视图未复核) | ❌ | ✅ 周期(RepeatAfter + quickAddMagic 自然语言);⚠️ 工作日靠"每周 + 选星期" | ✅ 有提醒(ReminderDetail,邮件/桌面通知) | ✅ Markdown | ✅ 项目 / 标签 / 子任务 | ✅ | ⚠️ 有 CSV 导入,Google Tasks 需我写脚本走 API | 综合最匹配(自托管 + 双端 + 提醒 + 小部件) |
| Tasks.org + Radicale(CalDAV) | GPL / 自托管 | ✅ Radicale 极简 compose | 无官方 Linux 客户端;靠 KOrganizer / Evolution(Akonadi 原生) | ⚠️ 需自建 CalDAV PUT 脚本(可写) | ✅✅ 最成熟:仓库 33 个 widget 相关文件(org/tasks/widget/AppWidgetManager.kt) | ⚠️ 列表 + 日历视图(年视图未复核) | ❌ | ✅ RRULE 完整(含 BYDAY 工作日) | ✅ VALARM 本地闹钟 | ✅ | ✅ 列表 / 子任务 / 标签 | ✅ | ✅✅ 最干净:Google Tasks → ICS VTODO → 直接 PUT 进 Radicale | 安卓体验最强 + 迁移最省力;桌面原生度依赖 PIM 栈 |
| Nextcloud Tasks | AGPL / 自托管 | ✅(整套 Nextcloud 较重) | Web | ⚠️ 需自建 CalDAV 脚本 | — 无官方 App,靠 DAVx5 + Tasks.org | ❌ 列表 / 智能集合 | ❌ | ✅ CalDAV RRULE | ✅ VALARM | ✅ | ✅ | ✅ | ✅ ICS | 只有已在用 Nextcloud 才值得,否则 Radicale 更轻 |
| Tududi | 开源 / 自托管 | ✅ | Web / PWA | ⚠️ 需走其 API | — 无自有 App,靠 CalDAV + Tasks.org | ⚠️ 项目 / 列表视图 | ❌ | ✅ 强(日/周/月/每月某星期/月末/按完成日重复) | ⚠️ 有通知(remind 相关,细节未复核) | ✅ | ✅ 项目 / 任务 / 笔记 | ⚠️ CalDAV 双向 | ⚠️ | 轻量备选;手机能力外包给 Tasks.org |
| Donetick | 开源 / 自托管 | ✅ | Web / PWA | ⚠️ 需走其 API | ❌ 仓库 296 个文件里 widget 相关 0 个 | ❌ | ❌ | ✅ 按到期日/完成日重复 | ✅ 多平台通知(含 Android APK) | ✅ | ⚠️ 家务协同模型(家庭/成员) | ✅ | ❌ | 场景不匹配(家务/积分/打卡) |
| Super Productivity | MIT / 客户端 + 自建同步 | ⚠️ 仓库有 packages/super-sync-server,但它是"同步服务"不是"任务服务端" | Electron 原生客户端(Linux 有包) | ⚠️ 客户端内快捷键(全局弹窗未复核) | ⚠️ 未复核 | ⚠️ 今日 / 看板 / 时间盒(无月/年视图) | ❌ | ✅ 有重复 | ⚠️ | ✅ | ✅ | ✅ | ❌ | 唯一真差异 = 时间追踪/番茄钟;不是"服务端 + 多端"模型 |
| Focalboard | MIT·社区维护 | ✅ | Web + 桌面端 | ⚠️ | ⚠️ 未复核 | ❌ 看板模型 | ❌ | ❌ 无重复 | ❌ 无提醒 | ✅ | ✅ 看板/卡片 | ⚠️ | ❌ | 不选:看板思维 + 已移交 community / Mattermost 不再主推 |
| TickTick 滴答清单(商业对照) | 商业云(非自托管) | ❌ | Web / 第三方客户端(无官方 Linux 客户端) | ⚠️ 需自建 PWA 壳 | ✅ 成熟小部件 | ✅ 日 / 周 / 月 / 日历 / 清单 | ⚠️ 官方宣称支持农历重复,本次未取到页面证据(未复核) | ✅ 工作日重复 | ✅ 定时提醒 | ✅ | ✅ | ✅ | ⚠️ 有导入,细节未复核 | 功能最贴需求,但数据在商业云 → 与自托管目标冲突,只作对照 |
| Mindwtr | 开源 / 自托管 | ✅(另有第三方 nix flake) | 有桌面端 | ⚠️ | ⚠️ 未复核 | ⚠️ GTD 流程视图 | ❌ | ✅ 有重复 | ⚠️ | ✅ | ✅ GTD 语境/项目 | ✅ 自建云同步 | ❌ | GTD 专精,2294★;不如 Vikunja 通用 |
| Pomodoist | 开源 / 自托管 | ✅ | Web / PWA | ⚠️ | ⚠️ 未复核 | ❌ | ❌ | ⚠️ | ⚠️ | ✅ | ⚠️ | ⚠️ | ❌ | 番茄专精(542★),无采集/小部件增量 |
| nia-todo | 开源 / 自托管 | ✅ | Web / PWA | ⚠️ | ❌ | ❌ | ❌ | ⚠️ | ❌ | ✅ | ⚠️ | ⚠️ | ❌ | 仅 9★(2026-10 新建),太早期,不作候选 |
| HamsterBase | 开源 / 自托管 | ✅ | Web | — | — | — | — | — | — | — | — | — | — | 淘汰:官方定位是 "self-hosted, local-first web archive",不是任务应用 |
四、需求 × 方案覆盖矩阵(R01–R17)
只列四个真正可当选的方案 + 商业对照。每一行独立核对,不合并。
| 需求 | Google Tasks | Vikunja | Tasks.org + Radicale | Tududi | TickTick(对照) |
| R01 桌面热键弹窗 | ✅ 现有脚本 32 ms | ✅ 换 endpoint 即可 | ⚠️ 需写 CalDAV 脚本 | ⚠️ 需走 API | ⚠️ 只能 PWA 壳 |
| R02 弹窗内快速操作 | ✅ 记/勾完成已实现,改期待补 | ✅ 走 API 全支持 | ✅ PUT/PROPPATCH | ✅ | ⚠️ 无公开 API 承诺 |
| R03 日/周/月/年视图 | ❌ | ⚠️ 有甘特/看板,日历视图未复核 | ⚠️ 有日历视图,年视图未复核 | ⚠️ 列表为主 | ✅ |
| R04 数据管理(分组/标签/子任务) | ⚠️ 清单+子任务,无标签 | ✅ 项目/标签/子任务/筛选 | ✅ 列表/子任务/标签 | ✅ 项目/任务/笔记 | ✅ |
| R05 组件可调用(API/CLI) | ✅(本机已接) | ✅ REST API 完整 | ✅ CalDAV 标准协议 | ✅ API | ❌ 无公开 API |
| R06 Android 小部件 | ✅ | ✅ 代码证据 AppWidget.kt | ✅✅ 最成熟 | ❌(靠 Tasks.org) | ✅ |
| R07 Android 完整操作 | ✅ | ✅ 官方 App(613★) | ✅ | ⚠️ 靠 Tasks.org | ✅ |
| R08 农历 | ❌ | ❌ | ❌ | ❌ | ⚠️ 未复核 |
| R09 工作日规则 | ⚠️ 手选周一~周五 | ⚠️ 每周+选星期 | ✅ RRULE BYDAY | ✅ 可设每月某星期 | ✅ |
| R10 周期任务 | ⚠️ 简单重复 | ✅ 含自然语言 | ✅ RRULE | ✅ 含按完成日重复 | ✅ |
| R11 一次性定时提醒 | ⚠️ 弱 | ✅ 提醒组件 | ✅ VALARM 本地闹钟 | ⚠️ 细节未复核 | ✅ |
| R12 标题 + 大描述 | ✅ | ✅ Markdown | ✅ | ✅ | ✅ |
| R13 分组 | ⚠️ | ✅ | ✅ | ✅ | ✅ |
| R14 多端同步 | ✅ | ✅ | ✅ CalDAV | ⚠️ CalDAV 双向 | ✅ |
| R15 Google Tasks 迁移 | — | ⚠️ 需脚本/CSV | ✅✅ ICS VTODO 直灌 | ⚠️ | ⚠️ 未复核 |
| R16 只接受 compose | ❌ 不可自建 | ✅ | ✅ | ✅ | ❌ |
| R17 运维可控 | ✅ 零运维 | ⚠️ 1 容器 + 备份 | ⚠️ 1 容器 + 可选 PIM 栈 | ⚠️ 1 容器 | ✅ 零运维 |
五、一阶实施:tasks 窗口
- 方案:用 Google 官方网页,Chrome 应用窗口打开;
Ctrl+Alt+Shift+Q 一个键进,进去就是谷歌原生全功能界面(清单 / 子任务 / 描述 / 日期 / 完成 / 删除) - 持久化:
5.1 定稿形态
| 项 | 内容 |
| 快捷键 | 只占 Ctrl+Alt+Shift+Q → Chrome 应用窗口打开 https://tasks.google.com/(--app= 模式,无地址栏/标签栏) |
| 系统载体 | /etc/nixos/modules/desktop/office/chrome_ui_tasks.nix(office 域扩展)+ 桌面条目 hermes-todo-open.desktop(NoDisplay) |
| 命令行(无快捷键) | todo ls / add / refresh / sync / done / undo / due / list / web;todo web 等同按 Q |
| 数据 | 仍是自己的 Google 账号与 8 个清单,不迁移、不复制 |
5.2 全局快捷键能生效的两个必需条件(踩过两次)
- 桌面条目必须带
X-KDE-GlobalAccel-CommandShortcut=true:KDE 靠它识别"这条 .desktop 可当全局快捷键"。缺了 → 快捷键设置里看得见组件,但按键永不触发。 - kglobalshortcutsrc 的
_launch 必须写单值(如 _launch=Ctrl+Alt+Shift+Q):写成 KConfig 三段式(值,默认,友好名)会被 kglobalaccel 静默丢弃,配置里看得见、按键没反应。 - 验收判据(不用手按):
qdbus --literal org.kde.kglobalaccel /kglobalaccel org.kde.KGlobalAccel.getGlobalShortcutsByKey 234881105,应返回 _launch / 待办:Google Tasks / hermes-todo-open.desktop。键值编码 = (修饰键<<24)|Qt::Key,Ctrl+Alt+Shift = 0x0E,Q = 0x51。
5.3 单例:试过两版,已全部撤销
| 版本 | 做法 | 结果 |
| v1 | xdotool search --onlyvisible 找窗口 → 有则激活 | ❌ --onlyvisible 只返回当前桌面视口内的窗口,窗口在别的桌面/还没映射就找不到 ⇒ 照样叠窗 |
| v2 | 记窗口 XID 到状态文件,先验活再激活;失效则按标题认领;确实没有才启动并轮询抓 XID | ❌ 实测"按几次还是几个实例" |
| 现状 | 全部删除:todo-open 脚本、xdotool 依赖、状态文件、识别逻辑 | 按一次开一个,不再做任何窗口识别(接受这个行为) |
5.4 窗口大小:为什么每次都是半屏(已修)
- 现象:每次打开都是"半屏 + 高度锁死改不动",不认上次关闭的大小/位置。
- 取证:
xprop _NET_WM_STATE 显示 MAXIMIZED_VERT(垂直最大化 ⇒ 高度锁死);Chrome Preferences 里 browser.app_window_placement.tasks.google.com_/ 存的是老的半屏矩形;主 profile 加 --window-size/--window-position 被忽略;换成全新 --user-data-dir 启动则完全正常(900×700 生效)⇒ 不是 KWin,也不是参数问题;主进程还会用内存里的旧值把磁盘上新写的值覆盖回去。 - 解决:给这个窗口加 KWin 窗口规则「记住上次大小与位置」,声明式写在
/etc/nixos/modules/system/service/kwin-data/kwin-hotkey-router-rules.yml(positionrule=4 / sizerule=4,初始值 2020,1120 / 1400×1000,匹配 wmclass=Google-chrome + wmname=Tasks),rebuild 时合并进 ~/.config/kwinrulesrc 并即时重载 KWin。 - 实测:关窗重开后回到
1400×1000 @ (2020,1120),且不再带 MAXIMIZED_VERT。以后拖动窗口,KWin 按"记住"策略沿用新位置。
5.5 验收数据(本机实测)
| 项 | 结果 |
getGlobalShortcutsByKey 234881105 | 返回 _launch / 待办:Google Tasks / hermes-todo-open.desktop(W 键 234881111 返回空,未被占用) |
todo refresh | 8 个清单、29 项未完成(经代理约 6 s) |
todo ls | 「AI电脑手机」11 项,带截止日;读本地缓存秒回 |
todo add "xxx @明天" | 落盘后后台 sync 自动推到 Google(探针任务已清理) |
5.6 遗留 / 下一步
- 把 tasks.google.com 用 Chrome「安装页面为应用」装成真正的 PWA:有独立 app id 与窗口状态,可能同时解决单例与窗口记忆(未实测,值得一试)。
- R01/R02 的"按键 < 200 ms 就地录一条"目前由命令行
todo add 承担(无快捷键);若要快捷键快记,再单独分配一个键(不占用 W)。 - R03 视图、R08 农历、R09 调休、R11 定时提醒:Google Tasks 侧无解,留给二阶(自托管 CalDAV / Vikunja)。