Skip to content

Repository files navigation

limitping

CI License: MIT

limitping 是一个面向 Codex 订阅的轻量命令行工具:查询 5 小时/每周用量与重置券, 并可使用 Codex CLI 当前可见的最低优先级模型发送一个最小 ping。它也可以把用量和 ping 状态推送到 Prometheus Pushgateway。

Important

这是非官方项目,与 OpenAI 无隶属或背书关系。用量接口属于未公开的 Codex 后端实现, 未来可能变化。codex exec 会消耗 token,也不保证一定启动新的订阅窗口。

致谢与项目定位

本项目大量代码、实现思路和产品灵感源于 wavever/CCLimitPing。特别感谢 wavever 开源了完整项目,并清晰梳理了 Codex 用量读取、 OAuth 刷新和窗口触发机制;没有这些工作,limitping 不会以现在的形式存在。

这个仓库不是 CCLimitPing 的完整替代品,而是针对个人自动化场景做的轻量、Codex-only 实现:

CCLimitPing 本项目 limitping
Provider Claude Code、Codex、Spark 仅 Codex
运行方式 手动、watch、schedule、后台常驻 只有 status / ping;配合 cron、LaunchAgent 或其他调度器运行
后台能力 内置 bg start/status/logs/stop、会话钩子 不启动后台进程,不管理守护服务
配置与功能面 配置文件、通知、续跑、兑换、升级等完整能力 尽量少的 flags,无独立配置文件
ping 方式 交互式官方 CLI codex exec headless 调用
可观测性 本地状态与日志 可选 Prometheus Pushgateway metrics,并记录最近成功 ping 时间

如果需要多 Provider、内置 watch/background、活跃会话检测或自动续跑,应优先使用 CCLimitPing;如果只需要一个可嵌入现有 cron/plist/监控体系的 Codex 小工具,本项目更合适。

功能

  • 显示 Codex 5 小时与每周剩余额度、重置时间和重置券。
  • --json 输出机器可读快照。
  • 从 codex debug models 动态选择最低优先级的可见模型。
  • --dry-run 在执行模型调用或推送指标前预览操作。
  • --if-5h-full 只在 5 小时额度恢复到 100% 时执行 ping;此时默认还会结合已配置的 cron 目标做相位对齐:仅在满额且到达对齐时间后才 ping(指标仍正常上报)。
  • --without-align 关闭相位对齐,只保留满额判断(满额即 ping);仅在配合 --if-5h-full 时有意义。不带任何 flag 时 ping 立即执行,与对齐无关。
  • --until-anchored 持续 ping 直到 5 小时窗口开始计时(被首次使用锚定):起始输入较大,每轮翻倍,每次 ping 后回读用量确认是否已计时,计时后立即停止;配合 --push-metric 时也会上报已配置 align 目标的未来计划。
  • align 子命令管理多条 cron 目标(每条带唯一 id 和自己的延时预算 max-delay,可按 id 单独删除),并预览未来的 ping/刷新时间。
  • 将用量、重置券数量和最近成功 ping 时间推送到 Pushgateway。
  • 成功 ping 时间持久化,后续上报不会被 ping_completed=0 覆盖。

环境要求

  • Go 1.22 或更高版本(从源码安装时)。
  • 已安装并登录的官方 codex CLI。
  • macOS 或 Linux。Windows 尚未测试。

limitping 复用 ~/.codex/auth.json;设置 CODEX_HOME 时则读取 $CODEX_HOME/auth.json。

安装

安装最新 GitHub Release 到 ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/ShawnKung/limitping/main/install.sh | sh

脚本支持 macOS/Linux 的 amd64 与 arm64,会校验 SHA-256,并以 0755 权限安装 ~/.local/bin/limitping。建议执行前先打开并检查脚本内容。

使用 Go:

go install github.com/ShawnKung/limitping/cmd/limitping@latest

从源码安装到 ~/.local/bin:

git clone https://github.com/ShawnKung/limitping.git
cd limitping
make install

可以覆盖安装目录:

make install BINDIR=/custom/bin

使用

$ limitping status
正在查询 codex 用量...
codex (plus)
  5h     [█████████░]  剩余  92.0%         30分 后重置 (周六 22:28 UTC+8)
  周     [████████░░]  剩余  80.0%  5天 2时28分 后重置 (周五 00:27 UTC+8)
  重置券 1 张可用

