惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
GbyAI
GbyAI
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
P
Proofpoint News Feed
The Cloudflare Blog
H
Help Net Security
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
量子位
博客园 - 聂微东
Apple Machine Learning Research
Apple Machine Learning Research
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MongoDB | Blog
MongoDB | Blog
Last Week in AI
Last Week in AI
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
月光博客
月光博客

Show HN

Show HN: AI agents for UK GDAD PCF roles and their skills The Two Pillars: Mixer Mode and Meta-Software in the Reorganization of Software Work After AI GitHub - JaiCode08/teleport-env What 1,000+ Harness Experiments Taught Me About Self-Improving Agents Show HN: Liiists, a Markdown-first, iOS and CLI list app SwiperTab – Get this Extension for 🦊 Firefox (en-US) GitHub - kouhxp/fftext: Summarize, explain, fact-check, or translate any text, URL, or file. No GPU. No cloud. One command GitHub - sweetpad-dev/sweetpad: Develop Swift/iOS projects using VSCode GitHub - dogmaticdev/IRON: IRON a.k.a. Intermediate Representation Object Notation is a Interpreter/Database that is used to create Programming Languages. GitHub - sjhalani7/vaen: Package your AI coding harness into a portable .agent file, and share it across repos, teams, & the community without ever having to copy-paste instructions, skills, MCP config, or secrets. Show HN: Gandalf the Grader Show HN: Citadeld – replay any CI failure locally from a single file GitHub - tdortman/cuSBF: High-Performance GPU Super Bloom Filter coral-ai/claude-code-token-xray at main · Coral-Bricks-AI/coral-ai GitHub - ulyssestenn/funes: Funes is a Git-based framework for LLM-managed knowledge work: an AI Librarian ingests raw sources, builds an interlinked Markdown knowledge base, and uses it to produce cited reports, analyses, and other outputs. GitHub - ThatXliner/gah: Git Add Hunk, built for agents to use GitHub - harmont-dev/harmont-cli: Command-line client for the Harmont CI platform GitHub - brooksmcmillin/mcp-authflow: OAuth 2.0 Authorization Server framework for MCP servers GitHub - javaid-codes/audit-supply-chain-agents GitHub - amorey/gochan: A small library of common channel architectures for Go, inspired by Rust GitHub - arifozgun/OpenGem: Free, Open-Source AI API Gateway with Gemini, OpenAI & Anthropic Compatibility in 1 file GitHub - Pranesh950/BioPetals: 🌸 Run BIOxAI models at home, BitTorrent-style. Fine-tuning and inference up to 10x faster than offloading GitHub - cnguyen14/bounty-doctor: Diagnose a GitHub bounty issue before you waste hours: detects honeypot scam repos, AI-bot attempt swarms, and stale contests. Show HN: CoreMCP – MCP Server for On-Prem DBs Show HN: KittyHTML – Render HTML/CSS as an inline image in your terminal GitHub - bingud/filemat: Web-based file manager Show HN: TruthLens – Free multi-signal deepfake image detector GitHub - apexlocal-jz/claude-usage-tray: Windows system-tray app showing your Claude Code rate-limit usage at a glance. Zero deps, ~300 lines of PowerShell. Cross-IDE (works regardless of VS Code, Cursor, plain terminal). Release v0.1.2.1 · kouhxp/yapsnap GitHub - noopolis/moltnet: Self-hostable chat network for AI agents. Pre-built bridges for Claude Code, Codex, and the Claws. Rooms, DMs, history. No Slack bots, no Matrix, no glue code.
GitHub - hatsu38/ghtrack
hatsu · 2026-06-22 · via Show HN

English | 日本語

A GitHub Action that records the execution time of each workflow run into your gh-pages branch on every run.

The goal is to apply the real-time accumulation pattern of benchmark-action/github-action-benchmark to workflow / step duration instead of benchmark values.

How it works

Collects job / step duration of a workflow run and writes it as a per-run JSON file under data/<track-name>/<YYYY>/<MM>/<DD>/<run_id>-<attempt>.json on the gh-pages branch. A Chart.js-powered index.html is bundled at the branch root and the time-series charts are visible in the browser once GitHub Pages is enabled.

🌐 Live demo: https://hatsu38.github.io/ghtrack/ ← this repo's own dogfood

Usage

Add this Action to the end of any workflow in the repository. If the gh-pages branch does not exist, an orphan branch is created automatically on the first run. Each workflow's data goes under data/<workflow-file-basename>/ by default, so you can drop the Action into multiple workflows without configuring anything.

# .github/workflows/your-workflow.yml
name: build

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - run: echo "build something"

  track:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write   # required to push to gh-pages
      actions: read     # required to fetch workflow run / job APIs
    steps:
      - uses: hatsu38/ghtrack@main

Inputs

All optional. The intent is that defaults are enough to start accumulating data into your repo's gh-pages branch out of the box.

name default description
github-token ${{ github.token }} used to fetch workflow run / job data and to push to gh-pages. Requires contents: write
gh-pages-branch gh-pages branch where the data is accumulated
track-name workflow file basename (e.g. test.ymltest) directory name under data/. Must match [a-zA-Z0-9._-]+. Override this to split one workflow into multiple tracks (matrix shards, environments, etc.)

File layout on the gh-pages branch

