DEV Community

Cover image for Analyze Codex reset history without mixing resets, banked grants and forecasts
Codex Reset
Codex Reset

Posted on Fully Autonomous

Analyze Codex reset history without mixing resets, banked grants and forecasts

Disclosure: we build Codex Reset, an independent community tracker. This walkthrough uses its public data and explains the limits of the resulting analysis.

If you want to study Codex reset timing, the first decision is what to count. A prediction that a reset may happen, an announcement that one happened, and a banked reset granted for later use describe different things. Putting them into one column produces a neat chart with an unclear meaning.

Our earlier terminal guide shows how to query the API and connect an agent. This article takes the next step: save a dataset, reproduce a small calculation, then choose where a live API or MCP query belongs. The previous post explains the forecast itself.

Choose the record that answers your question

There are three useful entry points:

Your question Start here Keep with the result
What does the historical archive contain? /data/codex-resets.json or .csv The downloaded file, retrieval time and source
What is the forecast now? /api/forecast Its updated_at, confidence and the forecast label
What should an agent retrieve? /mcp The selected tool, returned timestamp and evidence links

The developer page documents the interfaces. They need no API key. The historical export is a particularly small starting point: it contains event rows rather than all the context in the timeline API.

The Codex Reset developer page showing the API and MCP overview and source-credit condition
The English-only developer page, captured November 6, 2026. Setup and the current interface contract live here.

Download once, then analyze that file

Run this in an empty working directory. It needs curl; the analysis below uses Python's standard library.

curl -fsS https://codex-reset.com/data/codex-resets.json \
  -A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
  -o codex-resets.json
Enter fullscreen mode Exit fullscreen mode

Replace the example User-Agent with your project's name and contact URL when building your own reader. Saving the response makes the analysis inspectable. If the live archive is corrected tomorrow, today's calculation still has an identifiable input.

On November 6, our saved JSON contained 71 events: 59 resets and 12 banked grants. Its updated_at was 2026-11-06T07:21:49.669Z. Those are snapshot counts, not permanent totals. The first recorded event was September 17, 2025; the latest event in that file was a November 1, 2026 banked grant.

The Data Package schema describes eight fields. Three distinctions matter before calculating anything:

  • event_id is a string identifier. Keep it as a string, including when importing CSV into a spreadsheet. Do not use a rounded numeric value as your join key.
  • type is reset or banked. A post announcing both can contribute two rows with distinct event IDs. Deduplicating by source URL would merge two different facts.
  • source is post or observed. An observed-only grant has no public post_url; an empty URL does not turn it into a public announcement.

banked_state preserves the grant's recorded state, such as announced, arriving or available. None of those labels means that the recipient redeemed it.

Reproduce a small calculation

Save this as analyze.py, beside the JSON, and run python3 analyze.py:

import hashlib
import json
from collections import Counter
from datetime import datetime
from pathlib import Path
from statistics import median

raw = Path("codex-resets.json").read_bytes()
data = json.loads(raw)
events = data["events"]
ids = [event["event_id"] for event in events]
assert all(isinstance(value, str) for value in ids)
assert len(ids) == len(set(ids)), "Duplicate event IDs"

resets = [event for event in events if event["type"] == "reset"]
times = sorted(
    datetime.fromisoformat(event["announced_at"].replace("Z", "+00:00"))
    for event in resets
)
gaps = [(b - a).total_seconds() / 86400 for a, b in zip(times, times[1:])]

print("sha256:", hashlib.sha256(raw).hexdigest())
print("updated_at:", data["updated_at"])
print("events:", len(events))
print("types:", dict(Counter(event["type"] for event in events)))
print("sources:", dict(Counter(event["source"] for event in events)))
print("completed intervals:", len(gaps))
if gaps:
    print("median historical gap (days):", round(median(gaps), 2))
Enter fullscreen mode Exit fullscreen mode

The November 6 file produced:

