How it works
The design goal is a dashboard that feels local even when the server is huge and far away. Every trick below exists to serve that: fewer round trips, aggressive caching, and never blocking the UI on the network.
The whole fleet in one call
The pipeline tree, pause states, and latest-run statuses all come from a single request to GoCD's /api/dashboard. There's no N+1 walk over groups or pipelines, so the cost of a refresh doesn't grow with how much you have.
The client requests gzip, which matters more than it sounds. On a real GoCD 23.5.0 instance with 185 groups and 2,389 pipelines, the dashboard payload is 5.3 MB uncompressed but only 165 KB compressed, and the load dropped from ~20 seconds to 2–4 seconds. The request timeout is a generous 45 seconds regardless, for slower networks.
The tree starts fully collapsed, because a large org's groups expanded at once would be unusable. Press / to fuzzy-filter by name across every group, collapsed or not.
Personalized GoCD views
GoCD's web dashboard lets each user keep personalized view tabs. lazygocd reads those same server-side filters from GoCD's pipeline_selection endpoint and applies them with /api/dashboard?viewName=..., so v switches to the exact view you use in the browser.
Creating a view is terminal-native too: filter with /, press V, name the view, and lazygocd saves the matching pipelines as a whitelist view on the server. The new view appears in GoCD's web UI as well, and writes use If-Match so a concurrent web edit cannot be silently overwritten.
Instant startup from the disk cache
After every successful load, the dashboard is written to ~/.config/lazygocd/dashboard_cache.json. The next launch reads it and paints your whole fleet immediately, before touching the network, while a fresh load runs in the background. The header makes the state honest:
The LED next to the server URL is the connection at a glance: green connected, yellow loading, red error. When the fresh data lands, the view updates in place.
History cache and hover prefetch
Run history and stage details load lazily, per pipeline, via /api/pipelines/:name/history, only when you open one. Two layers keep that from ever feeling lazy:
- In-session cache. Once you've opened a pipeline's history, reopening it later in the same session is instant, served from memory while a background refresh keeps it current.
- Hover prefetch. Resting the mouse cursor on a pipeline row for ~300ms starts loading its history in the background, so pressing enter often finds it already there.
Live console logs with auto-tail
From the Details pane, enter on any job opens its raw console log in a scrollable full-screen view. While the stage is still running, the log refreshes itself every ~3 seconds and follows the newest output; once the stage finishes, it stops polling on its own.
Tailing is incremental: only new lines are fetched while a job runs, and background dashboard polls revalidate with ETag/304, so steady-state network cost is near zero. History paginates as you scroll, older pages loading automatically.
Scrolling up detaches you from the tail so you can read; G jumps back to the bottom and resumes following. Logs are colorized for scanning: failures and errors in red, warnings and stderr in yellow, successes in green, timestamps and agent chatter dimmed. / searches with inline highlighting and n/N jump between matches.
The job view is tabbed like GoCD's own job page: Console, Artifacts (the job's file tree, enter opens a file in your browser), and Materials (the trigger, repo and branch, and the commits behind the run).
Act on what you see: R reruns a failed run's failed jobs (or the whole stage), T triggers with environment variables, and desktop notifications fire when a favorited pipeline starts failing. Every git material gets its own stale-deploy check, and GitHub Enterprise works via github_api_base in the config.
Deployed-commit check
The question behind most dashboard visits is "is what's deployed actually the latest code?" When a pipeline's latest run has a direct Git material (not a chained upstream-pipeline material), opening its history compares the deployed commit against the newest commit on that branch and answers inline in the Details panel:
If you have the GitHub CLI signed in, lazygocd uses gh auth token automatically, so private repos work with zero setup. Otherwise public repos still work unauthenticated (rate-limited), and @ lets you paste a personal access token. Press o on any run to open its commit on GitHub, or the pending diff when the latest deploy is behind the branch head. The check only runs for the latest run, never for an older row you happen to have selected.
Cancel vs pause
The two are deliberately separate keys because they do different things:
| Key | What it does | Touches a running build? |
|---|---|---|
| p pause | Blocks future scheduling of the pipeline | No, a run already in flight keeps going |
| X cancel | Stops the currently running stage via POST /api/stages/.../cancel | Yes, that's its whole job |
X is only offered when the open pipeline's latest run actually has an active stage, and every mutating action (trigger, pause, unpause, cancel) sits behind a confirm prompt and is sent with the X-GoCD-Confirm header GoCD requires.
Favorites
Press f to star a pipeline. Starred pipelines pin to a gold ★ Favorites section at the top of the tree, expanded by default, and persist across sessions in ~/.config/lazygocd/favorites.json. A star also shows next to a favorited pipeline in its normal group listing, so you can tell at a glance from either place.
While a / filter is active the Favorites section hides itself, so search results stay a pure set with no duplicates.
The UI never blocks
All network calls run on background threads; the interface keeps responding while anything loads, with an animated spinner instead of frozen text. Input polling runs at 40ms (down from an earlier 150ms) so keypresses land instantly, and the dashboard plus the open pipeline's history silently re-poll every poll_interval_secs (default 30, configurable in config.toml).
A k9s-style stats bar keeps the fleet's health at a glance, and it only surfaces non-nominal states. Paused, building, and failed counts appear only when non-zero, so a healthy fleet shows a clean bar instead of a row of zeros.