gh-pages/
├── index.html
└── data/
    ├── manifest.json                   # workflow registry
    └── <track-name>/
        ├── index.json                  # run list for this track
        └── <YYYY>/<MM>/<DD>/
            ├── <run_id>-<attempt>.json # one file per run (the Entry)
            └── ...

Each per-run file is independent and append-only: a push never reads or modifies prior runs, so workflow run history scales linearly without hitting GitHub's createBlob size limit.

Schema

Per-run file (<track-name>/<YYYY>/<MM>/<DD>/<run_id>-<attempt>.json)

A duration_sec of null means the step is incomplete (because the run is observing itself, the final step of the track job is always recorded as incomplete).

Workflow index (data/<track-name>/index.json)

The dashboard uses runs[] to know which per-run files exist (GitHub Pages does not serve directory listings).

Manifest (data/manifest.json)

Accumulating from multiple workflows into the same repo

Each workflow automatically stores its data under data/<workflow-file-basename>/. You can drop the Action into multiple workflows without configuring track-name and the dashboard will display each workflow as a separate dataset.

Override track-name when you want to split one workflow into multiple tracks (e.g. matrix shards, environments):

- uses: hatsu38/ghtrack@<sha>
  with:
    track-name: e2e-shard-${{ matrix.shard }}

The dashboard reads the manifest, fetches each workflow's index.json, and renders a separate dataset per workflow. The Per-job chart uses ${workflow_file}::${job.name} as the key, so identically-named jobs (e.g. e2e_test) across multiple workflows do not get merged into one line.

Visualization (GitHub Pages)

On every run, the Action bundles index.html at the root of the gh-pages branch (auto-syncs if it changed). It loads Chart.js v4 + the date-fns adapter from a CDN (jsDelivr), reads ./data/manifest.json and each workflow's ./data/<track>/index.json, then fetches the per-run files that fall inside the active date range.

The default range is Last 30 days. Changing the range preset triggers an incremental fetch of any newly-needed per-run files (already-loaded ones are cached in memory).

Charts rendered per workflow:

  • Total duration per run: a line chart of each run's total_duration_sec
  • Per-job duration: a line chart with one dataset per job name. matrix permutations (name (N) / name (N, M) form) are aggregated under the base name by default, and max(matrix node duration) is shown for each run (the bottleneck node that determines wall-clock under parallel execution). A checkbox above the chart lets you expand the matrix into individual nodes (the setting is persisted in localStorage).

Light / dark theming follows prefers-color-scheme. Layout is responsive with viewport meta + max-width: 960px.

The dashboard UI defaults to English. When navigator.language starts with ja, labels and headings switch to Japanese automatically.

How to publish

  1. Make the repository public (or enable Pages on a GitHub Pro plan or higher)
  2. Settings → Pages:
    • Source: Deploy from a branch
    • Branch: gh-pages / /(root)
  3. After a few minutes, the charts appear at https://<owner>.github.io/<repo>/

If you only want to inspect the data, you can open https://<owner>.github.io/<repo>/data/manifest.json directly (and follow the listed paths).

Running locally

fetch() calls from index.html do not work when opened via file:// due to browser CORS policy (Chrome/Edge/Safari etc.). To check locally, check out the gh-pages branch and serve it via a local HTTP server:

# switch to the gh-pages branch (so index.html and data/* are at the root)
git switch gh-pages

# serve via any static server. With Node.js, npx is enough
npx serve .
# or
npx http-server -p 8000

Open http://localhost:<port>/ in the browser to see the same charts as production Pages.

Example (this repo's own dogfood)

Required permissions and notes

  • Always grant contents: write to the permissions: of the track job. Even when Repository Settings → Actions → Workflow permissions is set to "Read and write", declaring it explicitly in the workflow is recommended (so a Settings change does not silently break the action)
  • actions: read is also required on the track job (to call workflow run APIs)
  • Runs from fork PRs: GITHUB_TOKEN cannot write to the base repo, so the Action exits early with a core.notice and does not collect or push anything
  • Concurrent push contention: per-run files are append-only at unique paths, so they never conflict with each other. Only the per-workflow index.json is read-modify-write, and that small file is retried with exponential backoff + jitter (up to 10 attempts) when contended

Migration from the v1 single-file layout

If you have an existing gh-pages branch that used the previous data/<workflow>.json (entries[] aggregated) layout, run the one-shot migration script:

# 1. back up the old gh-pages on the remote
git fetch origin gh-pages
git push origin refs/remotes/origin/gh-pages:refs/heads/gh-pages-v1-backup
git push origin --delete gh-pages

# 2. check out the backup locally
git worktree add /tmp/ghtrack-v1 gh-pages-v1-backup

# 3. run the migration script (writes the v2 tree to a new dir)
node scripts/migrate-v1-to-v2.mjs /tmp/ghtrack-v1 /tmp/ghtrack-v2

# 4. push /tmp/ghtrack-v2 as the new gh-pages
cd /tmp/ghtrack-v2
git init -b gh-pages
git add .
git commit -m "chore(ghtrack): migrate to v2 per-run file layout"
git remote add origin <repo-url>
git push origin gh-pages

After step 4 the next ghtrack run will append in v2 mode without further changes. The gh-pages-v1-backup branch can be kept or deleted later.

Local development

pnpm install
pnpm typecheck
pnpm build   # bundle into dist/ (committed to the repo)

License

MIT