把Claude用量放进macOS菜单栏:一个可以完整读完的小工具
2026/8/29 1:38:39 网站建设 项目流程

在 Claude API 和 Claude Code 的使用逐渐进入日常开发后,一个高频问题开始浮现:想看当前用量总要先打开浏览器、登录控制台、找到用量页面,再等图表加载。如果只是每周看一眼还好,一旦每天大量调用 API 或长时间使用 Claude Code,这种“打开网页才能看到用量”的方式就会明显打断节奏。这个标题为 “Show HN: A Claude usage menu bar small enough to read before you run it” 的项目,正是针对这个场景出现的:把 Claude 用量放到 macOS 菜单栏,让开发者随时瞄一眼就知道今天的输入输出 token、请求数大概处于什么水平。

更值得注意的不是“菜单栏展示”这个结果,而是标题后半句 “small enough to read before you run it”。这句话的意思是:这个工具足够小,你可以在运行它之前把代码完整读一遍。这是一个非常重要的工程信号,意味着项目追求代码量小、行为透明、没有黑盒逻辑。本文不讨论某个闭源成品,而是把这类工具的完整实现思路拆开讲清楚,并提供一个可以自行跑通的最小版本,包含数据层、菜单栏展示层、常见报错和上线前的检查清单。

1. 先理解这类菜单栏工具到底在解决什么问题

1.1 用量查看的现状,为什么菜单栏更有优势

Claude 用量信息通常散落在不同地方。如果用官方 API,响应里会返回input_tokensoutput_tokenscache_creationcache_read等字段;如果用 Claude Code,会话过程中也会消耗 token;如果想看账号级别的聚合数据,则需要到控制台的用量页面或通过管理类接口获取。

问题在于,这些数据没有一个“统一入口”能让开发者日常零成本查看。浏览器的控制台页面适合做周报,但不适合高频查看。菜单栏应用的优势是常驻、轻量、无需打开浏览器,鼠标移过去就能看到数据。对写代码的人来说,这是把“监控”从主动查询变成被动显示,减少了上下文切换。

1.2 “small enough to read before you run it” 到底指什么

这句标题不是单纯强调代码行数少,它背后有三层含义:

第一层是代码可读性。一个工具如果只有几十到几百行,开发者可以快速理解它的入口、数据源、刷新逻辑和退出方式。第二层是安全透明。工具需要读取 API Key 或本地凭据,如果代码量小,用户就能确认数据发往哪里、有没有其他外部请求,避免闭源工具偷偷上传信息。第三层是维护成本低。小工具出问题时,日志和堆栈一眼就能看完,不需要借助复杂的调试链路。

这也是开源小工具最常见的价值体现:它不追求功能大而全,而是把“一个场景、一个入口、一个显示”做到足够清晰。

1.3 适合哪些人,以及使用前提

这个工具适合三类人:

  • 使用 Anthropic API 做应用的开发者,需要关注 token 消耗和成本。
  • 高频使用 Claude Code 的开发者,希望快速估算当天消耗。
  • 管理多个工作区或账号的团队成员,希望用一个统一视图观察用量趋势。

前提是需要有一个可以读取用量数据的来源。没有数据源,菜单栏 UI 就只是一个空壳。所以在实现之前,第一步不是写界面,而是确认“数据从哪来、认证怎么解决、刷新频率怎么控制”。

2. 环境准备:先把 Claude 本机环境跑通

2.1 学习环境与生产环境的最低要求

如果你只是想把菜单栏工具在自己的机器上跑起来,环境要求并不高:

项目学习环境要求生产环境建议
操作系统macOS 13 或更高macOS 13 或更高,且固定发布版本
Claude 凭据有 Anthropic API Key 或 Claude Code 已登录使用权限受限的只读 Key
开发工具Xcode 15+ 或 Node.js 18+建议使用稳定版 Xcode 和 Node.js LTS
网络能正常访问 Anthropic API需要稳定的网络和监控告警

在普通开发机上,先不要追求复杂架构。用本地 JSON 文件作为临时数据源,先让菜单栏 UI 跑通,再逐步把真实数据接入。

2.2 安装 Claude Code 的常见检查点

虽然菜单栏工具不一定依赖 Claude Code,但如果你计划统计 Claude Code 的消耗,建议先把 Claude Code 本机命令安装正确。官方最常用的安装命令是:

npm install -g @anthropic-ai/claude-code

安装完成后用以下命令验证:

claude --version

如果命令能正常输出版本号,说明全局路径已经配置好。首次使用时,还需要完成账号登录,登录后 Claude Code 会在本机保存凭据,后续调用会复用这套身份。

2.3 安装过程中最常见的四类报错

基于大量用户反馈和我自己的排查经验,以下四类报错出现频率最高:

错误现象常见原因检查方式处理建议
claude : 无法将“claude”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。claude' 不是内部或外部命令npm 全局 bin 目录没有加入 PATH,或安装未成功执行npm config get prefix,查看全局安装路径%AppData%\npm$(npm prefix)/bin加入 PATH,重新打开终端
error: claude native binary not installed. either postinstall did not runnpm 安装时 postinstall 脚本未执行,常见于权限不足或安装源异常查看 npm 安装日志,确认 install 脚本是否运行清理 node_modules 缓存后重新安装,确认 npm 没有关闭ignore-scripts
unfortunately, claude is not available to new users right now当前账号或所在区域不在服务开放范围内查看官方服务的区域和账号说明以官方当前开放状态为准,不要在受限环境下寻找规避方案
connection dropped (econnreset) · retrying in 3s · attempt 4/1网络连接不稳定,或本地网络环境干扰长连接ping和普通 curl 测试基础连通性调整网络环境后重试;若持续失败,检查本地网络配置

注意:安装报错必须先看完整日志,再看命令返回码。很多问题并不是命令写错,而是路径、权限或网络导致安装脚本中途失败。

2.4 获得用量数据的前置条件

要显示用量,至少需要一种数据来源:

  • 方式一:使用 Anthropic API 的调用记录,在每次 API 响应中提取usage字段并累加。
  • 方式二:使用控制台页面或管理类接口提供的聚合用量。
  • 方式三:使用 Claude Code 的日志和本地缓存来估算 token 消耗。

如果你是独立开发者,方式一最可控,因为数据完全由自己的请求产生。方式二适合查看账号级汇总,但具体接口结构会随官方版本变化,落地前需要确认当前文档。方式三的优点是无需额外鉴权,但字段和日志路径可能随 Claude Code 版本变化,适合做估算而不是精确统计。

3. 设计一个清晰的用量读取与展示流程

3.1 数据层与 UI 层要解耦

菜单栏小工具最容易犯的错误,是把网络请求、数据解析、界面刷新全部写在一个文件里。项目称为 “small enough to read”,恰恰说明它应该保持职责分离。

推荐的分层方式:

  • 数据采集脚本:负责从 API 或日志读取数据,输出统一格式的 JSON 文件。
  • 菜单栏应用:只读取 JSON 文件,负责展示和交互。
  • 配置文件:控制刷新间隔、API 地址、显示格式等。

这样做的好处很明显:数据采集脚本可以单独测试,菜单栏 UI 可以用样例数据先跑通,真实环境切换时不需要改 UI 代码。例如统一输出文件路径可以设为~/claude-usage.json,结构如下:

{ "updatedAt": "2025-06-01T10:30:00Z", "today": { "inputTokens": 1250000, "outputTokens": 380000, "cacheReadTokens": 900000, "cacheCreationTokens": 12000, "requests": 327 } }

这个 JSON 既包含更新时间,又包含当天累计数据。菜单栏 UI 只需要读取、解码、显示三步,逻辑非常容易理解。

3.2 两种数据源的选型建议

需求推荐数据源理由
只看当前项目的成本趋势本地统计 API 响应中的 usage 字段精确到每次请求,数据完全可控
查看账号每日汇总控制台或管理类接口适合做整体报表,但需要额外鉴权
统计 Claude Code 消耗Claude Code 日志与本地记录无需自己调用 API,但字段可能随版本变化
做成团队共享面板管理类接口 + 服务端缓存避免每台机器频繁请求上游接口

