Skip to main content

GHA Explorer

A terminal UI for exploring GitHub Actions workflow timing data. Fetches successful workflow runs from any repo you have access to straight from the GitHub API, caches everything locally in SQLite, and shows interactive trend charts of pipeline and job durations.

Hero screenshot

Features

  • Incremental sync — on launch, cached data displays instantly, then new runs fetch in the background. No re-fetching what you already have.
  • Multi-repo support — switch between any repo you own or have access to. All data lives in a single local cache DB.
  • Dynamic discovery — workflows, jobs, and matrix shards all auto-detected from your actual run history. Nothing hardcoded.
  • Trend charts — duration trends with rolling averages, per-job and pipeline-wide.
  • Job groups — combine matrix shards (Tests (1), Tests (2)) or a renamed job into one entry; grouped jobs get a per-member breakdown chart.
  • Per-repo settings — full-screen Settings page (, or ⚙ Settings): job groups (create, edit, rename — exclusions and notes follow a rename), and include/exclude tables for workflows, jobs and branches with Include all / Exclude all. Workflows and jobs are opt-out (everything included until you exclude it); branches are opt-in (a repo starts with its long-lived branches — main, develop… — and newly seen branches stay excluded until you include them, since branches are created constantly). Excluding a workflow removes its runs, and therefore its jobs.
  • Outlier filter — optional Hampel filter (rolling median + MAD) hides transient spikes — a stuck queue, a flaky runner — from the trend charts while keeping lasting duration changes visible. Tune sensitivity and window in Settings → General.
  • Filters — by workflow, branch (top branches discovered from the data, multi-select), time range (1d / 1m / 3m / 6m / 1y / all, or a Custom from/through date range).
  • Drag to zoom — click and drag across the trend chart to zoom to that period; it becomes the Custom range (whole days, never finer) and is saved with your filters.
  • Notes — pin a note to a date/time ("switched runners", "enabled test cache"). It's drawn as a red vertical line on the trend charts with a clickable ⓘ that pops the note in a bubble, so you can eyeball before/after. A note applies to the job you're viewing by default, or to several jobs, or to all jobs (including ones that don't exist yet). Notes on jobs that later get grouped show on the group's chart prefixed with the source job. Each note has a colour (red by default). Manage them via ⓘ Notes at the right of the stats line or n; a note's bubble has Edit and Delete (with confirmation).
  • Sticky state — repo, active tab, sidebar collapsed, and per-repo filter selections (workflow, job, branches, time range, y-axis) are saved in the database and restored next launch.
  • Status tab — live sync phase and progress, GitHub API rate-limit gauge, call/error counters, cache stats, and a streaming log.
  • Resilient — walks past the API's 1000-result cap per query, backs off on rate limits, and backfill resumes next launch.
  • No gh required — talks to the GitHub REST API directly. If you have the gh CLI signed in it reuses that login silently; otherwise a one-time in-app sign-in (browser device flow, or paste a token).
  • Dark lavender theme — plus --theme to use any built-in Textual theme (charts recolor to match).

Requirements

  • uv — provides uvx; it fetches Python 3.11+ and the dependencies for you
  • Charts use plotext 6, which ships compiled wheels for macOS (Intel/Apple silicon), Linux (x86_64/aarch64) and Windows x86_64; other platforms need a C compiler to build it
  • A GitHub account. The gh CLI is optional — see Signing in.
  • On Windows, use Windows Terminal (or another modern terminal) for colours, glyphs and mouse support.

Run

No clone needed — it's on PyPI:

uvx gha-explorer
uvx gha-explorer --repo owner/name   # skip the picker

Or install it as a tool so gha-explorer is on your PATH:

uv tool install gha-explorer
gha-explorer --theme catppuccin-mocha   # any built-in Textual theme
uv tool upgrade gha-explorer            # pick up new releases

To run the latest unreleased code straight from main, point uvx at the repo instead:

uvx --from git+https://github.com/swils23/gha-explorer gha-explorer

From a checkout, the single file still runs directly (it carries inline script metadata):

./gha_explorer.py            # or: uv run --script gha_explorer.py

Run it inside a git checkout whose origin is on GitHub and it opens that repository. Otherwise the first launch shows a repo picker listing every repo you have access to; pick one and it starts fetching. Your last choice — plus filters, active tab and sidebar state — is remembered for launches outside a checkout. s switches repo at any time.

Signing in

Credentials are looked up in this order, and you're only asked if none apply:

  1. GH_TOKEN / GITHUB_TOKEN in the environment.
  2. The gh CLI's login (gh auth token), when gh is installed and signed in — the default for gh users, so nothing changes for you.
  3. The built-in sign-in, saved from a previous launch.
  4. Otherwise a sign-in dialog: authorize in your browser with a one-time code (GitHub's device flow, the same mechanism gh auth login uses), or paste a personal access token (classic: repo scope; fine-grained: Actions: read + Metadata: read). The token is saved in auth.json in the data directory, readable only by you.

Settings → General → GitHub access switches between the gh login and the built-in sign-in (the gh option is disabled, with an explanation, when gh isn't available), and has Sign in / Sign out buttons. gha-explorer --logout forgets the built-in login from the command line.

Where data lives

Everything — the runs cache, settings and notes — lives in one SQLite file, gha-explorer.db, alongside the log and the saved login (auth.json) in a per-user directory: ~/.local/share/gha-explorer (or $XDG_DATA_HOME/gha-explorer; %LOCALAPPDATA%\gha-explorer on Windows). Set GHA_EXPLORER_HOME to put the directory somewhere else, and gha-explorer --data-dir prints the resolved path. A checkout that already has a database next to the script keeps using it, and a cache.db from before the first release is renamed on first launch.

Settings → General has a Database section: change the file's path (to rename or move it — the current database is copied to the new location if nothing is there yet), or Reveal in Finder / Explorer. A custom path is remembered in paths.json in the data directory; GHA_EXPLORER_DB overrides it.

Keybindings

Key Action
q Quit
r Refresh (incremental sync)
R Full rescan (re-walk history back to repo creation)
s Switch repo (open picker)
f Collapse / expand the filter sidebar (or the < / > buttons at its foot)
n Open the notes manager (add / delete notes)
, Open Settings for the current repo (Esc / Close to return)
Esc Close an open note bubble
1 Trends tab
2 Runs tab
3 Status tab (sync progress, API rate limit, log)

Architecture

The script is a single file (gha_explorer.py) — also packaged as the gha-explorer console script via pyproject.toml — with four layers:

  1. Database (SQLite, WAL — gha-explorer.db)run_jobs stores the normalised run-list row + the raw /actions/runs/{id}/jobs JSON per run_id, keyed by repo; sync_meta records per repo whether backfill has reached the repo's creation date; settings holds sticky UI state and per-repo config (global and per-repo scopes, JSON values); notes holds timestamped annotations per repo, each scoped to all jobs or a list of jobs. Never re-fetches the same run.
  2. Fetch — GitHub REST API via stdlib urllib (no gh subprocesses): /actions/runs filtered by status and created, /actions/runs/{id}/jobs, /user/repos, /rate_limit. Incremental sync: forward-fetch runs newer than the newest cached run, then backfill backwards in 90-day windows until the repo's creation date. Every list call walks past the API's 1000-result cap by moving the upper date bound down and deduping, so busy windows don't silently drop runs. Once backfill completes it's skipped on later launches (R forces it). Auth is a token from $GH_TOKEN, gh auth token, or the in-app OAuth device flow (resolve_token()); a 401 mid-sync re-opens the sign-in dialog.
  3. Aggregation — stats (mean / median / min / max / stdev) and rolling averages for trend smoothing.
  4. TUI (Textual + plotext) — tabs with an inline sync status in the top bar, a filter sidebar inside the Trends/Runs tabs, ASCII charts, and a Status tab fed by a shared SyncStats object and an in-memory log handler. Charts plot one point per run, so notes are placed between the runs that bracket them, proportional to elapsed time; plotext draws the line and ⓘ, then the ⓘ is made clickable by attaching the note id as Rich style meta.

Everything is derived from the data itself — no hardcoded workflow, job, or branch names, and no automatic grouping: matrix shards appear as separate jobs until you put them in a Group. Repo settings (groups, exclusions, rolling window) are applied on top of the cached runs (apply_repo_config) before anything is filtered or charted.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gha_explorer-0.1.2.tar.gz (64.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gha_explorer-0.1.2-py3-none-any.whl (65.6 kB view details)

Uploaded Python 3

File details

Details for the file gha_explorer-0.1.2.tar.gz.

File metadata

  • Download URL: gha_explorer-0.1.2.tar.gz
  • Upload date:
  • Size: 64.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for gha_explorer-0.1.2.tar.gz
Algorithm Hash digest
SHA256 6e4b4c2f3ab50249bcf231db6099937b6259575848df9aadd84238094a2f9d60
MD5 444e12ad6ba11d7c2d902aa750be461c
BLAKE2b-256 01ecb894529bd1d29e72b60a8ed537e74ecf18cfaadbba9869d04220f6fc08e0

See more details on using hashes here.

File details

Details for the file gha_explorer-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: gha_explorer-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 65.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for gha_explorer-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 35183a48c18479ccdb8f53ecea85c330b82a04ee679c7f0ab5420e7933ee5d8f
MD5 352a6a7a2282f0ddc704bc4cfa4d40fd
BLAKE2b-256 b874ba2fe74129d06205c1af5e69320a0ecd124387179fe7de4b475ee63cc67a

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page