GitHub trails
Connect a repo, count what ships — cycle time, estimated CI cost, and run health, with nothing sensitive stored.
What a GitHub trail is
A GitHub trail watches one repository and turns its activity into a card: shipped pull requests, cycle time, estimated CI cost, and run health, over the same 1D/7D/30D windows as every other trail. Connect GitHub once from Settings → Trails, then pick a repo in the trail wizard, and the trail starts from ~90 days of history — one connection powers as many trails as your plan allows.
The connection is read-only, through our own GitHub App. For private repos the App must be installed on the account or organization that owns the repo — authorizing the App against your user alone is not enough to see private repositories. If a private repo doesn't show up in the picker, install the App on its owner first.
Choosing what a trail watches
At creation, after picking a repository, you choose the trail's scope:
- Ship tracking watches pull requests: shipped count, cycle time, unshipped PRs, and what's in flight. The card and detail page show PR delivery metrics only.
- CI & Actions watches workflow runs: run counts, average run time, success rate, and estimated CI cost. The card headlines pushes and the detail page drops the PR tiles.
- Both (the default) is everything above on one card: today's full adaptive behavior.
The scope also trims what we ingest. A Ship tracking trail never registers the workflow-run webhook and skips workflow-run backfill; a CI & Actions trail never registers the pull-request webhook and skips PR backfill. Push events are always ingested, since both archetypes use them for context. When several trails watch the same repository, webhooks are registered for the union of their scopes. Trails created before scopes existed behave as Both, unchanged.
The scope is set at creation. To change it, end the trail and create a new one with the scope you want; creation re-backfills history.
What "shipped" means
A pull request counts as shipped when it merges to the repository's default branch. An open PR is "in flight". A PR closed without merging lands in the "unshipped" bucket — a bucket, not a judgment; closing without merging is often the right call, and we count it so the number is honest, not to shame it.
The metrics, exactly as computed
- Cycle time — the median time from a PR opening to it merging, over PRs merged in the selected window. Under 48 hours it renders as hours ("18h"); at 48 hours and above, as days with one decimal ("3.2d").
- CI cost (est.) — total workflow-run minutes in the window × $0.008/min, the GitHub-hosted standard Linux runner rate. This is an estimate, always labeled "est.": public repos run free on GitHub-hosted runners, self-hosted runners cost whatever your infrastructure costs, and larger or non-Linux runners bill at different rates. Treat it as "what this CI activity would cost at the standard metered rate", not your bill.
- Average run time — the mean duration of the window's workflow runs that have a duration ("5m 35s"). Shown on the card for repos that work in direct pushes rather than PRs (see below).
- Run success % — successful workflow runs as a share of concluded runs. An in-progress run never counts, for or against.
- Run fail rate — the complement: 100 − run success, same concluded-runs denominator.
- Deploy frequency — merges to the default branch per week, over the last 12 weeks.
- MTTR — the median time from a failed workflow run to the next successful run of the same workflow. If the same workflow never succeeds again in the data we have, that failure doesn't produce a pair.
- WIP aging — how many PRs are open right now, and the age of the oldest one.
- Off-hours share — how much push and run activity happens outside 9:00–18:00, computed in your local timezone, in your browser. The server only ever sees UTC hour buckets; your timezone never leaves the page.
- Run feed — the 20 most recent workflow runs: name, when, how long, and whether they succeeded.
The card's sparkline is always the trailing 30 days (it says which series it shows: shipped PRs per day, or pushes per day); the 1D/7D/30D chips switch the headline count and the metric grid, not the sparkline.
Repos that ship by pushing straight to the default branch, with no PR history at all, get a card in pushes terms: the headline counts pushes, and the PR-only cells (shipped PRs, cycle time) are replaced by action runs and average run time instead of sitting permanently empty.
When you'll see "—"
Any metric without the data to back it shows "—", never a made-up zero. Trails created before v2 shipped (2026-07-21) don't have the timestamps the time-based metrics need, so cycle time, CI cost, MTTR, and friends show "—" until new activity arrives with them. If you want history filled in now, end the trail and recreate it — creation re-backfills with full precision.
Backfill and limits
- New trails backfill roughly 90 days of PR, commit, and workflow-run history at creation.
- Trail caps: 10 personal trails per user, 25 team trails per Team Pro team. Ending a trail frees its slot.
- Team-owned trails require Team Pro. Trails for individuals come with Personal Pro.
What we store — and what we never store
Stored: PR numbers, PR states, dates and timestamps, commit shas, workflow run ids, run durations, success flags, and workflow names (the label you gave the workflow, e.g. "CI" — stored since v2 so cost and MTTR can be broken down per workflow).
Never stored: your code, diffs, commit messages, PR titles or bodies, and author names or emails. The payloads GitHub sends carry all of that; we read past it and it is never written anywhere.