常用命令:

limitping status
limitping status --json
limitping version
limitping update
limitping ping --dry-run
limitping ping
limitping ping --if-5h-full
limitping ping --if-5h-full --without-align
limitping ping --until-anchored
limitping align add "0 0 * * *"
limitping align list
limitping align preview --count 5
limitping ping --push-metric https://pushgateway.example.com
limitping status --push-metric https://pushgateway.example.com

ping 会忽略 visibility != "list" 的内部模型,选择 priority 数值最大的可见模型, 然后执行:

codex exec -m <model> -c model_reasoning_effort=low ping

--if-5h-full 要求用量响应包含 5 小时窗口,并且 used_percent == 0。不满足时命令正常 退出;如果同时设置了 --push-metric,仍会推送最新用量,并将本次 limitping_ping_completed 记为 0。满足满额条件后,默认还会做相位对齐(见下一节), 只有到达对齐时间才真正 ping;加 --without-align 可关闭对齐,恢复“满额即 ping”。

窗口是否已计时(active 判定)

Codex 的 5 小时滚动窗口按“重置后首次使用”锚定:窗口尚未被使用时,接口返回的 reset_at 是“假设此刻起算、整段窗口之后到期”的滚动占位值,此时 remaining 恒等于 窗口长度、used_percent 取整为 0;一旦被首次请求锚定,reset_at 冻结、remaining 随之低于窗口长度。因此 status/指标中的窗口 active 判定为:used_percent > 0,或 remaining 已明显小于窗口长度(即 reset_at 已冻结)——只要满足其一,就表示窗口已开始 计时。这样即使一次很轻的 ping 消耗不足 1%、used_percent 仍显示 0,也能正确反映窗口 已被锚定。

让窗口开始计时(--until-anchored)

若你想在额度满时主动把 5 小时窗口“打着”,让它从此刻开始倒数(这样稍后来用时可以少等 一截),使用 limitping ping --until-anchored:

limitping ping --until-anchored

它会先回读用量,若窗口已在计时则直接结束;否则从一个较大的起始输入出发发送 ping,每轮 把输入长度翻倍以逐步增加单次消耗,每次 ping 后等待片刻再回读用量,一旦检测到窗口开始 计时立即停止,或到达轮数上限后停止。--dry-run 只打印将执行的命令而不实际调用。

窗口锚定机制、active 判定与该命令的更多细节见 docs/five-hour-window-anchoring.md。

刷新时间对齐(--if-5h-full 默认开启)

如果你希望 5h 窗口的刷新时刻尽量落在某个固定时间(例如每晚 00:00,好让 23:00 开始 工作、用完一轮后 00:00 刚好刷新到),可以用 align 配置一组 cron 目标。之后 limitping ping --if-5h-full 会默认做“尽力而为”的相位对齐(无需额外 flag)。

配合每分钟运行一次的 cron(或 LaunchAgent):平时满额即 ping、每 5h 正常链式;临近 目标时间时,会在延时预算内延后 ping,使某次窗口的重置刚好落在目标时间附近。若只想保留 满额判断而不对齐,加 --without-align。

# 声明目标:每晚 00:00(多条时,每轮取最近的一个目标)
limitping align add "0 0 * * *"
limitping align add "0 12 * * *"

# 延时预算(max-delay)绑定在每个目标上:add 时用 --max-delay 设置该目标自己的预算;
# 缺省 90m。重复 add 同一个 cron 且带 --max-delay 时,只更新该目标的预算、不新增。
limitping align add "0 0 * * *" --max-delay 90m

# 查看当前配置(每个目标一行:id、cron、该目标的延时预算 max-delay)
limitping align list

# 按 id(或唯一前缀)删除单个目标;clear 清空全部
limitping align delete <id>
limitping align clear

# 预览未来 5 次计划 ping 与对应刷新时间
limitping align preview --count 5

# 实际运行:--if-5h-full 默认对齐;--without-align 关闭对齐(满额即 ping)
limitping ping --if-5h-full
limitping ping --if-5h-full --without-align

