
最近不少用 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 秒看一眼那个小图标不需要打开任何页面不需要输入任何命令你对“今天还能不能高强度使用”就有了一个清晰判断。从技术实现角度看这个项目也做了一个很好的示范不是所有工具都需要复杂的后台、炫酷的界面。一个常驻菜单栏的应用用极简的信息设计配合合理的刷新策略就能产生非常实用的价值。如果你也经常被用量问题打断完全可以按本文的思路自己实现一个适合自己需求的菜单栏用量监控工具。先从最小可用版本开始跑通数据获取和状态展示再逐步增加刷新策略和视觉反馈。整个过程不需要太复杂的架构两三个文件就能跑起来。真正重要的是把这个工具放在“你每次运行前都会看的位置”这个产品决策。工具本身的代码量不大但这个设计判断决定了它好不好用。