选型时还要考虑一个现实问题:API 响应中的 usage 字段只能统计本机发出的请求,如果你有多台机器或多个用户,单机统计会漏数据。账号级聚合更适合这种场景。

3.3 菜单栏显示信息的设计原则

菜单栏空间很有限,不能把大段文字直接塞进去。合理的显示方式是这样:

  • 菜单栏主标题只显示最核心的两个数字,例如C 1.25M / 0.38M,表示输入和输出 token。
  • 下拉窗口显示更多细节,包括请求数、缓存命中、更新时间。
  • 提供“刷新”“打开控制台”“退出”三个操作。

在 UI 设计上,要避免菜单栏标题太长。如果单日输入 token 达到百万级别,可以用缩写格式,例如1.2M而不是1250000

3.4 刷新策略:轮询频率不能太激进

菜单栏工具的刷新频率需要平衡实时性和资源占用。常见的策略是:

  • 初始化时立即刷新一次。
  • 之后每 60 秒读取一次本地 JSON 文件。
  • 如果数据源是远程 API,不要放在 UI 主线程同步请求,建议在后台任务中异步完成。
  • 请求失败时保留上一次成功数据,并在 UI 上标记 “stale”,而不是直接清空显示。

这种策略能保证用户在任何时刻打开菜单栏都有数据可看,同时避免高频请求触发限流。

4. 最小实现第一步:用脚本把数据整理成 JSON

4.1 一个可读性极高的 Node 脚本示例

在没有拿到原项目源码的情况下,这里给出一个通用实现思路。数据采集脚本的职责是:读取真实用量数据,整理成统一 JSON 文件。下面这个脚本先演示如何生成结构:

#!/usr/bin/env node // fetch-claude-usage.js const fs = require('fs'); const path = require('path'); function buildUsageRecord() { // 在真实项目中,这里应该从 Claude API 或日志读取数据。 // 此处使用示例值,主要演示数据结构。 const inputTokens = 1250000; const outputTokens = 380000; const requests = 327; return { updatedAt: new Date().toISOString(), today: { inputTokens, outputTokens, requests } }; } const outPath = path.join(process.env.HOME, 'claude-usage.json'); fs.writeFileSync(outPath, JSON.stringify(buildUsageRecord(), null, 2)); console.log('written to', outPath);

运行方式:

node fetch-claude-usage.js

运行后,会在用户根目录生成claude-usage.json。后面的菜单栏 UI 不需要关心这个脚本内部如何取数,只需要读取 JSON。这种解耦方式让整个工具保持“小到可以读完”的状态。

4.2 接入真实 API 时应该注意什么

如果要接入真实 API,代码结构可以扩展为:

async function fetchUsage() { const apiKey = process.env.ANTHROPIC_API_KEY; const url = process.env.CLAUDE_USAGE_API_URL; if (!apiKey || !url) { throw new Error('请先设置 ANTHROPIC_API_KEY 和 CLAUDE_USAGE_API_URL'); } const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } }); if (!res.ok) { throw new Error(`usage API error: ${res.status}`); } return await res.json(); }

这段代码不包含具体端点地址,因为不同账号和版本的接口结构变化较大。落地前要先确认官方文档中的认证方式、请求路径和返回字段,然后把返回结果映射成上面统一的 JSON 结构。

注意:不要把 API Key 写死在脚本里。建议从环境变量读取,或者使用系统钥匙串。菜单栏应用本身要展示数据,但不应该成为泄漏密钥的入口。

4.3 用样例数据验证 UI 的最佳姿势

在没有真实 API Key 之前,可以直接手动创建~/claude-usage.json,放入几组数字。这样菜单栏应用在开发阶段也能完整跑通,不会因为拿不到真实数据而卡住。

cat > ~/claude-usage.json <<'EOF' { "updatedAt": "2025-06-01T10:30:00Z", "today": { "inputTokens": 1250000, "outputTokens": 380000, "cacheReadTokens": 900000, "cacheCreationTokens": 12000, "requests": 327 } } EOF

这个文件就是整个菜单栏 UI 的“测试桩”。等真实采集脚本写好后,只需要把同样的 JSON 结构输出到同一个路径,UI 代码完全不用改。

5. 用 SwiftUI 实现菜单栏展示层

5.1 为什么选择 SwiftUI 的 MenuBarExtra

在 macOS 13 及以上版本,SwiftUI 提供了原生的MenuBarExtra场景,用于创建菜单栏常驻应用。它比传统 AppKit 的NSStatusBar写法更简洁,也比 Electron 方案轻量得多。对一个 “small enough to read before you run it” 项目来说,用 SwiftUI 能最大程度控制代码量。

创建 Xcode 项目时,选择 macOS App,然后在App入口中把主场景替换为MenuBarExtra。下面是完整的最小示例:

import SwiftUI import AppKit @main struct ClaudeUsageMenuBarApp: App { var body: some Scene { MenuBarExtra { UsageView() } label: { Label("C", systemImage: "chart.bar") } .menuBarExtraStyle(.window) } }

这段代码声明了一个菜单栏应用:点击菜单栏图标后,会弹出一个小窗口,窗口内容是UsageView

5.2 展示用量信息的主视图

UsageView负责展示数据,并提供刷新、打开控制台、退出三个操作:

struct UsageView: View { @StateObject private var viewModel = UsageViewModel() var body: some View { VStack(alignment: .leading, spacing: 8) { Text("Claude 用量") .font(.headline) Divider() Text("今日请求数:\(viewModel.usage?.requests ?? 0)") Text("输入 tokens:\(viewModel.usage?.inputTokens ?? 0)") Text("输出 tokens:\(viewModel.usage?.outputTokens ?? 0)") Divider() HStack { Button("刷新") { viewModel.refresh() } Button("打开控制台") { viewModel.openConsole() } Spacer() Button("退出") { NSApplication.shared.terminate(nil) } } } .padding() .frame(width: 280) } }

这里用@StateObject管理 ViewModel,视图只做声明式展示。如果后续要增加图表、颜色标识或告警状态,只需要在视图层扩展。

5.3 读取 JSON 与定时刷新

UsageViewModel是整个 UI 层的核心,读文件、解析、定时刷新都在这里:

struct UsageRecord: Decodable { let updatedAt: String let today: DailyUsage } struct DailyUsage: Decodable { let inputTokens: Int let outputTokens: Int let cacheReadTokens: Int? let cacheCreationTokens: Int? let requests: Int } final class UsageViewModel: ObservableObject { @Published var usage: UsageRecord? private let usageURL = URL(fileURLWithPath: NSString("~/claude-usage.json").expandingTildeInPath) init() { refresh() Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in self.refresh() } } func refresh() { guard let data = try? Data(contentsOf: usageURL) else { return } let decoder = JSONDecoder() if let record = try? decoder.decode(UsageRecord.self, from: data) { DispatchQueue.main.async { self.usage = record } } } func openConsole() { // 控制台地址以实际账号所在环境为准 if let url = URL(string: "https://console.anthropic.com/") { NSWorkspace.shared.open(url) } } }

这个 ViewModel 在 60 秒间隔内读取本地 JSON 文件,解析成功后更新@Published属性。由于读取的是本地文件,操作非常快,不会阻塞主线程。

5.4 运行与验证方法

在 Xcode 中运行项目后,菜单栏会立即出现一个柱状图标。点击后弹出窗口,应该能看到~/claude-usage.json中的数据。

验证路径可以按顺序检查:

  1. 菜单栏是否出现图标。
  2. 点击图标后窗口是否正常弹出。
  3. 窗口里的数字是否和 JSON 文件一致。
  4. 修改 JSON 文件中的数字,等待最多 60 秒,确认界面会自动更新。
  5. 删除 JSON 文件,确认应用不会崩溃,而是继续显示上一次缓存数据。

如果第 3 步数据不一致,优先检查 JSON 字段名是否与DailyUsage完全匹配。Swift 的Decodable对字段名大小写敏感,错一个字段就会导致整次解析失败。

6. 更轻量的替代方案:xbar 脚本式菜单栏

6.1 xbar 的思路:菜单栏只显示脚本输出

如果不想为这么小的工具维护一个 Xcode 工程,可以考虑 xbar 这类菜单栏脚本工具。xbar 的做法是把一个可执行脚本放在固定插件目录,脚本的stdout会直接变成菜单栏文字。脚本每运行一次,菜单栏就刷新一次。

这个方案极其适合 Claude usage 场景,因为整个“工具”可以只用一个 Python 脚本实现,完全满足 “small enough to read before you run it”。

6.2 一个 Python 脚本示例

把下面的脚本保存为claude-usage.10s.py,放到 xbar 插件目录,并赋予可执行权限:

#!/usr/bin/env python3 import json import os from pathlib import Path usage_file = Path(os.path.expanduser("~/claude-usage.json")) if not usage_file.exists(): print("C: no data") print("---") print("未找到用量文件") raise SystemExit(0) data = json.loads(usage_file.read_text()) today = data.get("today", {}) input_tokens = today.get("inputTokens", 0) output_tokens = today.get("outputTokens", 0) print(f"C {input_tokens / 1000:.1f}k / {output_tokens / 1000:.1f}k") print("---") print(f"今日请求数: {today.get('requests', 0)}") print(f"更新时间: {data.get('updatedAt', 'unknown')}")

文件名中的.10s.py是 xbar 的刷新约定:10s表示每 10 秒运行一次,py表示用 Python 执行。运行之后,菜单栏会直接显示类似C 1250.0k / 380.0k的文本,点击后展开详情。

6.3 方案对比:SwiftUI、xbar 与 Electron 类方案

方案代码量构建成本依赖适用场景
SwiftUI MenuBarExtra中等需要 Xcode 编译macOS 13+想做成正式菜单栏应用
xbar 脚本很少无编译,直接放脚本xbar、Python快速验证、个人监控
Electron/Tauri高,依赖 Node/Rust跨平台框架需要复杂 UI 或跨平台发布

从“可读性优先”的角度看,xbar 方式最贴近项目标题的描述:一个脚本就是全部逻辑,用户可以在运行前完整读完。SwiftUI 方案适合后续扩展,比如要做通知、图表、多账号切换。

7. 常见问题与排查路径

7.1 菜单栏图标不出现或点击无反应

问题现象常见原因检查方式处理建议
运行后菜单栏没有图标macOS 版本低于 13,MenuBarExtra 不可用打开“关于本机”查看系统版本升级系统,或改用 xbar 方案
点击图标后窗口一闪而过.window 样式下窗口未正确加载查看 Xcode 控制台日志检查 View 是否包含强制解包逻辑
运行时直接被系统拦截自编译应用未签名查看系统弹窗在系统设置中允许运行,或进行开发者签名

7.2 数据显示为 0 或完全不刷新

这类问题集中在数据层。排查顺序是:先确认 JSON 文件存在,再确认字段名一致,最后确认刷新逻辑执行。

ls -l ~/claude-usage.json cat ~/claude-usage.json

如果文件存在但 UI 仍为 0,很可能是Decodable解析失败。建议在 ViewModel 里加一行打印,把解码错误输出到日志:

do { let record = try decoder.decode(UsageRecord.self, from: data) DispatchQueue.main.async { self.usage = record } } catch { print("decode error: \(error)") }

如果文件不存在,说明数据采集脚本没有执行成功。先单独运行脚本,确认脚本能输出 JSON 后再回头排查 UI。

7.3 数据采集脚本或 API 返回认证错误

如果使用真实 API,401 Unauthorized是最常见的错误。这时要检查三个点:

