ฉันสังเกตคนเก่ง มีระเบียบ ใช้ manual time tracker มาหลายคน และ failure mode มักเป็นแบบเดียวกันทุกครั้ง
เช้าวันจันทร์จำได้ว่าต้อง start timer บ่ายวันจันทร์ switch context หกครั้งแต่ลืม switch timer ตาม วันอังคารรู้ตัวแล้ว กลับไปแก้ entry วันจันทร์จากความจำ ถึงวันพุธ timer ค้างอยู่ที่ "Email" สี่ชั่วโมงเพราะนั่นคือ project ที่เปิดค้างตอนวอกแวก
ข้อมูลผิด และคนที่ track อยู่ก็รู้ว่ามันผิด พอรู้ก็ trust น้อยลง trust น้อยก็ update น้อยลง ข้อมูลก็ยิ่งแย่ลง Manual time tracking คือการพังช้า ๆ แบบ slow-motion
ฉันพยายามหลายปีว่าจะเป็นข้อยกเว้น คนที่มีวินัยพอ ทำไม่ได้ คนรอบข้างฉันก็ไม่มีใครทำได้ คำถามจึงกลายเป็น: ถ้า manual tracking เป็นแค่ความฝัน การ tracking อัตโนมัติจับอะไรได้จริง และมันดีพอไหม?
"อัตโนมัติ" หมายความว่าอะไรจริง ๆ
มีข้อมูลสามอย่างที่ Mac รู้ได้ในทุกขณะโดยที่คุณไม่ต้องทำอะไรเลย:
App ไหนอยู่ข้างหน้า macOS ส่ง notification ผ่าน
NSWorkspaceทุกครั้งที่ app ข้างหน้าเปลี่ยน นั่นคือ hard signal — รู้แน่ชัดว่า Slack หรือ Xcode อยู่ด้านบนWindow ที่ focus บอกว่าอะไร App ส่วนใหญ่ตั้งชื่อ window ไว้มีประโยชน์ Xcode บอกชื่อ project Slack บอกชื่อ channel Chrome บอกชื่อแท็บ นั่นคือ soft signal — มีประโยชน์เมื่อชื่อมีความหมาย ไร้ประโยชน์เมื่อไม่มี (มองหน้าคุณอยู่นะ Finder)
แท็บเบราว์เซอร์ที่ active คือแท็บไหน ต้องการให้เบราว์เซอร์เปิดเผยชื่อแท็บให้ accessibility client บน macOS คือต้องให้ผู้ใช้อนุญาต Accessibility permission อย่างชัดเจน opt-in เท่านั้น
automatic Mac time tracker ที่ดีฟังทั้งสาม Timex ฟังทั้งสาม สิ่งที่มันเก็บคือ stream ของ row ที่หน้าตาประมาณนี้:
2026-05-21 14:32:01 | Xcode | timex/AppDelegate.swift
2026-05-21 14:32:02 | Xcode | timex/AppDelegate.swift
2026-05-21 14:32:03 | Xcode | timex/AppDelegate.swift
2026-05-21 14:32:04 | Slack | #engineering
2026-05-21 14:32:05 | Slack | #engineering
2026-05-21 14:32:06 | Chrome | github.com — pull request #482
แค่นั้นเอง สามคอลัมน์ หนึ่ง row ต่อวินาที แถบสีใน Today view คือ row พวกนั้นรวมเป็นบล็อกต่อเนื่องแล้ว render บนเส้น 24 ชั่วโมง
การตัดสินใจเรื่อง 1 Hz
มีคนถามบ่อยว่าทำไม sample หนึ่งครั้งต่อวินาทีแทนที่จะทุกห้าวินาที หรือทุกนาที หรือทุกหนึ่งในสิบวินาที
ช้ากว่า 1 Hz ทำให้พลาด context switch สั้น ๆ ถ้าคุณเช็ค Slack notification เก้าวินาทีแล้วกลับ Xcode ตัว sampler แบบ 60 วินาทีจะบันทึกนาทีนั้นเป็น all-Xcode หรือ all-Slack ขึ้นอยู่กับว่าอะไรอยู่ข้างหน้าตอน capture ทั้งสองผิด คุณอยากเห็น Slack blip เก้าวินาทีนั้น
เร็วกว่า 1 Hz ไม่ได้เผยข้อมูลใหม่ — มนุษย์ไม่ switch focus สิบครั้งต่อวินาที — และทำให้ SQLite file ใหญ่โดยไม่ได้ข้อมูลเพิ่ม หนึ่งวันทำงานที่ 1 Hz คือประมาณ 30,000 row ที่ 10 Hz คือ 300,000 row สำหรับ insight เดิม เราเลือกตัวเลขที่น้อยกว่า
อีกอย่างที่ 1 Hz ให้คือ idle detection ที่ honest macOS เปิดเผยเวลาตั้งแต่ user input ครั้งล่าสุด ถ้าช่องว่างเกิน threshold (Timex default ที่ 90 วินาที) row นั้นจะถูก mark ว่า idle สอง row idle ติดกันกลายเป็น idle block Idle block ไม่นับเข้า break timer ดังนั้น session focus ลึก ๆ จะไม่ถูกตัดอย่างไม่ยุติธรรมเพราะแค่ไปเติมกาแฟ
คำถามเรื่องแท็บเบราว์เซอร์
นี่คือส่วนของการ track อัตโนมัติที่ทำให้คนกังวล และมีเหตุผลที่สมเหตุสมผล
ถ้า Mac time tracker มองเห็นชื่อแท็บเบราว์เซอร์ที่คุณกำลังดู มันสามารถเห็น "Bank of America" หรือ "MyChart Patient Portal" ในประวัติได้ในทางทฤษฎี คำตอบที่สะอาดที่สุดคือถามผู้ใช้ก่อนที่อะไรจะเกิดขึ้น macOS บังคับให้เราทำแบบนั้น ครั้งแรกที่คุณเปิด Timex ฟีเจอร์แท็บเบราว์เซอร์จะ off คุณต้องให้ Accessibility permission อย่างชัดเจน และยกเลิกได้ตลอดเวลาใน System Settings
เมื่อคุณให้ permission แล้ว สิ่งที่เก็บไว้คือ string ชื่อ window ที่เบราว์เซอร์ publish สำหรับแท็บ current — ไม่มีอะไรเพิ่มเติม เราไม่อ่าน URL เราไม่อ่านเนื้อหาหน้าเว็บ เราไม่อ่านประวัติการเบราว์เซอร์ เราเก็บ string เดียวกับที่มองเห็นใน title bar ของเบราว์เซอร์ ณ ขณะนั้น
ถ้าไม่ต้องการ ปิด permission ไว้และตัว tracker ก็ยังทำงาน — คุณแค่เห็นเบราว์เซอร์เป็นบล็อกเดียว ("Chrome — 41m") แทนที่จะเห็น breakdown แต่ละแท็บ
Data model ใน SQLite
สำหรับใครที่อยากรู้เรื่อง storage layer: Timex ใช้ SQLite file เดียวที่มี table ชุดเล็ก ๆ รูปแบบที่สำคัญคือ activity log ซึ่งมีหน้าตาประมาณนี้:
CREATE TABLE activity_samples (
ts INTEGER NOT NULL, -- unix seconds
app_bundle TEXT, -- e.g. "com.apple.dt.Xcode"
app_name TEXT, -- e.g. "Xcode"
window_title TEXT, -- e.g. "AppDelegate.swift"
browser_tab TEXT, -- nullable, only when permission granted
is_idle INTEGER NOT NULL -- 0 or 1
);
CREATE INDEX idx_samples_ts ON activity_samples(ts);
นั่นคือรูปแบบทั้งหมดของ "วันนี้คุณทำอะไร" เปิด file ด้วย SQLite client ใด ๆ ก็ได้ Run query คำตอบอยู่ห่างแค่ไม่กี่ row
ฉันเคยแชร์ schema นี้ใน Your data, your file — argument เชิงลึกว่าทำไม storage layer คือตัว product สรุปสั้น ๆ คือ: tool ที่ output เป็นแค่ dashboard บน cloud แบบ proprietary จะเสื่อมสภาพไปตามเวลา tool ที่ output เป็น SQLite file จะอยู่กับคุณไปตลอด
คำถามที่การ track อัตโนมัติตอบได้
นี่คือ query ที่เราใช้กับข้อมูลตัวเองจริง ๆ:
เช้านี้หายไปไหน? ลากบน slice 09:00–12:00 ของแถบ ตัวเลขรวมจะ filter ตามช่วงนั้น แตะ app อันดับต้น ขยายเพื่อดูว่า window ไหนกิน slice นั้นไป
สัปดาห์นี้ทำงานถูกเรื่องไหม? รวมเวลาที่อยู่ใน
Xcoderow ที่มีชื่อ window ตรงกับชื่อ project ปัจจุบัน ถ้าน้อยกว่าที่คาด นั่นเป็นปัญหา calendar ไม่ใช่ปัญหา trackerล่าสุดที่คิดลึก ๆ คือเมื่อไหร่? หาบล็อก
is_idle=0ต่อเนื่องยาวที่สุดบน app เดียว ถ้ายาวที่สุดคือ 28 นาที คำตอบคือ "ไม่มีเลยสัปดาห์นี้" — และนั่นคือข้อมูลที่ดำเนินการได้Chrome กินเวลาไปเท่าไหร่? Filter ไปที่ row ที่
app_name='Google Chrome'Group bybrowser_tabSort by count อันดับต้นของ list น่าเศร้าที่มักจะเป็น Reddit หรือ Hacker News หรือหนึ่งในสอง AI vendor ที่ชื่อคล้องจอง
คำถามที่ตอบไม่ได้
อยากพูดตรง ๆ เรื่อง limit
บอกไม่ได้ว่าคุณตั้งใจจะทำอะไร มันเห็นแค่ว่า app อะไรอยู่ข้างหน้า ถ้าคุณใช้เวลาสี่สิบนาทีบน Hacker News เพื่อค้นหาข้อมูล สำหรับงาน tracker เห็น Hacker News ผู้จัดประเภทว่า "คุ้มค่าไหม" อยู่ในหัวคุณ ไม่ใช่ในข้อมูล เราไม่พยายาม automate ตรงนั้น ไม่คิดว่าทำได้
ไม่สามารถ tag project อัตโนมัติ App บางอันทำง่าย (ชื่อ window ของ Xcode คือ file path ซึ่ง map ไป project) App บางอันทำยาก (ชื่อ window ของ Chrome คือชื่อหน้า ซึ่งไม่บอกอะไรเรื่องงาน) คำตอบใน v1 คืออ่านแถบเองด้วยตา version ต่อไปอาจเพิ่ม rule-based tagging ("ถ้าชื่อ window มี X ให้ tag เป็น project Y") สำหรับคนที่ต้องการโครงสร้าง project แบบ lightweight
ไม่สามารถ reconstruct session ที่คุณไม่ได้เปิดไว้ นี่ชัดเจน ติดตั้งวันนี้ ได้ข้อมูลตั้งแต่วันนี้เป็นต้นไป ไม่มีการ backfill แบบมหัศจรรย์
Idle, Sleep, และ Screen Lock
สาม edge case ที่ควรพูดตรง ๆ เพราะ automatic tracker ส่วนใหญ่จัดการแต่ละอย่างไม่สม่ำเสมอ:
Idle — user input timeout Default 90 วินาที Mark ใน row ใช้ skip การนับ break timer แต่ข้อมูลยังบันทึกอยู่เพื่อให้แถบแสดงช่องว่างอย่างซื่อตรง
Display sleep — เมื่อ macOS หรี่หน้าจอเพราะ system idle เราหยุด sampler ทั้งหมด ไม่มีการเขียน row แถบแสดงช่องว่างที่สะอาด
Screen lock — เมื่อคุณกด Ctrl+Cmd+Q หรือทิ้งไว้นานพอให้ lock เอง เหมือนกับ display sleep: sampler หยุด ไม่มี row ช่องว่างสะอาด
หลักการคือ: ถ้าคุณไม่อยู่ที่ Mac ข้อมูลไม่มีสิทธิ์อ้างว่าคุณอยู่
"แล้ว project ล่ะ?"
เรื่องนี้ถามบ่อยพอที่ต้องตอบชัด ๆ
ถ้างานของคุณคือ bill ชั่วโมงให้ client คุณต้องการ project picker จริง ๆ automatic tracker ที่ไม่รู้โครงสร้าง project ของคุณไม่สามารถสร้าง invoice ได้ Toggl และ Harvest ออกแบบมาเพื่อนี้ มี project picker, start/stop friction, และ export pipeline ที่นักบัญชีเชื่อถือ
แต่ถ้างานของคุณคือ เข้าใจสัปดาห์ของตัวเอง ไม่จำเป็นต้องมี project picker คุณแค่ต้องมองแถบแล้วสังเกตว่าบ่ายวันอังคารเป็น Slack สี่ชั่วโมงโดยไม่มีอะไรอยู่ใน Cmd+Tab ใกล้ ๆ codebase นั่นคือ insight ที่ได้ ไม่ต้องมี project label
คนส่วนใหญ่ที่ฉันสร้างสิ่งนี้มาเพื่ออยู่ใน camp ที่สอง พวกเขาอยู่ใน Claude Code และ Cursor อยู่แล้ว และ Octomind agent run ที่กิน Wednesday morning หายไป พวกเขาอยากเห็นว่าชั่วโมงไปตกที่ไหน ไม่ต้องการจัดมันลง bill code
ทดสอบวันพุธ
นี่คือ test ที่ฉันใช้กับ time tracker ก่อนจะพิจารณาพึ่งพา
เช้าวันพุธ standup ถามว่าวันจันทร์ทำอะไร คุณเปิด tracker
- ถ้าข้อมูล reconstruct มาจากความจำคืนวันอังคาร มันโกหก คุณจำ Slack ผิดเป็น Xcode และ Xcode ผิดเป็น Slack คำตอบใน standup ผิดแต่ฟังดูมั่นใจ
- ถ้าข้อมูล automatic มันคือความจริงน่าเบื่อเดิม ที่แถบแสดงให้เห็นตอนเย็นวันจันทร์ คุณอ่านมัน พูดมัน แล้วไปต่อ
นั่นคือช่องว่างที่ automatic tracking ปิดจริง ๆ ไม่ใช่ productivity ไม่ใช่ focus ไม่ใช่แม้แต่ความจำ แค่ เวอร์ชันของวันที่ tracker รายงานตรงกับเวอร์ชันที่เกิดขึ้นจริง
ถ้าอยากเห็นหน้าตาบน Mac ของคุณ รับ trial 100 ชั่วโมง ใช้ได้สาม Mac ไม่ต้องสมัคร ไม่มี cloud แถบเดียวกับที่เราใช้บน laptop ของตัวเองทุกวัน