6月のプラン改定で、AI Ultra(月額100ドル・Pro 比5倍の利用上限)という選択肢が増えました。
私自身、Antigravity のエージェントを複数並列で回す日が増えており、月末になると Pro の上限に頭を抑えられる感覚がありました。ただ、その「感覚」だけで月80ドルの差額を払うのは、個人開発の財布には軽くない判断です。
クォータの正確な数値は公式に公開されていません。それなら、自分の環境で測るしかない。そう考えて、14日間の消費データを記録してから決めることにしました。
本稿は、その計測の仕組みと実測値、そして待ち時間を金額に換算して損益分岐を出すまでの記録です。
2026年6月時点のプラン構成 — 公開情報と不透明な部分の線引き
まず前提の整理から。2026年6月時点で、個人開発者に関係する選択肢は実質3つです。
- AI Pro(月額20ドル): Antigravity のエージェント利用を含む標準プラン
- AI Ultra(月額100ドル): 6月に追加された中間プラン。利用上限が Pro の約5倍
- 最上位 Ultra(月額200ドル): 250ドルから値下げ。上限は実質気にならない水準
注意したいのは、「5倍」という比率は公表されているものの、分母となる Pro の上限値そのものは公開されていないことです。リクエスト数なのか、トークン量なのか、モデルごとの重み付けがあるのか。この不透明さが、プラン選びを勘に頼らせる原因になっております。
公開されていないものは、外側から観測するほかありません。幸い、エージェントの実行履歴はローカルのログに残ります。ここを起点にしました。
消費を記録する小さな計測ハーネスを作る
最初に作ったのは、エージェントのセッションログを日次で集計するスクリプトです。
何を解決するコードか、先に一文で書いておきます。「いつ・何並列で・どれだけ実行し、どの時点でレート制限に当たったか」を毎日同じ形式で記録するためのものです。
Antigravity はセッションごとの実行履歴を JSONL 形式でローカルに保存します。保存先は環境によって異なるため、パスは引数で渡す設計にしました。
#!/usr/bin/env python3
"""agent_quota_tracker.py — エージェント実行ログの日次集計"""
import json
import sys
import re
from pathlib import Path
from collections import defaultdict
from datetime import datetime
# レート制限を示すメッセージのパターン(観測に基づき随時追加)
RATE_LIMIT_PATTERNS = [
re.compile(r"rate.?limit", re.IGNORECASE),
re.compile(r"quota.+exceeded", re.IGNORECASE),
re.compile(r"resource.?exhausted", re.IGNORECASE),
]
def is_rate_limited(text: str) -> bool:
return any(p.search(text) for p in RATE_LIMIT_PATTERNS)
def collect(log_dir: Path) -> dict:
daily = defaultdict(lambda: {
"sessions": 0,
"agent_runs": 0,
"max_parallel": 0,
"rate_limit_hits": [],
})
for jsonl in sorted(log_dir.rglob("*.jsonl")):
active = [] # (start, end) のリストで並列度を概算
for line in jsonl.read_text(encoding="utf-8").splitlines():
try:
ev = json.loads(line)
except json.JSONDecodeError:
continue
ts = ev.get("timestamp", "")
day = ts[:10] if ts else "unknown"
kind = ev.get("type", "")
if kind == "session_start":
daily[day]["sessions"] += 1
elif kind == "agent_run":
daily[day]["agent_runs"] += 1
start = ev.get("started_at", ts)
end = ev.get("ended_at", ts)
active.append((start, end))
elif kind == "error" and is_rate_limited(str(ev.get("message", ""))):
daily[day]["rate_limit_hits"].append(ts[11:16])
# 同一時刻に重なる実行数の最大値を並列度とみなす
for day, stats in daily.items():
overlaps = [
sum(1 for s2, e2 in active if s2 <= s1 < e2)
for s1, _ in active
]
if overlaps:
stats["max_parallel"] = max(stats["max_parallel"], max(overlaps))
return daily
def main():
if len(sys.argv) < 2:
print("usage: agent_quota_tracker.py <log_dir>")
sys.exit(1)
daily = collect(Path(sys.argv[1]))
for day in sorted(daily):
s = daily[day]
hits = ",".join(s["rate_limit_hits"]) or "-"
print(f"{day} runs={s['agent_runs']:3d} "
f"parallel_max={s['max_parallel']} limited_at={hits}")
if __name__ == "__main__":
main()ポイントは2つあります。
ひとつは、レート制限の検出をエラーメッセージのパターン照合で行っていること。クォータの内部仕様が見えない以上、「制限に当たった瞬間」だけが外側から観測できる確かな事実です。
もうひとつは、並列度を実行時間の重なりから概算していること。後述しますが、消費ペースは実行本数よりも並列度に強く相関しておりました。
cron や Antigravity 2.0 のスケジュール実行に登録して、毎晩1回走らせるだけで記録が貯まります。