工作原理与取舍:

  • 目标刷新时刻 T 取所有 cron 中最近的一次触发;理想 ping 锚点为 A* = T − 5h, 在此锚定可让窗口在 T 重置。
  • 离锚点还远(超过该目标自己的延时预算)时,按原始行为立即 ping,保持窗口新鲜;临近锚点 时在预算内延后到贴近 A* 再 ping。判定只依赖当前时间与 cron,无额外状态。
  • 因为窗口是滚动 5h,而 24 ÷ 5 除不尽,纯 5h 链无法每天精确命中同一墙钟时间;且相位 只能“往后拖、不能往前提”。延时预算(每个目标各自设置,缺省 90 分钟)决定精度与窗口空转 之间的平衡。对齐是“大致落在目标时间附近”,通常有分钟级到 1~2 小时的偏差。

配置保存在 ${XDG_CONFIG_HOME:-$HOME/.config}/limitping/config.json,延时预算随每个目标落盘:

{
  "targets": [
    { "id": "ca5ca66014b8", "cron": "0 0 * * *", "max_delay_minutes": 90 }
  ]
}

预触发 5h 窗口能少等多久?

下面给出一个简化模型,用来量化“让 5h 窗口尽量连续启动”的收益。它不是 Codex 计费系统的精确仿真,而是便于理解的等待时间模型:

  • 窗口长度为 $T=5$ 小时;
  • 真实使用会话按强度为 $\lambda$(次/小时)的泊松过程到达;
  • 每个预先启动的窗口内,第一次真实使用到来后会很快耗尽额度;
  • 只统计该窗口内至少发生一次真实使用的情况,不计网络延迟和 ping 自身消耗。

令 $X$ 为窗口启动后第一次真实使用到来的时间。条件于 $X\lt T$,它服从截断指数分布:

$$f_{X\mid X\lt T}(x)=\frac{\lambda e^{-\lambda x}}{1-e^{-\lambda T}},\qquad 0\le x\lt T$$

不预触发时,第一次真实使用才启动窗口;假设额度随即耗尽,下一次重置仍需等待约 $T$。预触发时,这次使用到达时窗口已经运行了 $X$,只需再等待 $T-X$。因此平均减少 的等待时间为:

$$\mathbb E[\Delta] =\mathbb E[X\mid X\lt T] =\frac{1}{\lambda}-\frac{T}{e^{\lambda T}-1}$$

预触发后的平均等待时间为:

$$\mathbb E[W_{\mathrm{ping}}] =T-\mathbb E[\Delta] =T-\frac{1}{\lambda}+\frac{T}{e^{\lambda T}-1}$$

代入 $T=5$ 小时:

平均真实使用频率 $\lambda$ 平均少等 预触发后平均等待 相对 5h 减少
每 10 小时 1 次 0.1/h 2时18分 2时42分 45.9%
每 5 小时 1 次 0.2/h 2时05分 2时55分 41.8%
每 2 小时 1 次 0.5/h 1时33分 3时27分 31.1%
每小时 1 次 1/h 58分 4时02分 19.3%
每 30 分钟 1 次 2/h 30分 4时30分 10.0%

当真实使用非常稀疏时,条件到达时刻趋近于在 5 小时窗口内均匀分布,此时平均少等 $T/2=2.5$ 小时,也就是约 50%。这也是“随机时刻到达”直觉下的简单答案。使用越 频繁,第一次真实使用通常越靠近窗口起点,本来就会很快自然启动窗口,所以预触发的 边际收益越小。

这个模型只回答“第一次真实使用快速耗尽额度后,距离下一次重置还有多久”。如果要 计算额度耗尽后陆续到来的其他会话的总排队时间,还需要额外给出单个窗口的额度、每次 会话消耗量和会话持续时间。

Prometheus Pushgateway

--push-metric <endpoint> 是全局选项,可用于 status 和 ping。endpoint 必须是 不含认证信息、查询参数或 fragment 的 http:// 或 https:// URL。指标通过 HTTP PUT 推送到:

<endpoint>/metrics/job/limitping/instance/<hostname>/collector/limitping

主要指标:

指标 含义
limitping_window_used_ratio 5h/周窗口已用比例
limitping_window_remaining_ratio 5h/周窗口剩余比例
limitping_window_remaining_seconds 距窗口重置的秒数
limitping_window_reset_timestamp_seconds 窗口重置时间戳
limitping_reset_credits_available 可用重置券数量
limitping_reset_credit_expiration_timestamp_seconds 最早到期的可用重置券时间戳
limitping_ping_completed 本次是否完成 ping(0/1)
limitping_last_successful_ping_timestamp_seconds 最近一次成功 ping 的时间戳
limitping_planned_ping_timestamp_seconds 未来计划 ping 时间戳(index="1..5",1 为最近;需配置对齐目标,并通过 --if-5h-full 或 --until-anchored 配合 --push-metric 运行)
metrics_pusher_collector_success 本次采集是否成功
metrics_pusher_last_run_timestamp_seconds 最近采集开始时间

最近成功 ping 保存在:

${XDG_STATE_HOME:-$HOME/.local/state}/limitping/last-successful-ping

Grafana 示例看板

contrib/grafana/limitping-dashboard.json 是从实际 部署中导出并脱敏的示例看板,包含推送健康度、5h/周余量、重置时间、重置券、最近成功 ping 和历史趋势等 15 个 panels。

在 Grafana 中选择 Dashboards → New → Import,上传 JSON,并为 DS_PROMETHEUS 选择抓取 Pushgateway 的 Prometheus datasource。看板查询按 Prometheus 抓取 Pushgateway 的默认 honor_labels: false 行为编写,因此使用 exported_job 和 exported_instance 标签。例如:

scrape_configs:
  - job_name: push_gateway
    static_configs:
      - targets: ["pushgateway:9091"]

如果启用了 honor_labels: true,需要把看板查询中的 exported_job / exported_instance 改为 job / instance。

Caution

Pushgateway 会收到主机名、订阅计划、用量比例、重置时间和可用重置券数量。请使用可信 endpoint;跨不可信网络时应使用 HTTPS,不要在 URL 中放用户名、密码或 token。

macOS LaunchAgent 示例

仓库提供了不含个人地址的模板: contrib/launchd/io.github.shawnkung.limitping.plist.example。

将模板中的 __HOME__ 和 __PUSHGATEWAY_URL__ 替换为实际值,创建日志目录后复制到 ~/Library/LaunchAgents/io.github.shawnkung.limitping.plist,再加载:

mkdir -p ~/.local/state/limitping
launchctl bootstrap "gui/$(id -u)" ~/Library/LaunchAgents/io.github.shawnkung.limitping.plist

模板默认登录后立即运行,并每 120 秒执行一次。代理环境、日志路径和周期应按自己的环境 调整。

安全与隐私

  • limitping 不输出或上传 Codex access token、refresh token 或 account ID。
  • 用量接口返回 401 时,工具可能使用 refresh token 刷新登录,并以 0600 权限原子更新 auth.json。
  • --dry-run 不调用 codex exec,也不向 Pushgateway 发送请求。
  • limitping update 只从本仓库的 GitHub Release 下载更新,校验同一 Release 中声明的 SHA-256 后才会原子替换当前可执行文件。
  • 报告安全问题时,请勿在公开 issue 中粘贴 auth.json、token 或完整调试日志。

开发

make check   # gofmt 检查、go vet、单元测试
make build

发布

推送形如 v0.1.0 的 tag 会触发 GitHub Actions 创建 Release:

git tag -a v0.1.0 -m "limitping v0.1.0"
git push origin v0.1.0

Release workflow 会把 tag 注入版本号、把 tag 对应的 Git commit 注入构建信息,并生成 以下四个裸二进制及 checksums.txt:

  • macOS amd64
  • macOS arm64
  • Linux amd64
  • Linux arm64

可以用下面的命令核对安装包来源:

$ limitping version
limitping 0.1.0
commit: 0123456789abcdef0123456789abcdef01234567

已通过 Release 安装的版本可以自更新:

limitping update

命令会查询最新 GitHub Release;发现更高版本时,下载当前 OS/架构对应的裸二进制, 校验 checksums.txt 中的 SHA-256,并在原安装路径原子替换当前程序。源码快照或开发构建 没有标准语义版本号,不能使用自动更新。

提交规范与安全报告方式见 CONTRIBUTING.md 和 SECURITY.md。

许可证与归属

本项目采用 MIT License。部分用量查询与 OAuth 刷新实现改编自 MIT 许可的 wavever/CCLimitPing,完整归属见 THIRD_PARTY_NOTICES.md。

About

轻量级 Codex 用量监控与窗口预触发工具,支持 Prometheus 指标和自动更新。

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages