Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions .github/scripts/traffic.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
#!/usr/bin/env python3
"""Accumulate GitHub traffic counts into rolling 30-day shields.io badge payloads."""
"""Accumulate GitHub traffic counts into shields.io badge payloads."""

from __future__ import annotations

import json
import subprocess
import sys
from datetime import date, timedelta
from pathlib import Path

WINDOW_DAYS = 30


def fetch(metric: str) -> dict[str, int]:
"""Return {date: count} for the 14 days of traffic the API still holds."""
Expand All @@ -20,14 +17,13 @@ def fetch(metric: str) -> dict[str, int]:
return {day["timestamp"][:10]: day["count"] for day in json.loads(payload)[metric]}


def badge(label: str, total: int, collected: int) -> str:
"""Render a shields.io endpoint payload, naming the real window until a month has accrued."""
def badge(label: str, total: int) -> str:
"""Render a shields.io endpoint payload."""
count = f"{total / 1000:.1f}k" if total >= 1000 else str(total)
period = "month" if collected >= WINDOW_DAYS else f"{collected}d"
payload = {
"schemaVersion": 1,
"label": label.capitalize(),
"message": f"{count}/{period}",
"label": label,
"message": count,
"color": "e2603a",
}
return json.dumps(payload) + "\n"
Expand All @@ -36,16 +32,12 @@ def badge(label: str, total: int, collected: int) -> str:
data_dir = Path(sys.argv[1])
history_path = data_dir / "history.json"
history = json.loads(history_path.read_text()) if history_path.exists() else {}
cutoff = str(date.today() - timedelta(days=WINDOW_DAYS))

# `uniques` is deduplicated per day and cannot be summed, so only `count` is carried.
# History is append-only because the API drops everything past 14 days, which makes this
# file the only lasting record, so the 30-day window is applied at render time.
for metric in ("clones", "views"):
# History is append-only because the API drops everything past 14 days.
for metric, label in (("clones", "Downloads"), ("views", "Views")):
history[metric] = history.get(metric, {}) | fetch(metric)
total = sum(count for day, count in history[metric].items() if day > cutoff)
collected = (date.today() - date.fromisoformat(min(history[metric]))).days
payload = badge(metric, total, collected)
payload = badge(label, sum(history[metric].values()))
(data_dir / f"{metric}.json").write_text(payload)
print(payload.strip())

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/traffic.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Traffic counts

# GitHub's traffic API only keeps 14 days, so a "this month" number has to be collected
# daily before it ages out. Counts land on the orphan `traffic-data` branch, which
# GitHub's traffic API only keeps 14 days, so total traffic has to be collected daily
# before it ages out. Counts land on the orphan `traffic-data` branch, which
# shields.io reads as a badge endpoint. The API needs Administration:read, which the
# default GITHUB_TOKEN cannot hold, hence the TRAFFIC_TOKEN secret.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Context7 MCP](https://img.shields.io/badge/Context7%20MCP-Indexed-blue)](https://context7.com/fcakyon/claude-codex-settings)
[![llms.txt](https://img.shields.io/badge/llms.txt-✓-brightgreen)](https://context7.com/fcakyon/claude-codex-settings/llms.txt)

[![Clones](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffcakyon%2Fclaude-codex-settings%2Ftraffic-data%2Fclones.json&cacheSeconds=3600)](https://github.com/fcakyon/claude-codex-settings/blob/traffic-data/history.json)
[![Downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffcakyon%2Fclaude-codex-settings%2Ftraffic-data%2Fclones.json&cacheSeconds=3600)](https://github.com/fcakyon/claude-codex-settings/blob/traffic-data/history.json)
[![Views](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Ffcakyon%2Fclaude-codex-settings%2Ftraffic-data%2Fviews.json&cacheSeconds=3600)](https://github.com/fcakyon/claude-codex-settings/blob/traffic-data/history.json)

Battle-tested [Claude Code](https://github.com/anthropics/claude-code), [Claude Desktop](https://claude.ai/download), [OpenAI Codex](https://developers.openai.com/codex), and [Cursor](https://cursor.com) setup with skills, commands, hooks, subagents, and MCP servers, plus Kimi, MiniMax, and GLM API support.
Expand Down
Loading