控:打造macOS菜單欄Token小工具)
經(jīng)常寫 Claude Code 的開發(fā)者應(yīng)該都有過這種經(jīng)歷代碼正改到一半突然收到用量超限的提示只能停下來等窗口重置。網(wǎng)絡(luò)上有人把這個(gè)場景做成了一個(gè)很輕量的解決方案——一個(gè)體積很小、掛在菜單欄上的 Claude 用量小工具小到你不用打開任何面板掃一眼菜單欄就能決定“現(xiàn)在還能不能繼續(xù)跑”。這篇文章會沿著這個(gè)思路從零拆解這樣一款工具的設(shè)計(jì)與實(shí)現(xiàn)包含數(shù)據(jù)來源分析、代碼示例、開機(jī)自啟配置和排錯(cuò)清單。1. 背景Claude Code 用量監(jiān)控為什么是剛需1.1 Claude Code 是什么Claude Code 是 Anthropic 推出的終端 AI 編程代理工具。和網(wǎng)頁版 Claude 不同你可以在終端里通過命令行直接和它交互讓它讀取項(xiàng)目文件、分析報(bào)錯(cuò)、生成代碼、執(zhí)行測試甚至做多文件的重構(gòu)。對很多把 Claude 當(dāng)主力編程助手的開發(fā)者來說Claude Code 已經(jīng)是日常開發(fā)流程的一部分。不過Claude Code 的底層依然要調(diào)用大模型接口也就意味著有“用量”這個(gè)概念。不同訂閱檔位、不同模型的調(diào)用都有額度限制一旦長時(shí)間高密度使用很可能觸發(fā)限流導(dǎo)致一段時(shí)間內(nèi)無法繼續(xù)調(diào)用。1.2 用量的不確定性帶來的問題使用 Claude 或 Claude Code 時(shí)用量消耗并不總是線性的。你可能會遇到下面幾種情況一個(gè)包含大量上下文的重構(gòu)任務(wù)可能一次對話就消耗大量 token。Claude Code 自動(dòng)讀取項(xiàng)目文件后輸入 token 會快速增長。頻繁使用技能、多輪對話、長日志分析都會明顯拉高用量。代碼助手用起來太順手往往“一不小心”就連續(xù)跑了幾個(gè)小時(shí)。如果等到請求被拒絕時(shí)才意識到用量超了開發(fā)節(jié)奏已經(jīng)被打斷了。此時(shí)還需要再切換工具、等窗口重置效率影響很大。1.3 菜單欄小工具的價(jià)值菜單欄小工具的核心價(jià)值是把“用量數(shù)據(jù)”從后臺搬到前臺。你不需要打開瀏覽器不需要敲一個(gè)命令也不需要切換到另一個(gè)窗口。只要眼睛掃一下屏幕右上角就能看到當(dāng)前大概消耗了多少 token。設(shè)計(jì)這種工具的難點(diǎn)不是“顯示數(shù)據(jù)”而是“讓數(shù)據(jù)足夠直觀”這也是標(biāo)題里提到的“small enough to read before you run it”——在你決定運(yùn)行下一步操作之前就能判斷要不要繼續(xù)。與其等超限報(bào)錯(cuò)不如提前從數(shù)據(jù)上預(yù)判。這也正是這類工具吸引人的地方把看不見的后臺消耗變成了菜單欄上一個(gè)可讀的指標(biāo)。2. 整體設(shè)計(jì)思路2.1 工具要解決的核心問題我們要實(shí)現(xiàn)的是一個(gè)跑在 macOS 菜單欄上的小應(yīng)用它需要滿足幾個(gè)關(guān)鍵要求常駐在菜單欄不占用 Dock 位置。能以極簡文字展示用量比如只顯示 token 總量的縮寫如“C 128K”。點(diǎn)擊菜單欄圖標(biāo)后可以查看近期會話的詳細(xì)統(tǒng)計(jì)。支持定時(shí)刷新最好是可配置刷新間隔。足夠輕量不依賴較大的運(yùn)行時(shí)。在動(dòng)手前先要把數(shù)據(jù)來源想清楚。沒有穩(wěn)定可靠的數(shù)據(jù)來源后面的展示再好看也沒有意義。2.2 數(shù)據(jù)來源選型Claude 的用量數(shù)據(jù)目前沒有一個(gè)完全統(tǒng)一的本地接口但從 Claude Code 的產(chǎn)品形態(tài)來看主要有三種思路方案說明優(yōu)點(diǎn)局限解析本地會話日志Claude Code 會在本地目錄記錄會話 JSONL 文件里面包含每次調(diào)用的 usage 字段不依賴額外接口反映的是當(dāng)前機(jī)器上的真實(shí)調(diào)用量只能統(tǒng)計(jì)當(dāng)前機(jī)器上的會話跨設(shè)備數(shù)據(jù)無法覆蓋調(diào)用 Anthropic API 的模型用量信息API 響應(yīng)中帶有 usage 字段可在自己寫的調(diào)用邏輯里累積數(shù)據(jù)精確適合自己開發(fā)應(yīng)用時(shí)統(tǒng)計(jì)對 Claude Code 這類現(xiàn)成工具拿不到它的運(yùn)行密鑰官方后臺或賬戶頁面手動(dòng)查詢在賬戶設(shè)置中查看訂閱用量最接近官方真實(shí)額度無法自動(dòng)化集成到菜單欄對菜單欄小工具來說最可行的方案是“解析本地會話日志”。這是最穩(wěn)妥也最容易實(shí)現(xiàn)的方式不需要額外權(quán)限也不需要把 API Key 交給第三方小工具。2.3 技術(shù)選型macOS 菜單欄應(yīng)用有幾種常見實(shí)現(xiàn)方式方案運(yùn)行方式優(yōu)點(diǎn)缺點(diǎn)Python rumpsPython 腳本啟動(dòng)后創(chuàng)建一個(gè)菜單欄 App代碼短、開發(fā)快、容易改需要本機(jī)有 Python 環(huán)境Swift NSStatusItem編譯為原生 macOS 應(yīng)用體積小、性能好、無外部依賴代碼量比 Python 多一些Electron Tray基于 Node.js / Web 技術(shù)前端能力強(qiáng)、跨平臺打包體積大、內(nèi)存占用偏高Node.js menubar基于 Electron 的輕量封裝對有 JS 經(jīng)驗(yàn)的開發(fā)者友好同樣存在 Electron 體積問題如果你追求輕量和可維護(hù)性Python rumps 是最合適的。rumps 是一個(gè)專門用來開發(fā) macOS 菜單欄應(yīng)用的 Python 庫接口非常簡潔幾分鐘就能寫出來一個(gè)小工具。下面我以它為例展開完整實(shí)現(xiàn)。3. 環(huán)境準(zhǔn)備與項(xiàng)目結(jié)構(gòu)3.1 環(huán)境要求在開始寫代碼前先確認(rèn)以下環(huán)境項(xiàng)目建議操作系統(tǒng)macOS 12 或更高版本Python3.9 或更高版本rumps0.4.0 或更高版本Claude Code已在本機(jī)安裝并使用過有會話日志生成版本需要根據(jù)你的項(xiàng)目實(shí)際情況調(diào)整本文示例以常見環(huán)境為例重點(diǎn)演示配置思路。如果你還沒有安裝過 Claude Code需要先安裝并完成一次登錄與對話這樣本地才會生成可分析的會話數(shù)據(jù)。3.2 安裝 rumps在終端中創(chuàng)建項(xiàng)目目錄并安裝依賴mkdir -p ~/claude-usage-menu cd ~/claude-usage-menu python3 -m venv venv source venv/bin/activate pip install rumps如果你希望全系統(tǒng)都能直接運(yùn)行也可以使用pip install --user rumps。不過在 macOS 上更推薦用虛擬環(huán)境避免影響系統(tǒng)自帶的 Python 環(huán)境。3.3 項(xiàng)目結(jié)構(gòu)建議按下面的方式組織文件claude-usage-menu/ ├── claude_usage_menu.py # 主腳本 ├── requirements.txt # 依賴清單 └── README.md # 使用說明其中requirements.txt內(nèi)容很簡單rumps0.4.0這樣在換電腦或重新部署時(shí)只需要pip install -r requirements.txt就能恢復(fù)環(huán)境。4. 解析 Claude 用量數(shù)據(jù)4.1 理解 usage 數(shù)據(jù)格式要解析數(shù)據(jù)首先要知道數(shù)據(jù)長什么樣。Claude Code 的會話記錄以 JSONL 格式保存在本地默認(rèn)目錄是~/.claude/projects/。目錄下的每個(gè).jsonl文件對應(yīng)一次項(xiàng)目會話文件名通常是項(xiàng)目路徑經(jīng)過編碼后生成的字符串。這些 JSONL 文件中的每一行都是一個(gè) JSON 對象記錄了會話過程中的一次事件。在 assistant 類型的事件里通常包含一個(gè)message字段而message.usage就是一次 API 調(diào)用的 token 消耗情況。典型的 usage 結(jié)構(gòu)如下{ usage: { input_tokens: 1250, output_tokens: 418, cache_creation_input_tokens: 0, cache_read_input_tokens: 5120 } }各字段含義input_tokens本次請求的輸入 token 數(shù)。output_tokens本次響應(yīng)的輸出 token 數(shù)。cache_creation_input_tokens寫入緩存的輸入 token 數(shù)。cache_read_input_tokens命中緩存后讀取的 token 數(shù)。其中緩存 token 在長上下文中很常見也是用量占比很高的一部分。如果只統(tǒng)計(jì) input 和 output會明顯低估實(shí)際消耗。4.2 從會話日志中統(tǒng)計(jì) token在寫代碼之前建議先手動(dòng)確認(rèn)一下日志路徑ls -lh ~/.claude/projects/ | head -20如果能看到一堆.jsonl文件說明日志路徑正確。接下來可以統(tǒng)計(jì)日志中的 usagegrep -o input_tokens:[0-9]* ~/.claude/projects/*.jsonl | awk -F: {s$2} END {print s}這個(gè)命令只是用來快速驗(yàn)證數(shù)據(jù)是否存在。正式腳本建議使用 Python 來處理因?yàn)?JSONL 解析更健壯還能順便統(tǒng)計(jì)各類 token 的分布。4.3 獲取精確剩余額度的限制這里需要提醒你一下本地日志只能統(tǒng)計(jì)“當(dāng)前這臺機(jī)器、當(dāng)前登錄賬號在本地產(chǎn)生的會話消耗”。它不能直接拿到官方賬戶的精確剩余額度。不同訂閱檔位的額度策略由官方后臺控制可能會按時(shí)間段滾動(dòng)重置也可能與套餐檔位有關(guān)。如果你需要精確的剩余額度數(shù)據(jù)最可靠的方式是登錄官方賬戶頁面查看。本地小工具更適合用來做“消耗趨勢提醒”而不是“精確額度儀表盤”。明白了這個(gè)邊界后我們的統(tǒng)計(jì)目標(biāo)就是把本地會話日志中的 token 消耗讀出來按分類累加再展示到菜單欄。5. 實(shí)現(xiàn)菜單欄展示5.1 用 rumps 創(chuàng)建菜單欄應(yīng)用rumps 的核心是App類和Timer類。我們先創(chuàng)建主腳本的骨架import json from pathlib import Path import rumps CLAUDE_DIR Path.home() / .claude / projects REFRESH_SECONDS 60這里的CLAUDE_DIR是日志目錄REFRESH_SECONDS是菜單欄的刷新間隔。建議不要設(shè)置太短比如 10 秒刷新一次因?yàn)槊看嗡⑿露家x取并解析一批 JSONL 文件間隔太短會白白消耗 CPU。5.2 統(tǒng)計(jì)函數(shù)編寫一個(gè)函數(shù)用來掃描目錄下的所有.jsonl文件解析其中的 usage 字段并累加def collect_usage_stats(): stats { input_tokens: 0, output_tokens: 0, cache_read_tokens: 0, cache_creation_tokens: 0, message_count: 0, found: False, } if not CLAUDE_DIR.exists(): return stats for jsonl_file in CLAUDE_DIR.glob(*.jsonl): try: with open(jsonl_file, r, encodingutf-8) as fp: for line in fp: line line.strip() if not line: continue record json.loads(line) usage record.get(usage) if not usage: message record.get(message) if message: usage message.get(usage) if not usage: continue stats[found] True stats[input_tokens] int(usage.get(input_tokens, 0)) stats[output_tokens] int(usage.get(output_tokens, 0)) stats[cache_read_tokens] int(usage.get(cache_read_input_tokens, 0)) stats[cache_creation_tokens] int(usage.get(cache_creation_input_tokens, 0)) stats[message_count] 1 except (json.JSONDecodeError, OSError): continue return stats這段代碼做了幾件事先判斷日志目錄是否存在不存在就直接返回空統(tǒng)計(jì)。遍歷所有.jsonl文件。逐行解析 JSON同時(shí)兼容 usage 在頂層或嵌套在 message 里的兩種結(jié)構(gòu)。分別累加輸入、輸出、緩存讀、緩存寫 token。用found標(biāo)記本地是否真的有可用日志。如果某個(gè)文件損壞或包含非法 JSON腳本會跳過該文件不會因?yàn)閱螚l壞數(shù)據(jù)導(dǎo)致整個(gè)程序崩潰。5.3 格式化顯示數(shù)字菜單欄空間有限直接顯示“123456789”這種長數(shù)字并不友好。我們需要一個(gè)格式化函數(shù)把大數(shù)字轉(zhuǎn)換為縮寫形式def format_tokens(count): if count 1_000_000: return f{count / 1_000_000:.1f}M if count 1_000: return f{count / 1_000:.0f}K return str(count)運(yùn)行結(jié)果示例輸入 tokens1.2M 輸出 tokens850K 緩存讀取560K 緩存寫入128K這種縮寫形式正是“小到能看清”的關(guān)鍵在菜單欄上顯示C 2.1M比顯示完整數(shù)字更易讀。5.4 創(chuàng)建菜單欄應(yīng)用接下來創(chuàng)建App子類把統(tǒng)計(jì)函數(shù)接入菜單欄class ClaudeUsageApp(rumps.App): def __init__(self): super().__init__(ClaudeUsage, titleC ...) self.menu [ rumps.MenuItem(正在讀取用量請稍候...), None, rumps.MenuItem(立即刷新, callbackself.refresh), rumps.MenuItem(退出, callbackself.quit), ] self.refresh() self.timer rumps.Timer(self.refresh, REFRESH_SECONDS) self.timer.start() def refresh(self, _None): stats collect_usage_stats() total_tokens ( stats[input_tokens] stats[output_tokens] stats[cache_read_tokens] stats[cache_creation_tokens] ) self.title fC {format_tokens(total_tokens)} self.menu.clear() self.menu.add(rumps.MenuItem(f輸入 tokens{format_tokens(stats[input_tokens])})) self.menu.add(rumps.MenuItem(f輸出 tokens{format_tokens(stats[output_tokens])})) self.menu.add(rumps.MenuItem(f緩存讀取{format_tokens(stats[cache_read_tokens])})) self.menu.add(rumps.MenuItem(f緩存寫入{format_tokens(stats[cache_creation_tokens])})) self.menu.add(rumps.MenuItem(f消息條數(shù){stats[message_count]})) self.menu.add(None) self.menu.add(rumps.MenuItem(立即刷新, callbackself.refresh)) self.menu.add(rumps.MenuItem(退出, callbackself.quit))這里需要注意幾點(diǎn)self.title是菜單欄上顯示的標(biāo)題我把它設(shè)置成類似C 1.8M的短文本。self.menu.clear()會清空舊菜單避免重復(fù)添加菜單項(xiàng)。rumps.MenuItem的callback參數(shù)指定點(diǎn)擊該菜單項(xiàng)時(shí)觸發(fā)的函數(shù)。rumps.Timer(self.refresh, REFRESH_SECONDS)會每隔 60 秒調(diào)用一次refresh。None在菜單列表中表示分隔線。最后添加啟動(dòng)入口if __name__ __main__: ClaudeUsageApp().run()到這里一個(gè)最基本的 Claude 用量菜單欄工具就完成了。5.5 運(yùn)行與驗(yàn)證在項(xiàng)目目錄下運(yùn)行python claude_usage_menu.py正常情況下菜單欄右上角會立刻出現(xiàn)一個(gè)C 0或C 0.9M類似的文字。點(diǎn)擊它會展開一個(gè)菜單展示各類 token 的統(tǒng)計(jì)信息。如果你在菜單欄中看不到任何內(nèi)容可以查看終端輸出。rumps 在創(chuàng)建菜單欄應(yīng)用時(shí)如果權(quán)限不足或運(yùn)行環(huán)境異常通常會打印對應(yīng)的錯(cuò)誤信息。6. 完整代碼整合6.1 完整腳本把上面的代碼整合到一個(gè)文件里完整版如下# 文件路徑claude-usage-menu/claude_usage_menu.py import json from pathlib import Path import rumps CLAUDE_DIR Path.home() / .claude / projects REFRESH_SECONDS 60 def collect_usage_stats(): stats { input_tokens: 0, output_tokens: 0, cache_read_tokens: 0, cache_creation_tokens: 0, message_count: 0, found: False, } if not CLAUDE_DIR.exists(): return stats for jsonl_file in CLAUDE_DIR.glob(*.jsonl): try: with open(jsonl_file, r, encodingutf-8) as fp: for line in fp: line line.strip() if not line: continue record json.loads(line) usage record.get(usage) if not usage: message record.get(message) if message: usage message.get(usage) if not usage: continue stats[found] True stats[input_tokens] int(usage.get(input_tokens, 0)) stats[output_tokens] int(usage.get(output_tokens, 0)) stats[cache_read_tokens] int(usage.get(cache_read_input_tokens, 0)) stats[cache_creation_tokens] int(usage.get(cache_creation_input_tokens, 0)) stats[message_count] 1 except (json.JSONDecodeError, OSError): continue return stats def format_tokens(count): if count 1_000_000: return f{count / 1_000_000:.1f}M if count 1_000: return f{count / 1_000:.0f}K return str(count) class ClaudeUsageApp(rumps.App): def __init__(self): super().__init__(ClaudeUsage, titleC ...) self.menu [ rumps.MenuItem(正在讀取用量請稍候...), None, rumps.MenuItem(立即刷新, callbackself.refresh), rumps.MenuItem(退出, callbackself.quit), ] self.refresh() self.timer rumps.Timer(self.refresh, REFRESH_SECONDS) self.timer.start() def refresh(self, _None): stats collect_usage_stats() total_tokens ( stats[input_tokens] stats[output_tokens] stats[cache_read_tokens] stats[cache_creation_tokens] ) self.title fC {format_tokens(total_tokens)} self.menu.clear() self.menu.add(rumps.MenuItem(f輸入 tokens{format_tokens(stats[input_tokens])})) self.menu.add(rumps.MenuItem(f輸出 tokens{format_tokens(stats[output_tokens])})) self.menu.add(rumps.MenuItem(f緩存讀取{format_tokens(stats[cache_read_tokens])})) self.menu.add(rumps.MenuItem(f緩存寫入{format_tokens(stats[cache_creation_tokens])})) self.menu.add(rumps.MenuItem(f消息條數(shù){stats[message_count]})) self.menu.add(None) self.menu.add(rumps.MenuItem(立即刷新, callbackself.refresh)) self.menu.add(rumps.MenuItem(退出, callbackself.quit)) if __name__ __main__: ClaudeUsageApp().run()這段代碼的核心邏輯并不復(fù)雜但已經(jīng)覆蓋了從數(shù)據(jù)采集到菜單欄展示的完整鏈路。如果你使用的是較新版本的 rumps部分內(nèi)部 API 可能會略有調(diào)整建議以官方文檔中的類方法為準(zhǔn)。6.2 配置為開機(jī)啟動(dòng)如果希望菜單欄工具在系統(tǒng)啟動(dòng)后自動(dòng)運(yùn)行可以把腳本配置為一個(gè) LaunchAgent。在~/Library/LaunchAgents/下創(chuàng)建一個(gè) plist 文件?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyLabel/key stringcom.example.claudeusage/string keyProgramArguments/key array string/Users/yourname/claude-usage-menu/venv/bin/python/string string/Users/yourname/claude-usage-menu/claude_usage_menu.py/string /array keyRunAtLoad/key true/ keyKeepAlive/key true/ /dict /plist注意把/Users/yourname/替換成你的真實(shí)用戶路徑。使用虛擬環(huán)境中的 Python 可以避免依賴系統(tǒng) Python 的包環(huán)境。然后執(zhí)行加載命令launchctl load ~/Library/LaunchAgents/com.example.claudeusage.plist在新版 macOS 中系統(tǒng)可能會提示load已廢棄推薦使用launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.claudeusage.plist兩種命令都可以讓 LaunchAgent 生效你可以根據(jù)自己系統(tǒng)的提示選擇合適的方式。6.3 結(jié)果說明運(yùn)行腳本并讓 Claude Code 繼續(xù)正常工作一段時(shí)間后你會看到菜單欄數(shù)字會隨著會話量上升而變化。舉例說明我的展示方式如果菜單欄顯示C 0說明本地沒有找到可用的 usage 日志或者所有日志中的 usage 字段都為空。如果菜單欄顯示C 1.2M說明本地累計(jì)消耗約 120 萬 token。點(diǎn)擊菜單欄后可以看到輸入、輸出、緩存讀取、緩存寫入四項(xiàng)的詳細(xì)拆分。這個(gè)數(shù)字只是一個(gè)相對參考目的是讓你形成“用量直覺”。當(dāng)數(shù)字快速上漲時(shí)你至少會意識到當(dāng)前會話消耗明顯偏大。7. 常見問題與排查7.1 菜單欄不顯示內(nèi)容問題現(xiàn)象常見原因解決思路菜單欄沒有任何圖標(biāo)或文字Python 環(huán)境缺少 rumpspip install rumps后重新運(yùn)行終端直接退出腳本語法錯(cuò)誤檢查 Python 版本和代碼縮進(jìn)消息顯示權(quán)限失敗macOS 輔助功能或通知權(quán)限未授予在系統(tǒng)設(shè)置中檢查終端/腳本的權(quán)限如果菜單欄上沒有出現(xiàn)內(nèi)容先確認(rèn)終端里是否打印了異常堆棧。最常見的異常是ModuleNotFoundError: No module named rumps說明當(dāng)前 Python 環(huán)境沒有安裝 rumps。記得先激活虛擬環(huán)境再運(yùn)行腳本。7.2 讀取不到會話日志問題現(xiàn)象常見原因解決思路顯示 C 0本地沒有~/.claude/projects目錄先正常使用一次 Claude Code顯示 C 0日志路徑發(fā)生改變在終端執(zhí)行l(wèi)s -lh ~/.claude/projects/確認(rèn)顯示 C 0日志文件為空新開一個(gè)會話再觀察解決這個(gè)問題的第一步是先確認(rèn)日志目錄是否存在。如果 Claude Code 版本更新后路徑有變化需要同步調(diào)整CLAUDE_DIR常量。7.3 usage 統(tǒng)計(jì)為 0問題現(xiàn)象常見原因解決思路統(tǒng)計(jì)結(jié)果始終為 0JSONL 中的字段結(jié)構(gòu)不兼容手動(dòng)查看一行日志確認(rèn) usage 位置統(tǒng)計(jì)結(jié)果始終為 0日志文件編碼異常使用 Python 腳本逐行調(diào)試統(tǒng)計(jì)結(jié)果偏小只統(tǒng)計(jì)了輸入輸出沒有統(tǒng)計(jì)緩存確認(rèn)解析邏輯包含 cache 字段可以手動(dòng)查看一條日志來判斷結(jié)構(gòu)head -5 ~/.claude/projects/*.jsonl如果日志中的 usage 字段嵌套層級和示例不同需要調(diào)整collect_usage_stats中的取值邏輯。7.4 請求被限流與 529 問題使用 Claude Code 時(shí)如果用量達(dá)到限制終端里可能會返回類似529或配額相關(guān)提示。這類錯(cuò)誤通常不是本地文件導(dǎo)致的而是賬戶配額或服務(wù)端限流導(dǎo)致。如果菜單欄顯示用量并不高但 Claude Code 依然報(bào)錯(cuò)說明本機(jī)日志只反映了部分會話或配額策略涉及跨設(shè)備賬戶維度。此時(shí)應(yīng)優(yōu)先查看官方賬戶頁面的用量說明而不是繼續(xù)依賴本地統(tǒng)計(jì)。8. 最佳實(shí)踐與工程建議8.1 數(shù)據(jù)統(tǒng)計(jì)單位與顯示策略菜單欄空間很有限不要堆砌完整數(shù)字。建議遵循以下原則只顯示一個(gè)總覽值例如C 1.8M。把詳細(xì)分類放到下拉菜單中。設(shè)置合理的刷新間隔建議 30 到 120 秒。在版本更新時(shí)留意 Claude Code 是否會改變?nèi)罩韭窂交蜃侄谓Y(jié)構(gòu)。小工具的核心是“一眼可知”不是“信息大全”。把最關(guān)鍵的判斷依據(jù)放到最顯眼的位置其余細(xì)節(jié)收起來。8.2 隱私與安全Claude 會話日志中通常包含項(xiàng)目路徑、代碼上下文、文件內(nèi)容等信息屬于敏感數(shù)據(jù)。在設(shè)計(jì)工具時(shí)要注意幾點(diǎn)不要在工具中上傳會話日志到任何第三方服務(wù)。不要圖方便把日志文件提交到公開倉庫。本地處理即可避免引入不必要的網(wǎng)絡(luò)請求。如果需要多人使用或發(fā)布到 GitHub建議把日志目錄路徑做成配置項(xiàng)避免硬編碼個(gè)人目錄。不要為了追求“好看”而把整個(gè)會話內(nèi)容展示在菜單欄里這既沒有必要也容易造成信息泄露。8.3 從腳本到正式應(yīng)用的演進(jìn)建議如果只是自己使用上面的腳本已經(jīng)足夠。但如果你希望把它打磨成一個(gè)更完善的小工具可以考慮以下方向方向說明圖標(biāo)化在菜單欄中顯示一個(gè)小圖標(biāo)用量接近閾值時(shí)圖標(biāo)變色閾值提醒用量超過一定數(shù)值時(shí)彈出系統(tǒng)通知跨設(shè)備統(tǒng)計(jì)通過自建的日志同步服務(wù)匯總多臺設(shè)備的用量配置化把日志目錄、刷新間隔、顯示格式放到配置文件中原生 Swift 重寫去掉 Python 依賴打包成獨(dú)立 app其中“閾值提醒”是最值得優(yōu)先實(shí)現(xiàn)的功能當(dāng)本地累計(jì) token 超過你設(shè)定的警戒線時(shí)用rumps.notification彈一個(gè)提示這樣你不需要一直盯著菜單欄也能在關(guān)鍵時(shí)刻收到提醒。9. 結(jié)語與可繼續(xù)優(yōu)化的方向本文從 Claude Code 的用量管理痛點(diǎn)出發(fā)帶大家完整實(shí)現(xiàn)了一個(gè)菜單欄用量小工具。核心知識點(diǎn)可以歸納為幾條Claude Code 的會話數(shù)據(jù)會以 JSONL 形式留在本地usage 字段包含輸入、輸出和緩存三類 tokenPython 的 rumps 庫可以快速創(chuàng)建菜單欄應(yīng)用LaunchAgent 可以讓腳本開機(jī)自啟。如果你正在高頻使用 Claude Code建議先把這個(gè)小工具跑起來觀察一兩天的數(shù)據(jù)變化你會對自己的真實(shí)消耗速度有一個(gè)更具體的感知。在此基礎(chǔ)上再決定是否需要做閾值提醒、跨設(shè)備統(tǒng)計(jì)或原生應(yīng)用封裝。下一步值得探索的方向是了解 Claude 官方接口中的 usage 字段在不同模型下的差異以及如何在更長的時(shí)間維度上做用量趨勢可視化。把“能看到今天的用量”升級為“能預(yù)測未來幾小時(shí)會不會超限”才是這類小工具真正的進(jìn)階價(jià)值。