关于 work-hours
根据个人已有的活动时间戳估算工作时长的技能。它比较消息活动与设备在场模型,并说明如何依据证据校准空闲时长、解读数据。
主要功能
- 01合并多个来源的活动记录
- 02比较消息与设备在场模型
- 03依据证据校准空闲阈值
- 04按客户归属工作时长
- 05扣除休息与休闲活动
适用场景
- 01依据活动记录估算工作时长
- 02比较不同方法的工时结果
- 03区分工作、休息与休闲
- 04生成按工作日和客户划分的报告
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ marks97/ work-hours --skill work-hours安装后在 Claude Code 中输入/work-hours确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/config.example.jsonmac-upload-prompt.mdmethodology.mdsources.mdscripts/calibrate.pycommon.pyextract_chess.pyextract_claude.pyextract_mac.pyextract_meetings.pyextract_whatsapp.pymodel.pyslack_parse.py详细介绍
工作时长
根据人员已经产生的时间戳,事后重建工作时间。结果的准确性只取决于两件事:区分人员自己的操作与自动化行为,以及判断沉默意味着什么。以下内容都围绕如何做好这两点。
在采信任何数字前,请先阅读 references/methodology.md——其中列出了那些会让结果偏差数小时的陷阱。各数据源的具体操作方法见 references/sources.md。
基本原则
- 个人数据默认临时存储。 所有内容都放在配置中的运行目录(
run_dir,默认值为~/.cache/work-hours/run)。绝不要将提取的事件写入代码仓库。人员表示工作完成后,删除运行目录及所有上传的数据(浏览器历史记录、聊天导出文件、屏幕使用时间数据库);并确认这些路径已不存在。 - 全程只读。 对 Slack、GitHub、跟踪工具、邮件,只搜索和读取,不发布内容或进行互动。
- 限制资源占用。 转录文件夹可能有数 GB:使用
nice -n 19 ionice -c3,逐行读取,只启用一到两个读取进程,并使用python3 -I。 - 索取数据,不要猜测。 人员可以提供你无法访问的数据(聊天导出文件、笔记本电脑上的文件、国际象棋用户名、会议安排)。尽早询问;参见“需要索取的内容”。
工作流
S=<this skill>/scripts
# 0. config: copy references/config.example.json to ~/.config/work-hours/config.json and fill it in
# (timezone, window, customer rules, Slack user id, chess usernames, meeting schedule, categories).
# The person's real config never lives inside the skill.
python3 -I $S/extract_claude.py # human prompts + answers/interrupts from transcripts
# Slack: run the MCP search loop (references/sources.md), then:
python3 -I $S/slack_parse.py <saved result files...>
python3 -I $S/extract_whatsapp.py _chat.txt --me "<name>" --customer <c> --tag <who>
python3 -I $S/extract_chess.py # chess.com / lichess → leisure intervals
python3 -I $S/extract_meetings.py # recordings + recurring calls (run after the point extractors)
python3 -I $S/extract_mac.py <upload-dir> # laptop presence, foreground apps, browsing
# any other human-only source (PR approvals, tracker moves made in the UI): write events.<name>.ndjson
python3 -I $S/calibrate.py # silence survival, bout criterion, ground-truth check
python3 -I $S/model.py --idle 25 --tail 5 # → report.md
单点事件存储在 events.<source>.ndjson(ts、src、customer、kind)中;时间段存储在 intervals.<source>.ndjson(start、end、category)中。model.py 会读取所有匹配这些名称的文件,因此新增数据源只需添加一个新文件。
模型
有两种独立的方法。报告两者;两者结果一致,才说明准确。
- B. 消息: 将所有来源中的每个人工操作合并成一条时间线。沉默不超过
idle分钟时视为工作;超过此时长则视为休息,但仍会从最后一次操作之后计入tail分钟。休闲时间段(国际象棋对局、休闲浏览)会被扣除。 - A. 在场情况: 笔记本电脑处于有人使用状态的时长(已解锁,并扣除显示器睡眠后的尾随时长),减去休闲时间,再加上仅在有证据时确认的离开电脑工作时长:电脑不在身边时发送的手机消息(间隔少于
idle分钟时合并计算)以及通话。笔记本电脑显示人员已离开时,不要让消息模型继续填补空档——这会导致每天重复计入约 1.5 小时。
先合并所有客户的数据进行衡量;按客户拆分时,将每个工作分钟归属到最近操作对应的客户。按固定的本地时间划分工作日(默认 05:00),因此 02:00 的工作时段归入前一天。
选择空闲阈值(最重要的数字)
在一个真实数据集中,阈值设为 5 分钟和 60 分钟时,结果分别从每天 6.0 小时变为 13.9 小时,而间隔直方图没有明显的自然分界。应进行校准,不要凭空选择。
calibrate.py会给出工作时段的判定标准:一个下限,通常约为 10 分钟。- 以人员本人的表述作为真实依据。 在他们使用的所有语言中,查找消息里的“午餐”“稍等一下”“回来了”“去睡觉了”“在火车上,用手机工作”等表达。每条匹配结果都要亲自阅读:不能让词语列表替你判断含义。编写包含
away和phone_work时段的labels.ndjson。合适的阈值应能区分这两种情况。在校准案例中,明确说明的休息间隔从未少于 27 分钟,手机工作间隔从未超过约 26 分钟,因此阈值定为 25 分钟。 - 注意力检查。 在由 Agent 驱动的工作中,查看人员是在 Agent 完成后几秒内回复(说明他们一直在关注),还是过了很久才回复(说明他们当时不在)。如果人员通常在 Agent 完成约 16 分钟后才回复,而且几乎从不在 2 分钟内回复,那么沉默就不代表他们在专注等待,因此不要为了涵盖这些情况而调高阈值。
可以索取的内容
按价值排序:
- 笔记本电脑活动。 将
references/mac-upload-prompt.md发给他们 Mac 上的 Agent。该文件会上传浏览器历史记录、knowledgeC.db(屏幕开启时的前台应用)以及锁定/电源日志。这是最强的信号。 - 聊天记录导出,包括与他们共事的人之间的聊天(WhatsApp「导出聊天」)。
- 用于有 API 的休闲活动的用户名(chess.com、lichess)。
- 定期会议: 日期、时间、时长以及变更时间。
- 如果他们想要更精确的数据,可提供耗时较长的导出文件: Google Takeout(YouTube 和 Maps)、Apple Health(睡眠)。只有开启「跨设备共享」后,iPhone 的屏幕使用时间才会同步到 Mac;即便如此,数据仍保存在需要完全磁盘访问权限的系统存储中。
- 要排除的假期和其他时段,作为配置项
exclude。
报告
先列出工作日和周末每天的总时数,再说明不同方法和阈值下的范围。然后介绍各客户的时间分布、按时钟时间划分的日常规律(开始、用餐时段的低谷、第二个工作时段、结束),以及在「工作」时间内发现了多少休闲活动。明确指出仍无法看到的内容:手机屏幕使用时间、未记录的通话,以及离开键盘时的思考。