
说实话第一次在 GitHub 上看到 Caveman 这个项目名的时候我差点直接划走。caveman 嘛穴居人原始人怎么看都像个玩具。但抱着“这年头还敢叫自己原始人的项目到底能有多糙”的好奇心我点进去之后反而被它的克制吸引住了。折腾了两周我把它改造成了自己桌面上最常用的命令行工具今天这篇就是想把它内部的设计思路、实操经验和踩坑记录完整捋一遍给同样喜欢轻量方案的朋友一个参考。Caveman 做的事情其实特别简单用纯命令行管理个人任务、随手笔记和时间记录数据全部落在一个本地的 SQLite 文件里没有服务端没有网页没有 App不依赖任何第三方框架。它适合谁适合那些不想被协作软件绑架、对数据主权有执念、并且愿意花十分钟学几个命令的人。如果你属于“工具越多越焦虑”的类型Caveman 这种返璞归真的路子可能会让你重新找到掌控感。1. 为什么叫 Caveman极简本身也是一种生产力1.1 名字背后的定位很多人第一眼看到 caveman 这个名字会以为这是个搞笑项目。但实际上它在程序员圈里有点自嘲的意思现代软件越来越重动辄几十 MB 的安装包、几百 MB 的内存占用、还有一堆用不上的功能按钮反而不如一个“原始人”工具来得直接高效。Caveman 的核心理念就是一句话把复杂留给代码把简单留给用户。我第一周使用时的真实感受是它不会打断你。现在很多待办工具的交互流程是“打开 App - 看到一堆花哨的动效 - 输入任务 - 设置提醒 - 点保存”这一套下来至少三十秒。而 Caveman 就是终端里敲一行字的事情敲完就结束没有多余反馈但它确实帮你把事记下来了。这种“无存在感”的设计恰恰是它最独特的价值。说到这里顺便提一句它的数据文件就是~/.caveman/caveman.db这一个文件。备份只需要复制这个文件迁移就是把文件拷到另一台机器没有任何配置同步、账号体系、云服务依赖。对于喜欢折腾多设备的人来说这种原始方式反而最可靠。1.2 和主流工具比Caveman 到底赢在哪为了让大家直观理解它的定位我拿自己用过一阵子的几类工具做了个对比。不算严谨但足够说明问题。方案依赖启动耗时数据位置支持离线学习成本Notion / 飞书文档重量级客户端数秒云端有限高Todoist客户端 账号数秒云端有限中Excel 管理任务Office 套件数秒本机是中CavemanPython3 SQLite100~200ms本机是低从表格能看出来Caveman 唯一需要安装的运行环境是 Python 3而 Python 在 macOS 和 Linux 上基本是自带的。启动耗时方面它连图形界面都没有自然快得离谱。最值得一提的还是数据位置所有信息都在你自己的电脑上不经过任何第三方服务器。对于记录的内容比较敏感、不希望被算法分析的用户而言这一点比任何功能都重要。我理解很多人会质疑“那我为什么不直接用记事本” 区别在于 Caveman 提供了结构化的数据模型和查询统计能力。记事本写 1000 条任务之后就只能靠搜索而 Caveman 可以组合多个条件精确筛选比如查看“高优先级且明天到期且尚未完成”的任务一条命令就够了。这属于“原始但不简陋”的范畴。2. 核心设计与数据模型2.1 技术选型Python 的标准库够不够用Caveman 选 Python 而不是 Go、Rust也没什么高大上的理由就是图省事Python 自带的sqlite3、argparse、datetime三个标准库就覆盖了全部需求不需要pip install任何第三方包。这也意味着你把它拉下来就能跑不会因为依赖冲突浪费半小时。有人可能会觉得命令行工具用 Python 启动慢其实纯标准库启动一般在 100 毫秒级别人根本感知不到。真正慢的往往是那些开头先加载一堆框架、连一下远程服务再渲染界面的应用。Caveman 这种“裸奔”式设计反而在感官上更流畅。2.2 数据库表结构设计我用sqlite3 caveman.db .schema看过它的结构。三张表非常清晰tasks、notes、time_logs。这里贴一下简化后的建表语句方便大家理解我的改造思路。CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, project TEXT DEFAULT inbox, priority TEXT DEFAULT medium, status TEXT DEFAULT pending, -- pending / done / archived created_at TEXT NOT NULL, due_date TEXT, done_at TEXT ); CREATE TABLE IF NOT EXISTS notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, body TEXT, tags TEXT DEFAULT , created_at TEXT NOT NULL, updated_at TEXT ); CREATE TABLE IF NOT EXISTS time_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, start_at TEXT NOT NULL, end_at TEXT, duration INTEGER, comment TEXT );这个设计有一个很关键的细节所有时间字段都存成TEXT类型的 ISO 格式字符串比如2025-04-27 09:30:00而不是 Unix 时间戳。原因我在后面踩坑部分会详细说简单讲就是为了保证可读性和跨平台一致性。duration字段单位为秒但展示时可以很方便地格式化成“1小时23分”。2.3 接口设计像 git 一样组织命令Caveman 的子命令结构是照着 git 学的主命令是caveman后面接一个动词再接具体参数。翻译成人话就是caveman add # 添加一个任务 caveman done # 完成任务 caveman list # 查看任务列表 caveman note # 增加一条笔记 caveman log # 记录某任务花的时间 caveman stats # 输出统计报表这种结构的好处是学习成本极低。只要记住“动词 对象”这个组合逻辑看到caveman add --help基本就能猜出其他子命令的用法。对比某些工具动辄几十个快捷键、还得画脑图记忆Caveman 的交互方式确实更接近“人类直觉”。2.4 为什么不用 Web UI这可能是我被问最多的问题“你都用了 SQLite随便套个 Flask 就能做网页版为什么不加” 我的理解是加上容易但加了之后 Caveman 就不再是 Caveman 了。一旦有 Web 界面用户就会期待实时刷新、多端同步、权限管理每加一个功能都可能引入新的维护负担。而命令行的优势恰恰在于它的“低摩擦”不需要等待服务启动不需要记 URL不需要处理页面崩溃。3. 实操过程从零搭好一个能用的 Caveman3.1 初始化环境第一步当然是拿到项目。Caveman 本体是一个单文件脚本你不用安装直接把仓库克隆下来把脚本放到~/bin目录就行。git clone https://github.com/your-fork/caveman.git mkdir -p ~/bin cp caveman/caveman.py ~/bin/caveman chmod x ~/bin/caveman然后手动创建配置目录初始化数据库mkdir -p ~/.caveman caveman init执行完init之后~/.caveman/caveman.db会自动创建三张空表也就位了。这里有个小建议最好用绝对路径~/bin并且确认它在你 PATH 里。如果你用 zsh记得在~/.zshrc里加上export PATH$HOME/bin:$PATH然后source ~/.zshrc让配置生效。3.2 日常任务管理演示下面是我最近一天的实际操作记录截取了几个典型命令。新建任务指定项目和优先级caveman add 写季度技术总结 -p work -P high -d 2025-05-02 caveman add 给花浇水 -p life caveman add 预约牙医 -p life -P high -d 2025-04-29查看所有未完成任务按优先级排序caveman list --status pending --sort priority输出大概是ID TITLE PROJECT PRIORITY DUE_DATE 3 预约牙医 life high 2025-04-29 1 写季度技术总结 work high 2025-05-02 2 给花浇水 life medium完成任务就直接用 ID 操作caveman done 3这里有一个非常实用的技巧done命令背后实际执行的是UPDATE tasks SET statusdone, done_atdatetime(now,localtime) WHERE id?。它会自动打上完成时间方便后续统计“这周完成了多少件事”。如果某天误操作了可以用我后面讲的恢复方法找回。3.3 笔记与时间记录任务管理只是 Caveman 的一半它还能当随手笔记用。我一般会用它记录灵感和会议摘要caveman note 组件拆分思路 --body 按照边界划分不要按代码行数划分 --tags idea,refactor caveman note 发布流程简化方案 --tags ops查看笔记列表caveman list-notes --tag idea时间记录功能是我自己 fork 之后用得最多的。我经常需要估算某个任务的耗时以前靠手动记 Excel 特别容易忘。现在直接在终端操作caveman log start 1 caveman log stop 1 --comment 整理故障列表 画图这一组命令会把时间区间写进time_logs表然后自动算出duration。当天的累计耗时可以用caveman stats --today查看输出类似时间记录统计 (今天) 任务 #1 写季度技术总结: 2小时45分 任务 #4 修复登录接口: 1小时10分 总计: 3小时55分3.4 让 Caveman 真正融入工作流alias、备份与导出一个工具如果每次都要敲全名用几次就会烦。我最开始就给 Caveman 配了两个 aliasalias ccaveman alias cdonecaveman done这样实际操作就是c add 写周报、cdone 5非常顺滑。另外我还在 shell 里给它加了一个补全函数按 Tab 就能列出子命令不过这个依赖具体 shell就不展开贴代码了。数据安全永远是第一位。我用 cron 每天凌晨自动备份0 2 * * * sqlite3 ~/.caveman/caveman.db .backup ~/backups/caveman_$(date \%Y\%m\%d).db注意这里date命令里的%在 cron 里要转义成\%我第一次写的时候漏了导致备份文件名全变成caveman_date排查了半天。备份之外还可以用纯 SQL 直接导出 CSV方便做月底复盘sqlite3 -header -csv ~/.caveman/caveman.db \ select title, duration, start_at from time_logs join tasks on tasks.idtime_logs.task_id where start_at like 2025-04% \ /tmp/timelog_2025_04.csv导出之后扔进 Excel 或者随便一个数据分析工具都能继续处理这比很多封闭软件导出功能强的地方就在于数据库是自己手里的想怎么查都行。4. 踩过的坑与排查实录4.1 SQLite 并发写入冲突说一下我最开始遇到的坑。当时我同时开了两个终端一个在跑长任务另一个随手caveman add 喝水结果第二条命令直接报错database is locked。原因是 SQLite 默认在多个进程同时写同一个库文件时会触发文件锁我的 Windows 终端环境尤其敏感。解决办法有两种。一是直接把数据库改成 WAL 模式增加并发读写能力sqlite3 ~/.caveman/caveman.db PRAGMA journal_modeWAL;执行后会返回wal这说明日志模式切换成功了。改成 WAL 之后读操作不会阻塞写操作日常使用基本不会再遇到database is locked。如果偶尔还是碰到最省事的兜底方案是在命令外面加一个重试循环比如for i in 1 2 3 4 5; do caveman add xxx break; sleep 0.5; done。4.2 中文字符在终端里显示乱码我在 Windows 的 PowerShell 里第一次运行 Caveman 的时候中文任务标题显示成????当时以为是编码问题后来才发现是终端代码页不对。Python 3 默认字符串是 UTF-8但 PowerShell 有时仍按 GBK 读取输出。最简单的修复方式是把终端切成 UTF-8 模式chcp 65001如果你用的是 Windows Terminal可以直接在配置里把默认编码设为 UTF-8一劳永逸。macOS 和 Linux 基本遇不到这个问题因为它们默认就是 UTF-8。另外如果你在自己的 fork 里改了代码记得在脚本顶部加# -*- coding: utf-8 -*-输出时最好也做一层兜底import sys sys.stdout.reconfigure(encodingutf-8)4.3 日期与时区统计偏差这个坑比较隐蔽。早期版本的时间字段存的是datetime(now)也就是 UTC 时间。我人在东八区每天看统计总觉得“今天”的完成数量少了几条后来一查才发现是时区没对上——凌晨 1 点完成的任务数据库里记的是前一天晚上 17 点。所以我在实操中强烈建议所有时间字段存本地时间用datetime(now, localtime)写入如果实在要存 UTC展示时也必须转回本地时区。ISO 格式的好处在这个问题里体现得很充分2025-04-27 01:00:00一眼就能看懂是不是本地时间而 Unix 时间戳还得心算转换。4.4 误删数据后的恢复策略命令行工具最大的风险就是误操作。有一次我想清空测试数据写了DELETE FROM tasks执行完才意识到正式任务也被删了。好在 SQLite 没有 VCS但它有日志文件WAL 模式下还有-wal文件。如果误删后立刻停止写入可以用备份恢复如果没有备份可以检查同目录下的caveman.db-wal它里面可能还留着最近未合并的修改。从那之后我给所有危险命令都加了二次确认比如caveman purge --yes必须显式加参数才能执行。代码层面其实就是一行判断的事但心理安全感完全不一样。4.5 截图式反思不要轻易“优化”掉的功能还有一个经验不是来自错误而是来自“过度设计”。我原本总觉得list输出太简陋想给它加彩色高亮、百分比进度条。加完之后发现终端日志重定向到文件时会残留 ANSI 转义码导出的 CSV 也变脏了。最后我老实回退到纯文本输出。这件事让我明白命令行工具专注于机器可读和稳定视觉美化交给外部工具处理反而是更负责任的做法。5. 这个项目带给我的经验和启发5.1 极简工具的边界到底在哪很多人会觉得“极简 功能少”实际不是。Caveman 的核心逻辑就是把“存储、查询、统计”这层基本功做扎实把其他能力留给用户通过 shell 管道、SQL、甚至外部脚本去组合。这种边界意识特别值得学习工具先确定自己不该做什么才知道该把什么做好。5.2 给想折腾命令行工具的读者几个建议如果你也想自己动手写类似的小工具我建议从这几个点入手。第一数据结构优先。先花半小时设计数据库表想清楚每个字段的含义再开始写命令逻辑。绝大多数工具难用的根源都是因为数据模型不合理。第二命令接口要遵守“最小惊讶原则”。add就是添加done就是完成别搞出几个语义重叠的动词。你面对的不仅是未来的自己还有可能来 fork 你的陌生人。第三别忘了给每个子命令写--help文档。Caveman 本身就很强调可发现性一行注释可能省掉别人拆源码的时间。5.3 后续我计划扩展的方向目前我在计划加一个简单的“归档”逻辑每季度把已完成且超过 90 天的任务自动备份并清理避免数据库无限膨胀。另一个方向是支持从命令行直接生成 Markdown 周报毕竟周报这种东西手动整理格式太浪费时间了。根据我个人经验这类工具最忌讳一上来就想着“全平台同步”“云端协作”。先把单人使用的闭环跑顺把数据备份和恢复练扎实比加一百个功能都有用。Caveman 这名字本身就提醒我很多年来石器时代的人类能用有限的资源解决生存问题今天的软件也一样有时候少即是多。