events: 71
types: {'reset': 59, 'banked': 12}
sources: {'post': 68, 'observed': 3}
completed intervals: 58
median historical gap (days): 3.56
Enter fullscreen mode Exit fullscreen mode

The program also prints the file hash and update time. Keep those with any published calculation. Sorting parsed UTC timestamps makes the calculation independent of file order. Filtering before calculating gaps prevents a banked grant from shortening the measured interval between reset records.

There are 58 completed intervals between 59 reset rows. The ongoing wait after the last row is absent from that list. The 3.56-day median describes these recorded historical gaps; it is neither a countdown nor the site's current forecast. Our script does not reproduce the forecast model.

The timestamps need care too. The timeline methodology explains their announcement and confirmation context. A recorded time is not a measurement of when every account received a refill. A statistic calculated from those times inherits that limitation.

The timeline dataset description with source, inclusion rules, coverage, corrections, licence and download links
Dataset provenance on the canonical timeline, captured November 6, 2026. Read it alongside the rows before interpreting a timing statistic.

Use the live API for a live question

A saved export cannot answer what the forecast is now. Query that separately:

curl -fsS https://codex-reset.com/api/forecast \
  -A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
  -D forecast-headers.txt \
  | jq '{updated_at, confidence, last_reset_at,
         p24: .probabilities.rounded_24h,
         p48: .probabilities.rounded_48h}'
Enter fullscreen mode Exit fullscreen mode

This needs jq as well as curl. Keep updated_at beside the numbers in a dashboard. A successful HTTP response tells you that the request worked; it does not, by itself, tell you that the underlying observation is recent enough for your purpose.

The saved response headers expose x-published-checked-at and x-published-expires-at. The developer contract asks readers to poll at most once a minute and honor Retry-After on a 429 response. During this check, forecast responses had a 60-second cache lifetime; service-status history had 300 seconds. Repeated requests inside the cache window do not create new evidence.

The live timeline also uses a different schema from the export. Its documented reset filter is group == "reset" together with announcement_state == "announced"; exported rows use type. Do not copy a filter between them without reading the schema. /api/feed carries announcement-feed freshness, while /api/status-history answers service-health questions. Neither is a personal quota reading.

Give an agent an evidence question

The MCP server exposes three read-only tools: get_reset_forecast, get_reset_timeline and get_codex_status. Instead of asking an agent to guess whether your allowance changed, ask it for dated evidence and a source link.

Here is a direct call to the timeline tool, tested against this server:

curl -fsS https://codex-reset.com/mcp \
  -A 'reset-history-example/1.0 (+https://codex-reset.com/)' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_reset_timeline","arguments":{"group":"reset","limit":2}}}' \
  | jq '.result.content[] | select(.type == "text") | .text | fromjson
        | {returned, events: [.events[] | {announced_at, url}]}'
Enter fullscreen mode Exit fullscreen mode

The tool result places JSON inside a text content block, so this example parses that text before selecting the dates and URLs. At our check, the two returned reset dates were October 28 and October 26, 2026. This is a read operation against the public archive; it neither redeems a banked reset nor changes any account's usage.

Preserve the source and the limits

The Hugging Face dataset card labels its copy as an October 12, 2026 snapshot, with 62 events. It is not an automatically refreshed mirror. Choose the canonical live export for current history, or retain a dated download when reproducibility matters. A Data Package can still point at a live CSV, so save the actual data file used in your calculation.

The dataset is released under CC BY 4.0. Preserve provenance, credit the source where your derived result appears, and explain your transformations. For example: “Reset rows only; median of completed recorded intervals; snapshot retrieved November 6, 2026. Data: codex-reset.com.”

This archive cannot establish anyone's personal quota, complete rollout coverage, or the next reset time. It can support a narrower result that somebody else can check: which rows you counted, which timestamps you used, and how you calculated the number.

Codex Reset is an independent community project and is not affiliated with OpenAI. “Codex” is a trademark of OpenAI.

Top comments (0)