  • 环境变量ANTHROPIC_API_KEY是否设置正确。
  • 当前 Key 是否拥有读取用量数据的权限。
  • 请求地址是否与账号所在区域匹配。

如果使用 Claude Code 的本地身份,则要检查本机登录状态是否过期。可以重新执行 Claude Code 的登录流程,然后再运行采集脚本。

7.4 Claude Code 安装阶段残留问题

在菜单栏工具之前,很多用户会先被 Claude Code 的安装问题卡住。这里把最典型的场景列全:

问题现象常见原因处理建议
claude : 无法将“claude”项识别为 cmdletnpm 全局路径不在 PATH找到 npm 全局 bin 目录并加入 PATH
error: claude native binary not installedpostinstall 脚本未执行清理缓存后重装,并检查 prefer-offline 等 npm 配置
your organization has disabled claude subscription access组织策略限制联系组织管理员确认订阅权限
"deepseek-v4-pro" is not a model this version of claude code recognizes配置了当前版本不认识的模型名检查模型名和 Claude Code 版本是否匹配

排查时不要只看错误码,还要看错误发生的阶段。安装阶段错误优先检查 npm 和网络,登录阶段错误优先检查账号权限,运行阶段错误优先检查模型配置和网络连接。

7.5 本地网络不稳定导致请求重试

收集到ECONNRESETconnection dropped时,Claude Code 会显示重试提示。此时不要反复重装,先确认网络基础连通性:

curl -I https://api.anthropic.com

如果连通失败,应从网络设备、DNS、本地防火墙等方向排查。如果只是偶发的长连接断开,正常重试即可。

8. 最佳实践与扩展方向

8.1 发布前检查清单

把一个菜单栏小工具给其他人使用之前,建议按这份清单逐项检查:

  • [ ] API Key 没有硬编码在源码或配置文件里。
  • [ ] 应用只发起当前数据源必需的网络请求。
  • [ ] 本地 JSON 文件的权限不是全局可读。
  • [ ] 刷新失败时保留上次数据,并显示更新时间。
  • [ ] 日志输出不包含完整 Key 和敏感请求体。
  • [ ] 已确认目标 macOS 版本兼容性。
  • [ ] 退出按钮会真正结束进程,而不是隐藏到后台。
  • [ ] 没有依赖会随时间失效的硬编码路径。

其中最关键的一条是“失败时保留上次数据”。菜单栏工具的典型使用场景是长时间挂着,如果某次刷新生效瞬时网络异常就把界面清空,体验会非常差。

8.2 生产环境还需要考虑什么

如果只是个人使用,一个 SwiftUI 应用或 xbar 脚本已经足够。但当你想让团队一起使用时,就要补上几件事:

  • 配置外置化:API 地址、刷新间隔、显示格式不要写在代码里,用配置文件或环境变量维护。
  • 日志与监控:记录刷新成功、失败、耗时,方便远端排查。
  • 权限分级:尽量使用只读 Key,不要把写权限和账号管理权限暴露给本机脚本。
  • 多用户兼容:不同用户的家目录路径不同,不要写死绝对路径。
  • 自动更新:如果分发为 App,需要签名、公证和更新通道;如果只是脚本,建议在脚本里加入版本自检。

8.3 可以继续扩展的方向

这个工具的扩展空间很大,但每次扩展都要回到“small enough to read”的原则,不要一次性堆叠太多功能。值得做的方向包括:

  • 预算告警:当今日 token 消耗超过阈值时,用系统通知提醒。
  • 多账号支持:在菜单栏切换不同账号的用量。
  • 按项目统计:结合 Claude Code 的会话记录,拆分不同目录的消耗。
  • 历史趋势:在本地保存最近 30 天的用量,生成简单趋势图。
  • 导出报表:把月度用量导出成 CSV,方便和财务对账。

这些方向里,预算告警的价值最高。因为多数开发者不是不知道用量,而是忘记去看。菜单栏展示解决了“看”的便利性,通知则解决“忘”的问题。

8.4 给新手的实践建议

如果你想亲手实现一个类似工具,建议按这个顺序推进:

  1. 先用脚本读一次 API 响应,打印出usage字段,理解数据长什么样。
  2. 把数据整理成统一 JSON 文件,确保脚本能独立运行。
  3. 用样例 JSON 跑通菜单栏 UI。
  4. 接入真实数据源,替换脚本中的模拟数据。
  5. 加入定时刷新、失败保留、日志输出。
  6. 最后再加通知、图表等扩展功能。

不要在第一步就直接去写菜单栏 UI。先解决“数据从哪来”,再解决“数据怎么显示”,整个开发过程会顺利很多。保持代码量小不是偷懒,而是让工具在面对不确定的 API 变化和系统环境时,仍然可以被快速理解和修复。对这类菜单栏小工具来说,可读性本身就是一种维护性和安全性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询