最近不少用 Claude Code 和 Claude API 做开发的朋友,都碰到过一个非常尴尬的场景:代码写到一半,模型突然停下来,不是网络问题,也不是代码问题,而是用量额度耗尽了。轻则换一个模型再跑,重则整个任务中断,上下文全部重新来过。更难受的是,这种打断往往发生在你最不想被打断的时候。
这个项目的核心出发点其实特别朴素:与其让你在运行之后才发现用量不够,不如让你在运行之前就一眼看到现状。
这就是标题里那句 “small enough to read before you run it” 的真实含义——做一个菜单栏小工具,把 Claude 用量放在你每次运行之前都必须扫一眼的位置。
这篇文章我会从实际开发痛点出发,拆解这个菜单栏小工具为什么值得关注,它解决了什么问题,以及如果你想自己动手做一个类似的 Claude usage 菜单栏工具,完整的实现思路和示例代码是什么。
1. 为什么“运行前看用量”比“运行中看日志”更靠谱
先说说我观察到的普遍痛点。
很多 Claude Code 用户,尤其是重度用户,对用量管理其实处于一种“被动挨打”的状态。日常流程通常是这样的:打开终端,启动 Claude Code,输入请求,模型开始响应,然后你专注地沉浸在工作流里。直到某一次输出突然被中断,你才意识到——配额用完了。
这个问题的本质不是“Claude 不够强”,而是“用量信息没有出现在正确的信息层级里”。
代码写成什么样、上下文窗口还有多大、模型是否正在思考,这些信息在终端里都有反馈。但“我这个月还能用多少量”“今天还剩多少请求数”,这类信息往往藏得很深,要么在网页后台,要么在某个查询命令里,需要你主动去查才能看到。
菜单栏为什么是个好位置?因为它是 macOS 用户视觉习惯里“永远固定”的区域。
你不需要打开浏览器,不需要输入命令,甚至不需要把注意力从当前窗口移开,只需要微微抬头,就能看到当前用量状态。这种“低干扰、高频可见”的特性,正是用量监控工具最需要的。
用一句话来判断:如果你需要一个工具来提醒你“还剩多少”,那它就应该出现在你每次开始任务之前那个必然经过的位置上。
这个项目选择菜单栏,本质上做的是一个“信息可达性”优化,而不是“功能堆叠”。它没有去造一个新的管理后台,而是把你已经需要的信息,放到你最容易看到的地方。
2. 基础概念:Claude 用量到底在“计量”什么
在动手实现之前,有必要先把“用量”这个概念说清楚。
这里的 “usage” 并不是一个简单的计数,而是由多层信息构成的:
2.1 订阅制下的用量
如果你使用的是 Claude Pro 或 Claude Team 这类订阅方案,用量通常体现在一定时间窗口内的消息数上限,或者特定时间段内的请求频率限制。订阅方案更偏向“人”的维度,因为使用者是自然语言交互为主,消耗速度不会像编程工具那么快。
2.2 API 模式下的用量
当你通过 API 使用 Claude 模型时,计费维度是 token——更准确地说,是输入 token 和输出 token 分别计费。这也是 Claude Code 这类编程工具最主要的计费方式。
这里有一个很容易被忽略的事实:Claude Code 在运行过程中,每一次交互都包含多轮 token 消耗。模型需要读取你的代码上下文、工具调用结果、历史对话,这些都属于输入 token;生成的代码、解释、分析结果,则属于输出 token。一个复杂的重构任务,消耗的 token 数量往往远超你的直观预期。
2.3 用量信息的核心维度
所以,一个称职的 Claude usage 菜单栏工具,至少应该展示以下信息:
| 信息维度 | 作用 | 关键程度 |
|---|---|---|
| 剩余量 | 当前可用的配额或余额 | 极高 |
| 已用量 | 已经消耗的总量 | 高 |
| 计费周期 | 用量是按月、按周还是按天重置 | 高 |
| 速率限制 | 当前距离限流阈值还有多少缓冲 | 中 |
明白了这些,你再看菜单栏工具的价值就清楚了:它把多重信息浓缩成“一眼能看懂”的视觉表达。一个数字、一个百分比、一个小色块,就能在运行前完成一次有效判断。
3. 环境准备与前置条件
如果你打算按下面的思路自己实现一个 Claude 用量监控菜单栏工具,需要先准备好相应的环境。
需要说明的是,版本信息请以你本机实际安装情况为准,本文重点演示通用实现思路,避免因为版本号过时导致误导。
3.1 基础软件环境
| 组件 | 作用 | 说明 |
|---|---|---|
| macOS 系统 | 菜单栏应用运行平台 | 建议使用较新的 macOS 版本,菜单栏 API 更稳定 |
| Xcode | 开发和编译 Swift 应用 | 包含 SwiftUI、AppKit 等框架 |
| Swift 5.7+ | 编程语言 | 用于编写菜单栏应用 |
| Claude 账户 | 获取用量数据 | 订阅账户或 API 账户均可 |
| Claude API Key | 调用用量查询接口 | API 模式下必填 |
3.2 理解菜单栏应用的技术底座
macOS 的菜单栏应用,技术上有两个经典方案:
- AppKit + NSStatusItem:老牌方案,灵活度高,控制精细,适合自定义程度较高的工具。
- SwiftUI + MenuBarExtra:较新的方案,代码更简洁,开发效率高,适合快速实现。
菜单栏应用和普通窗口应用最大的区别在于:它没有传统的 Dock 图标和主窗口,而是依靠 NSStatusItem 或 MenuBarExtra 在系统菜单栏绘制一个小图标。点击图标后,可以弹出一个菜单或一个小型面板。
这种应用形态,先天就是为“常驻 + 快速查看”设计的,非常适合做用量监控。
4. 核心设计思路拆解
在写代码之前,先把设计思路理清楚。这个工具虽然小,但涉及几个决定用户体验的关键决策。
4.1 信息层级要分主次
菜单栏空间极其有限,你不能把一堆数字都塞进去。合理的做法是:
- 常驻显示:一个极简的状态摘要,比如剩余百分比。
- 点击展开:完整的用量明细,包括已用量、周期重置时间、速率限制等。
这个设计原则来自一个基本事实:你 90% 的时候只需要知道“够不够用”,只有 10% 的时候需要知道“具体用了多少”。
4.2 刷新策略要克制
用量数据不是实时的,也不是越高频越好。
请求频率过高,一方面会消耗 API 配额本身,另一方面可能触发速率限制,反而影响正常使用。更合理的方案是:
- 应用启动时刷新一次。
- 每隔 5 到 10 分钟自动刷新一次。
- 用户手动点击菜单栏图标时刷新一次。
- 在当前用量接近阈值时,提高刷新频率。
这一点是这个工具真正容易踩坑的地方。很多人第一次做这类工具时,会把刷新周期设置得很激进,结果工具本身变成了新的“配额消耗源”。
4.3 视觉反馈要提前于“不可用”状态
真正好用的用量监控,不是在你已经用完之后才变红,而是在你还剩 20%、30% 的时候,就用颜色或文案提示你“快不够了”。
所以,合理的状态分层应该是:
- 绿色:用量充足。
- 黄色:用量剩余不足 30%,需要留意。
- 红色:用量剩余不足 10%,很快会耗尽。
- 灰色:查询失败或数据不可用。
这样你在运行 Claude Code 之前扫一眼菜单栏,就能立刻做出判断:是继续干,还是先省着点用。
5. 完整示例:Swift 实现 Claude Usage 菜单栏工具
这一节我们通过一个最小可用的示例代码,演示如何实现一个菜单栏用量监控工具。
以下代码基于 SwiftUI 的MenuBarExtra实现,配合同步的用量数据管理器,可以快速跑通主流程。
5.1 创建项目结构
建议在 Xcode 中新建一个 macOS App 项目,然后按照以下路径创建文件:
ClaudeUsageBar/ ├── ClaudeUsageBarApp.swift // 应用入口 ├── UsageManager.swift // 用量数据管理与刷新 ├── UsageMenuView.swift // 菜单栏视图与弹窗内容 └── Info.plist // 基础配置5.2 用量数据模型
首先定义一个数据模型,用来描述用量信息。
// 文件路径:ClaudeUsageBar/UsageManager.swift import Foundation struct ClaudeUsage: Codable { let totalLimit: Double // 周期内总配额 let usedAmount: Double // 已用量 let remainingAmount: Double // 剩余量 let resetDate: Date? // 重置时间 var remainingPercent: Double { guard totalLimit > 0 else { return 0 } return (remainingAmount / totalLimit) * 100 } }这里把用量数据抽象成总量、已用量、剩余量和重置时间四个核心字段。实际对接哪个渠道,取决于你的账户类型和可用的数据源,这个模型不绑定具体实现。
5.3 用量管理核心
接下来是核心的管理器,负责异步获取用量数据,并通过@Published属性驱动 UI 更新。
// 文件路径:ClaudeUsageBar/UsageManager.swift import SwiftUI import Combine @MainActor final class UsageManager: ObservableObject { @Published var usage: ClaudeUsage? @Published var isLoading = false @Published var lastError: String? private var timer: Timer? func startMonitoring() { Task { await refreshUsage() } startTimer() } func refreshUsage() async { isLoading = true defer { isLoading = false } do { // 这里通过 URLSession 请求用量接口 // 具体端点根据账户渠道而定 let usage = try await fetchUsageFromAPI() self.usage = usage self.lastError = nil } catch { self.lastError = error.localizedDescription } } private func startTimer() { // 默认每 10 分钟刷新一次,贴近使用时可以缩短间隔 timer?.invalidate() timer = Timer.scheduledTimer(withTimeInterval: 600, repeats: true) { [weak self] _ in Task { [weak self] in await self?.refreshUsage() } } } private func fetchUsageFromAPI() async throws -> ClaudeUsage { // 示例逻辑:构造请求并解码 // 注意:这里需要替换为你的真实用量查询端点 let url = URL(string: "https://api.example.com/claude/usage")! var request = URLRequest(url: url) request.setValue("Bearer YOUR_API_KEY", forHTTPHeaderField: "Authorization") let (data, _) = try await URLSession.shared.data(for: request) return try JSONDecoder().decode(ClaudeUsage.self, from: data) } }这段代码的核心逻辑有两点值得注意:
第一,通过@MainActor确保 UI 更新发生在主线程,避免并发问题。
第二,使用Timer做定时刷新,默认间隔为 600 秒。你可以在实际使用中根据需求调整,但建议不要低于 120 秒,否则频繁请求会带来不必要的消耗。
5.4 菜单栏视图
接下来是菜单栏视图的实现。这里需要区分“常驻显示的小图标”和“点击后展开的详情面板”两个部分。
// 文件路径:ClaudeUsageBar/UsageMenuView.swift import SwiftUI struct UsageMenuView: View { @ObservedObject var manager: UsageManager var body: some View { MenuBarExtra { VStack(alignment: .leading, spacing: 12) { if let usage = manager.usage { Text("Claude 用量概览") .font(.headline) ProgressView(value: usage.remainingPercent, total: 100) .progressViewStyle(.linear) HStack { Text("剩余量") Spacer() Text("\(usage.remainingAmount, specifier: "%.0f")") } .font(.subheadline) HStack { Text("已用量") Spacer() Text("\(usage.usedAmount, specifier: "%.0f")") } .font(.subheadline) HStack { Text("用量比例") Spacer() Text("\(usage.remainingPercent, specifier: "%.1f")%") } .font(.subheadline) if let resetDate = usage.resetDate { Text("重置时间:\(resetDate.formatted())") .font(.caption) .foregroundStyle(.secondary) } } else if manager.isLoading { ProgressView("正在加载用量信息...") } else { Text("暂无法获取用量信息") .foregroundStyle(.secondary) if let error = manager.lastError { Text(error) .font(.caption) .foregroundStyle(.red) } } Divider() Button("立即刷新") { Task { await manager.refreshUsage() } } Button("退出") { NSApplication.shared.terminate(nil) } } .padding() .frame(width: 260) } label: { // 常驻菜单栏的极简标 Image(systemName: statusIconName) .foregroundStyle(statusColor) } } private var statusIconName: String { guard let usage = manager.usage else { return "gauge.with.dots.needle.33percent" } if usage.remainingPercent < 10 { return "exclamationmark.triangle.fill" } else if usage.remainingPercent < 30 { return "gauge.with.dots.needle.50percent" } else { return "gauge.with.dots.needle.100percent" } } private var statusColor: Color { guard let usage = manager.usage else { return .gray } if usage.remainingPercent < 10 { return .red } else if usage.remainingPercent < 30 { return .yellow } else { return .green } } }这段代码把视觉反馈逻辑集中在了两个计算属性中:图标和颜色。当剩余量低于 30% 时,图标变成带警示的样式;低于 10% 时,变成明显的三角警告,颜色也从绿色过渡到黄色再到红色。
这就是“运行前一眼判断”的核心体验。
5.5 应用入口
最后是应用入口,负责组装依赖并启动监控。
// 文件路径:ClaudeUsageBar/ClaudeUsageBarApp.swift import SwiftUI @main struct ClaudeUsageBarApp: App { @StateObject private var usageManager = UsageManager() var body: some Scene { MenuBarExtra("Claude Usage", systemImage: "gauge.with.dots.needle.100percent") { UsageMenuView(manager: usageManager) } } }注意:这里通过@StateObject持有UsageManager,并在MenuBarExtra的content中传入视图。实际启动时,还需要在合适的位置调用usageManager.startMonitoring(),例如在 App 的init中,或者在UsageMenuView的.task修饰符中调用一次。
// 在 UsageMenuView.Body 中补充 .task { manager.startMonitoring() }这样应用启动后,就会自动进入监控模式,定期刷新用量数据。
6. 运行与验证
6.1 编译运行
在 Xcode 中打开项目,选择你的 Mac 作为运行目标,然后点击运行按钮,或者使用快捷键Cmd + R。
如果一切正常,你会看到菜单栏上出现一个仪表盘样式的图标。点击它,即可展开用量详情面板。
6.2 预期输出
正常运行时的预期效果如下:
- 菜单栏常驻图标颜色为绿色。
- 点击图标后弹出面板,显示剩余量、已用量、用量比例和重置时间。
- 每次点击面板中的“立即刷新”,数据都会更新。
如果当前用量低于 30%,菜单栏图标会变成黄色;低于 10%,则变成红色警告样式。
6.3 如何判断接入成功
判断标准非常简单:面板中是否有数据展示,以及数据刷新是否正常。
如果面板一直显示“暂无法获取用量信息”,优先检查两个地方:
- 网络请求是否返回了合法的 JSON。
- 数据模型中字段与接口返回字段是否一致。
在这里要特别提醒:上面的示例中fetchUsageFromAPI()使用了示例端点api.example.com,这不是真实可用的地址。你需要根据自己实际的数据来源来替换这一部分。
如果你的用量信息来自 Claude 官方后台页面,可以采用以下思路:
- 本地网页解析:通过授权方式获取用量页面的 HTML 或 API 响应,再解析出关键数字。
- 官方 API 查询:如果你拥有 Claude API 的访问权限,可以在控制台检查是否有用量相关的查询端点。
- 手动录入辅助:极端情况下,可以允许用户手动输入数字,工具只负责展示和提醒。
无论采用哪种方式,请确保你的接入方式符合平台使用条款,并且不涉及未授权的绕过行为。
7. 常见问题与排查方法
这部分内容结合了不少 Claude 使用者的高频问题,整理成表格供快速排查。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 菜单栏不显示图标 | 应用未正常运行 | 检查 Xcode 控制台输出 | 确认 App 入口中MenuBarExtra的配置正确 |
| 用量信息一直为空 | 接口地址错误或返回格式不匹配 | 在fetchUsageFromAPI中打印响应数据 | 核对数据模型中字段名与 JSON 键名一致 |
| 菜单栏图标颜色不变 | 刷新逻辑未触发 | 检查startMonitoring是否被调用 | 在视图.task中补上启动调用 |
| 刷新导致应用卡顿 | 网络请求阻塞了主线程 | 检查是否使用了异步方法 | 确保请求在async方法中执行 |
| 定时刷新不生效 | Timer 未正确保留 | 检查 timer 是否被释放 | 将 timer 持有在管理器中 |
| 弹出的菜单内容显示不全 | 窗口宽度不足 | 调整.frame(width:)参数 | 适当增加面板宽度 |
| Claude Code 提示配额不足 | 实际额度已耗尽 | 登录后台查看用量 | 优化请求策略或升级方案 |
| 模型请求被限流 | 单位时间内请求过多 | 查看错误状态码 | 增加请求间隔,错峰使用 |
这里重点说下“用量数据获取不到”这一问。
从项目标题看,这个工具的核心目标是“在运行前看清用量”,那么数据来源是绕不开的问题。如果你的用量数据来自订阅账户,Web 后台的展示逻辑和 API 返回的结构往往不同,直接把 HTML 当 JSON 解析会失败。
建议的做法是:
- 先用浏览器的开发者工具观察网络请求,找到加载用量数据时实际调用的接口。
- 确认接口的鉴权方式,通常是 Cookie 或 Token。
- 在本地工具中模拟同样的请求,解析 JSON 或 HTML 数据。
- 将解析逻辑封装在
UsageManager中,与 UI 解耦。
这个链路并不复杂,但需要耐心调试。
8. 最佳实践与工程建议
如果你不只满足于“跑通”,还想把这个工具做得更顺手、更稳妥,下面这些建议值得参考。
8.1 不要把刷新频率调得太高
用量监控工具本身也可能消耗资源。如果你通过 API 查询用量,而查询接口本身附带消耗,持续高频刷新就是雪上加霜。
一个合理的策略是:
- 默认 10 分钟刷新一次。
- 用量低于 30% 后,改为 5 分钟一次。
- 用量低于 10% 后,改为 1 分钟一次。
- 用户手动刷新时的间隔,不限制。
这种动态调整既能保证关键时期的信息及时性,又不会在用量充足时造成浪费。
8.2 用多级视觉反馈代替数字轰炸
菜单栏不是仪表盘面板,放不下太多数字。你应该花更多精力在设计状态的颜色和图标上,而不是把屏幕空间塞满。
简单说:你的工具要让用户在一秒内能做出判断,而不是考用户的瞬时记忆力。
8.3 注意隐私和 API Key 安全
用量工具需要访问你的账户数据,这里涉及安全边界问题。
几个建议:
- 不要把 API Key 硬编码到代码中。
- 优先使用系统钥匙串(Keychain)存储敏感信息。
- 日志中不要打印 token 或密钥。
- 发布工具时,避免把个人密钥提交到仓库。
如果要开源这个项目,更稳妥的方式是让用户在本地配置密钥,而不是直接嵌入。
8.4 支持多数据源是未来的方向
很多开发者可能同时使用多个 AI 编程工具,而不是只使用 Claude。如果你把自己的工具设计成“可插拔数据源”,将来接入其他模型时会更从容。
比如可以定义一个UsageProviding协议,让不同的服务商各自实现用量获取逻辑。主界面只依赖协议,不依赖具体实现。这样 Claude 的用量、其他模型的用量,可以在同一个菜单栏工具里统一展示。
8.5 做好失败提示
网络请求不是永远成功的。用量监控工具必须考虑网络不可用、服务端错误、认证失败这三类典型异常状态。
- 认证失败:提示用户重新配置 API Key。
- 网络不可用:保留上一次成功获取的用量数据,并标记“数据可能不是最新”。
- 服务端错误:重试一次,如果还失败,则等待下一个刷新周期。
一次性成功很容易,难的是在异常状态下依然保持体验正常。
9. 理解这个项目的核心价值
回到标题本身:“A Claude usage menu bar small enough to read before you run it”。
这个项目之所以值得关注,不是因为技术有多难,而是它用一个极度克制的设计,解决了一个非常真实的开发者体验问题。
用过 Claude Code 的人都知道,AI 编程助手在长时间任务中最大的不确定性,不是模型能力不够,而是“你永远不知道它还剩下多少力气”。一次意外的配额耗尽,可能让你丢掉的不仅是当前请求,还有一段复杂的上下文。重新来过的成本,远远超过那几十秒的等待。
菜单栏一个小图标的价值,本质上是在帮你把这种不确定性降到最低。在启动任务之前,你只需要花 0.5 秒看一眼那个小图标,不需要打开任何页面,不需要输入任何命令,你对“今天还能不能高强度使用”就有了一个清晰判断。
从技术实现角度看,这个项目也做了一个很好的示范:不是所有工具都需要复杂的后台、炫酷的界面。一个常驻菜单栏的应用,用极简的信息设计,配合合理的刷新策略,就能产生非常实用的价值。
如果你也经常被用量问题打断,完全可以按本文的思路,自己实现一个适合自己需求的菜单栏用量监控工具。先从最小可用版本开始,跑通数据获取和状态展示,再逐步增加刷新策略和视觉反馈。整个过程不需要太复杂的架构,两三个文件就能跑起来。
真正重要的,是把这个工具放在“你每次运行前都会看的位置”这个产品决策。工具本身的代码量不大,但这个设计判断,决定了它好不好用。