October 15, 2026
Building Just-Released: Native GTK 4 GitHub Release Orchestration for Linux
Many of the most exciting developer utilities, AI runners, and specialized command-line tools distribute their Linux builds exclusively as raw binaries or tarballs attached to GitHub Releases, rather than through traditional package managers like apt, pacman, or Flathub.
For developers, maintaining dozens of standalone release binaries quickly becomes tedious: you manually check releases on GitHub, download archives, extract executables into /usr/local/bin or ~/.local/bin, and make sure your shell paths and custom configs don't break during upgrades.
I built just-released to automate this entire workflow. It is a native Linux desktop application built with Python, GTK 4, and Libadwaita that tracks upstream repositories, inspects release tags and assets, matches platform-specific files via glob patterns, and orchestrates updates through safe deployment strategies.
Why a Native GTK 4 / Libadwaita Application?
Linux desktop users value applications that respect their operating system's visual language, system themes, dark mode preferences, and responsive window ergonomics. Instead of building an Electron container that consumes hundreds of megabytes of memory, just-released is written natively in Python utilizing GObject introspection (PyGObject):
- Zero UI lag: Native Wayland and X11 rendering via GTK 4.
- Adaptive layout: Libadwaita widgets (
AdwPreferencesWindow,AdwActionRow,AdwBanner) that gracefully adapt between compact laptop screens and wide displays. - System integration: Native dark mode switching, system notifications, and portal-aware file dialogs.
Technical Architecture
The application separates upstream network discovery from local filesystem deployment:
1. Automated Asset Pattern Matching
A single GitHub release often contains dozens of compiled assets for different architectures: .deb, .rpm, linux-amd64.tar.gz, darwin-arm64.zip, and Windows .exe installers.
Users should not have to manually re-select the correct archive on every new release. just-released implements an automated pattern inference engine:
# pattern_matcher.py: Inferring glob rules from selected filenames
import fnmatch
import re
def infer_asset_pattern(filename: str, tag: str) -> str:
# Strip dynamic release versions to isolate stable platform tokens
sanitized = filename.replace(tag.lstrip("v"), "*").replace(tag, "*")
tokens = sanitized.split("-")
# Auto-detect Linux architecture tokens
arch_match = re.search(r"(x86_64|amd64|arm64|aarch64)", filename)
if arch_match:
return f"*{arch_match.group(0)}*{filename.split('.')[-1]}"
return sanitized
When a new version is published upstream, just-released matches the exact binary needed for the host system without requiring user intervention.
2. Deployment Strategies: Symlink vs. Smart Sync
Downloading a new binary and blindly overwriting a directory often destroys local configuration files, environment definitions, or custom wrapper scripts that you created.
just-released provides three safe deployment models:
Strategy A: Symlink Mode (symlink)
Ideal for multi-version testing or rapid rollbacks:
~/.local/share/just-released/apps/ripgrep/
├── versions/
│ ├── 14.0.0/
│ │ └── rg
│ └── 14.1.0/
│ └── rg
└── current -> versions/14.1.0/
Switching versions is an atomic symlink rewrite (os.symlink), taking less than a millisecond with zero downtime.
Strategy B: Smart In-Place Sync (smart-sync)
When installing into an existing folder that contains user-created config files:
- Downloads and extracts the incoming archive into a temporary staging sandbox.
- Compares checksums against existing files.
- Overwrites only matching binary files and new upstream dependencies while leaving unrecognized user scripts and
.envfiles completely untouched.
3. Native Libadwaita Integration
Building for the modern GNOME platform requires adhering to Human Interface Guidelines (HIG). By leveraging Libadwaita's AdwStatusPage, AdwSplitButton, and clean view stack transitions, the entire application feels like an integral part of the operating system:
# main.py snippet: Creating an adaptive preferences row
from gi.repository import Adw, Gtk
class AppEntryRow(Adw.ActionRow):
def __init__(self, app_name: str, current_version: str, latest_version: str):
super().__init__(title=app_name, subtitle=f"Installed: {current_version}")
self.update_btn = Gtk.Button(label="Update")
if current_version != latest_version:
self.add_suffix(self.update_btn)
self.add_css_class("suggested-action")
Conclusion
just-released demonstrates that desktop Linux utilities can combine the power of low-level filesystem management with the refined aesthetics of modern GTK 4. It eliminates the manual friction of managing GitHub Release software, bringing true package-manager ergonomics to standalone developer tools.