🚀 GitLab MR Tracker
GitLab MR Tracker is a fast, asynchronous Terminal User Interface (TUI) dashboard designed for engineering teams. It provides real-time verification of GitLab Merge Requests across target environment branches (main, preproduction, staging, etc.), handling strict SHA verification as well as cherry-picked commit identification.

✨ Key Features
-
🔐 OS Keyring Integration (Zero Plain-Text Secrets): Personal Access Tokens (PAT) can be securely stored directly in your OS secret manager (GNOME Keyring, KWallet, macOS Keychain, or Windows Credential Manager).
-
🏷️ Dynamic Scoped Labels & Custom Chips:
- Smart Filtering: Configure specific label prefixes (e.g.,
deploy::,review::) to display cleanly as colored chips in the main table grid, while keeping all attached tags visible in the side inspector panel. - Customizable Palette: Map label names or wildcard patterns (e.g.,
deploy::*) to custom terminal colors or standard HEX codes (#FF5733) via an XDG-compliant JSON config.
- Smart Filtering: Configure specific label prefixes (e.g.,
-
⚡ High Performance & Asynchronous: Powered by
tokioandreqwest, utilizing non-blocking event loops and bounded concurrent requests via semaphores to protect GitLab API rate limits. -
🛡️ Pass-Through Pass Caching: Core MR metadata (author, milestone, assignee, description, labels) is fetched once and cached locally. Fully deployed MRs bypass network re-queries entirely ("Green Pass").
-
🔍 Dual Match Verification Engine:
- System 1 (Strict SHA): Validates precise merge/squash commit SHAs on target branches (resistant to
git reset --hard). - System 2 (Intelligent Fuzzy Matcher): Uses a keyword relevance matrix to verify cherry-picked commits deployed across branches.
- System 1 (Strict SHA): Validates precise merge/squash commit SHAs on target branches (resistant to
-
🖥️ Responsive Flexbox TUI Grid: Features a dynamic layout engine (
Constraint::Fill) that seamlessly scales table columns and side panels from 1080p laptop displays to ultra-wide 4K monitors without empty trailing spaces. -
🔃 Smart Auto-Sorting by Last Update: The dashboard defaults to sorting MRs by
updated_at(most recently pushed to remote first), automatically re-applied after each refresh. Cycle through sort columns (S) and toggle direction (Shift+S). The active sort is always visible in the table title bar. -
🌐 Browser Integration: Open any selected MR directly in your default browser with a single keypress (
O). -
🔔 Smart Desktop Notifications: Receives native OS desktop notifications only when an MR's branch status has changed since the last run — no duplicate alerts on restart or redundant refreshes.
-
📁 XDG-Compliant Persistence: Saves tracked dashboard state, UI configurations, and last-known branch statuses automatically to platform-standard configuration paths using
directories. -
Customizable Refresh Interval: Tailor the background polling rate to your needs (defaults to 15 minutes / 900s) via
config.jsonor theGITLAB_REFRESH_INTERVAL_SECSenvironment variable. -
📊 Activity Badge: Each MR in the Context Inspector displays a color-coded activity badge based on its
updated_attimestamp — 🟢 Active, 🟡 Slowing, or 🔴 Stale. Thresholds are fully configurable viaconfig.jsonor environment variables (ACTIVITY_RECENT_DAYS,ACTIVITY_STALE_DAYS). -
🔀 Animated Mergeability Badge: For open MRs, the Status column alternates every second between the base
Openbadge and a live mergeability indicator sourced directly from the GitLab API:Badge Color Meaning Mergeable🟩 Light green MR can be merged cleanly Conflict🟥 Red Merge conflicts must be resolved Rebase🟨 Yellow Branch is behind target — rebase required No extra column is added: the animation keeps the layout compact while surfacing critical merge-readiness at a glance.
🔑 Authentication & Configuration
The application requires your GitLab Project configuration and an API Personal Access Token.
Step 1: Set up environment variables
-
Copy the provided template to create your local
.envfile: -
Open
.envand specify your project details:# Required: Your target GitLab Project ID GITLAB_PROJECT_ID=12345678 # Optional: Custom self-hosted GitLab instance (Defaults to https://gitlab.com if omitted) GITLAB_URL=https://gitlab.my-company.com # Optional: Override token via environment variable (Not recommended for disk storage) # GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx # Optional: Override initial tracked branches for new sessions (comma-separated) DEFAULT_BRANCHES="main,develop" # Optional: Filter table column tags by prefix (comma-separated) TABLE_LABEL_PREFIXES="deploy::,review::" # Optional: Activity badge thresholds in the Context Inspector (in days) ACTIVITY_RECENT_DAYS=2 # 🟢 Green if updated within N days (default: 2) ACTIVITY_STALE_DAYS=7 # 🔴 Red if not updated for N days (default: 7)
🔄 Settings Resolution Order
Settings are resolved in the following order (highest to lowest priority):
- System Environment Variables & Local
.env(current directory) - Global
.env(~/.config/gitlab-tracker/.env) - User Config File (
~/.config/gitlab-tracker/config.json) - Built-in Fallback Defaults (
https://gitlab.com,["main"]for default branch)
Step 2: Keyring PAT Security Layer
Your GitLab personal access token is never stored in plain text.
Upon first launch, if no token is found, gitlab-tracker will securely prompt
you for your token and store it in your operating system's native secure
keyring (GNOME Keyring, macOS Keychain, or Windows Credential Manager).
┌────────────────────────────────────────────────────────┐
│ TOKEN LOOKUP ORDER │
├────────────────────────────────────────────────────────┤
│ 1. GITLAB_TOKEN environment variable (if set) │
│ 2. Native OS Keyring (GNOME Keyring / macOS Keychain) │
│ 3. Interactive CLI Prompt (First run fallback) │
└────────────────────────────────────────────────────────┘
-
First-Run Onboarding: If no
GITLAB_TOKENis found in your.envor environment, the application will prompt you interactively in the terminal on its initial launch:🔑 No GITLAB_TOKEN found in environment or system Keyring. Please enter your GitLab Personal Access Token: glpat-xxxxxxxxxxxx ✅ Token securely saved to OS Keyring! -
Secure Token Persistence: The token is encrypted and handed off directly to your operating system's native secret manager:
- Linux: GNOME Keyring / KWallet via Secret Service API
- macOS: Apple Keychain Service
- Windows: Windows Credential Manager
-
Subsequent Launches: You can delete the
GITLAB_TOKENentry from your.envcompletely. On subsequent runs,gitlab-trackerretrieves the token silently from the OS Keyring without requiring plain-text files or manual re-entry.
Step 3: UI, Default Branches & Label Customization (config.json)
On its first launch, the tool automatically generates a config.json file inside your OS user configuration directory:
- Linux:
~/.config/gitlab-tracker/config.json - macOS:
~/Library/Application Support/gitlab-tracker/config.json - Windows:
C:\Users\<User>\AppData\Roaming\gitlab-tracker\config.json
You can edit this file to adjust default environment branches, label badge colors, wildcard rules, and activity badge thresholds:
Activity badge thresholds control the colored indicator displayed next to the
Updatedfield in the Context Inspector:
Badge Meaning Condition 🟢 Active Updated recently elapsed days < activity_recent_days🟡 Slowing Activity slowing down between the two thresholds 🔴 Stale No recent activity elapsed days ≥ activity_stale_days⬛ Unknown Timestamp unavailable —
🔔 How Desktop Notifications Work:
Notifications are powered by notify-rust and rely on your system's native notification daemon (e.g., libnotify on Linux, NSUserNotifications on macOS).
A notification is sent only when a branch is newly detected for a given MR — i.e., when the branch was not present in the last persisted state (tracker_state.json). This means:
- ✅ No duplicate alerts when restarting the app with an unchanged state.
- ✅ No spam during periodic background refreshes if nothing changed.
- ✅ Reliable detection of new deployments across refreshes and restarts.
The last-known branch state per MR is persisted in tracker_state.json under the last_known_branches key. On the very first launch (empty state), a single batch of notifications may be sent for all already-known branches — this is a one-time occurrence.
🌿 How Branch Resolution Works:
- Active Session Priority: If
tracker_state.jsonexists from a previous run, the app restores your last active layout (columns added/removed via input). - First Run / Fresh Session: If no state exists, initial branches are loaded from
DEFAULT_BRANCHESin.envif provided, falling back todefault_branchesinconfig.json(defaults to["main"]).
📦 Installation
Recommended — Install from crates.io
The simplest way to install gitlab-tracker if you have Rust (1.80+) available:
This downloads, compiles, and installs the latest published release directly from crates.io into ~/.cargo/bin/. No cloning required.
Pre-built Binaries
If you prefer not to compile, download the latest pre-compiled binary for your architecture from the Releases Page and place it somewhere on your $PATH.
Building from Source
For development or to test unreleased changes, clone the repository and build manually:
# Build optimized release executable
# Optional: install binary globally to ~/.cargo/bin/
Once installed via any of the methods above, launch the dashboard from any terminal folder:
⌨️ Dashboard Navigation & Shortcuts
| Shortcut | Action |
|---|---|
▲ / ▼ or k / j |
Navigate rows in the table |
142 + Enter |
Add MR ID !142 to tracking |
staging + Enter |
Add branch staging to target columns |
-142 + Enter |
Remove MR ID !142 from tracking |
-staging + Enter |
Remove branch column staging |
O |
Open selected MR in your default web browser |
R |
Force immediate network refresh for all MRs |
s |
Cycle sort column (Updated → ID → Milestone → Title → …) |
S |
Toggle sort direction (ascending / descending) |
Del or X |
Delete selected MR row |
ESC |
Quit dashboard |
🏗️ Project Architecture
src/
├── main.rs # Event loop orchestrator & async channel setup
├── app.rs # State machine & row navigation logic
├── config.rs # Label filtering, wildcard matching, HEX color parsing & activity badge
├── models.rs # Strongly-typed API DTOs & runtime event types
├── gitlab.rs # Async network handling & rate-limit semaphores
├── storage.rs # OS Keyring interface & XDG state/config persistence
├── utils.rs # Fuzzy matching algorithmic utilities
└── ui/ # Flexbox Renderers for Table & Context Inspector
📄 License
Distributed under the MIT License. See LICENSE for details.