1. 工具过载时代,为什么我还想试试“穴居人”风格的待办工具
1.1 复杂工具带来的隐性成本
我先说一个自己经历过的场景。有一阵子我为了“好好管理任务”,手机里装了三款待办应用,电脑上还配了一个带标签体系的桌面客户端。刚开始确实新鲜,又是设颜色又是分项目,感觉自己的工作效率马上就要起飞了。结果两周之后,我发现自己每天花在“整理任务清单”上的时间比“处理具体任务”还多——同步冲突要处理,标签体系越分越乱,各个平台的通知来回轰炸。最讽刺的是,我列了一堆“整理待办工具”的任务,它们就那样躺在清单里,和真正重要的事情混在一起,然后一起过期。
这就是复杂工具的隐性成本:它把自己的维护成本悄悄转移给了你,而你误以为那种“忙碌感”就是生产力。caveman 这个项目正是在这个背景下进入我视野的。它自称“穴居人”,一共就三个命令,数据存在本地一个 JSON 文件里,没有账号、没有同步、没有插件市场。第一眼看到它时我心想:这也太简陋了。但用了三周之后,我反而把手机上的几个待办应用全删了。
这篇文章就围绕 caveman 展开。我会讲它到底用什么思路做到了“简单到像穴居人”,怎么把它接入真实工作流,实际使用中会遇到哪些坑,以及它留给我的一些工具选型上的思考。如果你是那种被重型软件折磨过、想找一个零负担任务记录方案的开发者,或者你自己也有做一个小工具的想法,这篇应该能给你一点参考。
1.2 caveman 对“简单”的定义
先说清楚:caveman 的简单不是“还没开发完”的简单,而是“故意不做”的简单。这一点很容易被误会,因为它作为一个开源项目,功能少得不像话——没有优先级,没有截止日期,没有提醒,没有子任务,没有云同步。你甚至不能给任务打标签。但它从一开始就把自己定位成“一块石头”——穴居人拿石头砸坚果,不需要理解齿轮传动,也不需要充电。
所以它的核心逻辑被压到了最低限度:记录一句话,查看一句话,标记一件事干完了。仅此而已。这种取舍背后其实是一种很明确的姿态:待办工具的本质价值不是帮你建立一套宏大体系,而是让你“把脑子里的事情腾出来”。你在终端里敲一行字,它就记住了;你不需要打开 App、跨过各种启动页、处理各种弹窗,只需要一个命令。如果你愿意,你甚至可以把它当成一个带换行的便签文件来用。
我特别欣赏它对“数据”的态度。很多工具把数据锁在自己的生态里,导出要会员,迁移要折腾。caveman 不一样,它的全部数据就是一个人类可读的 JSON 文件,安安静静躺在你的用户目录下。这意味着你能看见它、能备份它、能用任意脚本操作它,甚至哪天整个工具不维护了,你的数据也还是你的。这种“看得见摸得着”的安全感,恰恰是现代软件最稀缺的东西。
2. caveman的存储与命令设计:一个JSON文件承载全部逻辑
2.1 存储机制解析
caveman 把数据存成一个 JSON 文件,默认路径是用户主目录下的~/.caveman.json。第一次运行工具时它会自动创建这个文件,之后每次执行命令,都是对这个文件的读取和重写。这里的核心逻辑非常简单:一个数组装着所有待办条目,每条记录有一个自增的 id、一段任务文本、以及一个标记是否完成的状态字段。
一个典型的存储结构长这样:
{ "nextId": 5, "items": [ { "id": 1, "text": "写季度总结", "done": false }, { "id": 2, "text": "预定下周的会议室", "done": true }, { "id": 3, "text": "给路由器换个位置", "done": false } ] }nextId负责保证新任务的编号不会重复,items就是任务主体。每次执行操作后,整个结构会被完整写回文件。这种全量读全量写的模式在任务量不大的场景下根本没有性能问题,反而极大降低了实现复杂度——不用考虑增量同步、不用维护索引、不用加锁,挂了一个文件就能跑。
为什么选 JSON 而不是 SQLite 或者更复杂的存储方案?我的理解是,作者从一开始就抛弃了“扩展丰富性”这个目标,换取“人可以直接读懂和修改”。SQLite 需要专门的客户端工具才能查看,而 JSON 用任何编辑器打开就能看懂,甚至能直接手改。这一点对极简工具来说太重要了:它意味着即使工具本身挂了,你也能无损取回所有数据。我自己就干过直接用 sed 替换文本、批量修改一批任务状态的事情,这种掌控感是重型应用给不了的。
2.2 三个命令的语义与边界
caveman 的全部功能就是三个动作:add、list、done。我把它们拆开看:
caveman add "任务描述":追加一条新任务,系统自动分配一个 id。这是唯一入口,没有富文本、没有分类选项。caveman list:展示所有任务及其编号和完成状态。有的版本默认展示未完成任务,也有的版本全部展示;不同分支行为略有差异,但核心都是“让你一眼看到现在还剩什么”。caveman done <id>:根据编号把对应任务标记为已完成。完成之后任务不会消失,它还在那个 JSON 数组里,只是done从 false 变成 true。
这组设计最有趣的地方在于它的“边界感”。它刻意不去做的事:没有“删除”命令,因为作者认为标记完成就够了,真错了文本里还留着痕迹;没有“修改”命令,因为如果输错了,你可以直接去编辑 JSON 文件。这种取舍乍看反直觉——用户连基本的编辑能力都没有?但用久了你会发现,绝大多数任务管理的需求其实就是“记下来、看一眼、划掉”,其余都是附带动作。少一条命令,就少一分学习成本,也少一个出错的地方。
2.3 从源码构建与安装
caveman 用 Go 编写,这本身就非常符合它的气质的:编译出来是一个单一二进制文件,丢到 PATH 里就能用,没有任何运行时依赖。安装方式特别省事。如果你本地有 Go 环境,直接编译:
git clone <caveman的仓库地址> cd caveman go build -o caveman . sudo mv caveman /usr/local/bin/没有 Go 环境的话,也可以从仓库的 Release 页面直接下载对应平台的二进制文件。更离谱的玩法是——因为它逻辑太简单,就算哪天仓库没了,你照着上面的 JSON 结构自己用 Python 或者 Shell 写一个等价脚本,也花不了半小时。这大概是极简设计能带来的最奢侈的副产品:随时可以抛弃原版,自己做一份。
安装完之后,第一件事就是跑一下caveman list,确保它能自动创建配置文件。这一步验证的是权限和路径有没有问题,如果当前用户对主目录有写权限,基本不会出岔子。
3. 从装好到用顺:终端里的完整接入过程
3.1 一个真实工作日的操作演示
光说设计理念不如直接演示一遍。我把自己某天早上的实际流程还原一下,每一步都在终端里敲,你和我之间的工具使用方式应该是一样的。
早上九点半到工位,先看一眼今天要做什么:
caveman list如果昨天已经加过一批任务,这里会把未完成和一个简单的序号一起打出来。然后开始干活,中途接到新需求,随手记一笔:
caveman add "整理接口文档,下午三点前发给后端" caveman add "报销发票:两张高铁票" caveman add "联系印刷厂确认样品进度"每加一条,心里就少了一件需要记挂着的事。到中午吃完饭,第一批任务处理完了,回头把对应编号划掉:
caveman done 3 caveman done 1再执行一次caveman list,剩下的就是还没解决的。整个过程行云流水,打开终端到退出可能只花了十秒钟。它不会弹一个“今日达成率”,也不会给你推送什么高分报告,但完成了就是完成了,那种踏实感比花里胡哨的统计有用得多。
对我来说,这个工具最舒服的地方在于它不打断思路。你在终端里写代码时,本身就是那种“命令行会话”的语境,随手敲一条任务比切到一个图形化应用、等它启动、再找一个输入框要自然得多。caveman 就像一个一直蹲在你 shell 旁边的洞穴伙伴,你喊一声,它回应一声,仅此而已。
3.2 用alias和shell函数补齐体验
官方的几个命令比较精简,但日常使用中,我还是给它加了一层自己的“壳”。毕竟工具可以极简,我自己的操作体验不用跟着极简到生硬。
首先最基础的是起个别名,把命令缩短到几乎和白板笔一样快:
alias c="caveman" alias ct="caveman add" alias cl="caveman list" alias cd="caveman done"这样一来,记一条新任务就是:
ct "给客户回电话确认地址"查看清单就是cl,比敲完整命令省了一半时间。还有更进一步的做法,比如在 zsh 里定义一个函数,带个时间戳再取其中关键字:
function cag() { caveman add "$(date '+%m-%d %H:%M') $*" }这样每次新增的任务会自带一个时间字段,你回头翻 JSON 时能知道它是什么时候加进去的。虽然工具有意不做“日期”概念,但你在外面包一层就能轻松补上,这就是所有文本化记录工具的通用优势——一切可以靠外部组合来完成。
我自己的 zsh 配置里还加了一条“今日总览”的捷径,其实就是用一个函数包装两次调用:
function ctoday() { echo "==== 待办 ====" caveman list echo "==== 已完成 ====" cat ~/.caveman.json | jq -r '.items[] | select(.done==true) | "\(.id) \(.text)"' }这里调用了jq来手工解析 JSON,属于我个人的补充操作。它做不了什么“智能”,但足够让一个极简工具的观感更接近“现代任务面板”。
3.3 数据备份与多设备间的“人工同步”
讲到多设备,这是很多人一听“本地存储”就会皱眉的地方:家里一台电脑,公司一台电脑,怎么办?如果你期待无缝云同步,那 caveman 确实不是给你的。但换个思路看,它反而更忠实——文件就那一个,任何现成的文件同步方案都能套上去,完全不存在厂商锁死的问题。
我自己的处理方式是把它放进一个私有 Git 仓库,两台机器各自克隆,每天下班前git add .caveman.json && git commit -m "sync",第二天到公司先git pull。如果哪天忘了,也没关系,最多就是在某台机器上冒出来一条老任务,顺手标记完成就好。用过复杂同步工具的人都知道,真正麻烦的是“冲突处理”和“多端状态不一致”,而 caveman 几乎没有这个烦恼:因为数据太简单了,即便发生覆盖,从旧备份里恢复也异常容易。
如果你不想用 Git,把它放到坚果云、Dropbox 这类同步文件夹里也行。逻辑完全一样——云端只是负责搬运文件,数据处理权力始终在你手里。所以每次有人问“这种工具没有云同步是不是落后”,我心里都在想:依赖厂商的同步才叫落后,一个随时可以手动复制的 JSON 文件才是永恒的兼容。
4. 实际使用中绕不开的坑与补救方案
4.1 文件损坏时的恢复经验
极简工具的一个隐含代价是:它不会为你做太多保护措施。JSON 文件如果被写坏,工具可能直接罢工,甚至静默丢失部分内容。这事我遇到过一回:当时我一边开着编辑器改~/.caveman.json,一边在另一个终端里执行caveman add,两边同时写,结果格式冲突,整个文件损坏到无法解析。caveman list直接报错。
这种情况下千万不要慌乱,第一个原则永远是“先备份,再动手”。如果你平时没有做备份的习惯,那么当下最紧要的是把损坏文件复制一份出来再尝试修复:
cp ~/.caveman.json ~/.caveman.json.bak cat ~/.caveman.json打开看之后大概率能发现问题,常见的是逗号缺失、引号不成对、或者文件尾部被截断。修复手段很直接:用jq验证,然后手工补齐。对于 JSON 这种格式,只要结构没碎到离谱,靠肉眼和数据片段就能恢复大半。如果文件已经彻底乱掉,那就只能以.bak或者之前的 Git 提交版本为准,损失一小段任务记录换一个教训——以后任何对文件的直接编辑,都先开一个临时副本。
经过这次事件,我给自己定了一个规则:所有对 JSON 的手动修改都先复制成带后缀的备份文件,改完确认工具读通了再删。这也是我反复建议任何使用文本存储工具的朋友应该做的一步。
4.2 并发写入与多窗口冲突
caveman 的写入模式是“读出所有内容,改完再整个写入同一个文件”。这种模式在单用户单进程场景下没有问题,但你要是同时打开两个终端窗口,各自执行一条caveman add,后写入的那个进程可能把前一个进程的修改覆盖掉。这类问题的本质是“你没法同时维持两份对同一文件的修改”,它是几乎所有轻量文件型存储工具的共性毛病,并不只是 caveman 的问题。
我的应对方案其实很简单:养成“在一个窗口里集中操作”的习惯。反正一次会话中新增任务的频率没有那么高,真需要搞“并发”,就写个 Shell 层面的简单串行包装,或者干脆直接向文件追加——因为 JSON 数组的写法是[ {"id":1,...}, {"id":2,...} ],如果只是追加新元素,你可以先把右括号前的]替换成, {...}],这个操作只要脚本写得严谨就不会破坏前面内容。
不过说实话,普通使用场景完全不需要做到这一步。我自己三周用下来,真正因为并发丢失数据的只有上述那一次手动修改,其他时候从没出过问题。它毕竟不是一个多人在线的协作系统,你把它当成“个人备忘录”来理解,就不会觉得这是缺陷。
4.3 缺失功能用外部管线补齐
caveman 没有提醒、没有统计、没有优先级。这些在很多用户眼里是不可接受的“缺陷”,但换个角度看,它们都是可以在工具外面补回来的功能。Unix 那句“每个程序只做好一件事”的理念在这里体现得淋漓尽致:caveman 负责存储和展示,至于提醒,交给 cron;至于统计,交给 wc 和 grep;至于“今日重点”,交给管道和过滤。
举一个实际例子。我想要每天早上九点自动看到任务清单,就在 crontab 里加了一行:
0 9 * * * caveman list > /tmp/today.txt; head -5 /tmp/today.txt | mail -s "今日待办" my@email.com在 Linux 桌面环境还可以直接弹系统通知,用notify-send也一样。想要统计“完成了多少任务”,一行命令就能得到数字:
cat ~/.caveman.json | jq '[.items[] | select(.done==true)] | length'如果敢于折腾,你甚至能把这个 JSON 文件喂给一个简单的网页脚本,实现一个完全私有、完全自制的“可视化看板”。这个思路比要求 caveman 长出各种插件功能要聪明得多——它不背负担,你还拿了全部自由度,真正的双赢。
5. 极简工具的价值边界:caveman给我上的工具选型课
5.1 和主流待办工具的一次正面比较
我身边很多朋友听说我在用一个“穴居人”工具,第一反应都是:你图什么?为了让他们明白,我拉了一张对比表,把 caveman 和几个典型方案的差异摆明白:
| 对比维度 | caveman | Todoist / Microsoft To Do | Taskwarrior |
|---|---|---|---|
| 配置成本 | 近乎零 | 需要账号、平台、设置 | 需要学习命令体系 |
| 功能丰富度 | 极简:记录、查看、完成 | 高:项目、标签、协作、日历 | 高:依赖、期限、报告 |
| 数据存储 | 本地 JSON,随时可读 | 云端数据库,导出受限 | 本地文本文件,有专门格式 |
| 同步方式 | 靠文件同步,自己控制 | 厂商云同步 | 可配同步服务器但复杂 |
| 学习曲线 | 几分钟 | 中等 | 较陡 |
| 适合场景 | 个人轻量记录 | 团队协作与重度管理 | 极客习惯、复杂工作流 |
从这个表格能很清楚地看出,caveman 锚定的位置是“一个人、一天、十几件事”这种轻量需求。它不可能替代 Todoist 的团队共享能力,也没法跟 Taskwarrior 的完备度掰手腕。但如果你需要的只是“别把事忘了”,它的性价比反而是最高的——不需要付费,不需要理解概念,不需要被任何设计规则绑架。
5.2 这类工具适合谁:一份自测清单
到底要不要用 caveman 这种工具?我自己的判断标准可以概括成下面几个问题:
- 你每天需要管理的任务量是三五条、十几条,还是几十条带子任务的复杂项目?
- 你是否经常在命令行环境里工作,还是几乎所有时间都泡在图形化应用里?
- 你更信任“一个自己看得见的文件”,还是更喜欢“一个无所不能的 App 帮你安排一切”?
- 你能接受没有提醒、没有日历、没有倒数日吗?
如果前三条的答案偏向“终端”“少量任务”“数据自控”,那 caveman 会很合适;如果有一天你需要协作、需要精细的周计划、需要和日历联动,那确实该换用重型工具了。关键不在于谁好谁坏,而在于你是否清楚自己的场景到底需要多少复杂度。很多人痛苦不是因为工具太少,而是用错了复杂度的工具来承担一个简单任务。
5.3 留给自研小工具的几条经验
从 caveman 上学到最深刻的东西,是它对于“产品的边界”的克制。我平时偶尔也会写一些小工具自用,以前总想加这个功能加那个功能,结果弄到一半就不想维护了。现在我做工具时坚持三条原则,很大程度上是受这个项目的启发:
第一,能用文本解决的问题就绝不引入专用数据库。文本文件或 JSON 文件带来的兼容性、可读性、可迁移性是所有数据库都给不了的。第二,入口越少越好。一个任务工具如果有一百个参数、十个子命令,让用户每次使用都要思考,那它本质上已经背叛了“工具”的初衷。第三,让用户永远能访问底层数据。人只要知道自己存的东西在哪里、长什么样、能不能带走,就会对这个工具有一种天然的信任,这种信任是任何精美界面都换不来的。
我把这三条经验用到自己的一个笔记草稿脚本上之后,整个项目的代码量减少了近一半,维护负担也变得微不足道。工具的意义是帮助你、配合你、然后默默退到一边,而不是反过来成为需要你供养的另一个系统——caveman 用自己的方式把这句话证明了一遍。
如果硬要说还缺点什么,那就是它不太适合直接管理那些需要设定期限、按周复盘的重型任务,遇到这种情况,我依然会打开更正式的表格。但在绝大多数普普通通的一天里,敲一行字、划掉一件事,这种穴居人式的朴素确实让我省下了不少心力。最后提醒所有想试的朋友一句话:先备份那个 JSON 文件,然后把它当成一块简单的石头用,别指望它长出翅膀。