What it is
AetherPak CLI is a Go-compiled tool that fully automates local compilation, signature backfilling, registry distribution, and index generation. It acts as the core engine that powers AetherPak GitHub Actions, but can also run independently on any developer machine or non-containerized CI runner.
- Zero Dependencies: Single compiled binary needing only local system tools (flatpak, ostree, and gpg).
- Integrated Linter: Automatically hooks
flatpak-builder-lintcheck points into compilation. - CI-Agnostic Output: Dotenv format files capture resolved build coordinates easily.
Interactive CLI Execution
AetherPak CLI outputs status logs using structured timing metrics and beautiful Lipgloss-styled status banners during execution:
Real execution logs simulation displaying AetherPak release stages.
Command Reference
High-level convenience workflows coordinating processes in-memory:
add
Onboards an app into aetherpak.yaml from a local manifest, a bundle URL, or a git repository (added as a submodule), with an interactive wizard and a pre-commit diff:
aetherpak add --manifest org.example.App.yaml
release
Plans changed matrix entries, builds/imports concurrently, pushes OCI packages, and regenerates index sites:
aetherpak release --base-sha abc123def --workers 4
publish
Chains build/import and OCI push for target application(s):
# Config-driven publish
aetherpak publish --app-id org.example.App --registry ghcr.io
# One-off publish from local manifest
aetherpak publish --manifest apps/manifest.json --arch x86_64
# One-off publish from Flatpak bundle (URL or local path)
aetherpak publish --bundle https://example.com/app.flatpak
status
Validates system dependencies, repository configuration files, and GPG signing credentials:
aetherpak status --gpg-key key.asc
preview
Generates and serves a local landing page template preview using customizable dummy data or live pages index, simulating GPG status, single/multiple apps:
aetherpak preview --port 8080
Independent single-responsibility commands for custom pipeline steps:
plan
Computes app changes compared to a base commit:
aetherpak plan --base-sha HEAD~1 --output-file plan.envbuild
Wrapper sandboxing flatpak-builder builds:
aetherpak build --manifest manifest.json --flatpak-remote flathub=https://dl.flathub.org/repo/flathub.flatpakrepo --flatpak-dep flathub:org.gnome.Sdk//45import
Imports prebuilt flatpak bundle packages:
aetherpak import --app-id org.example.App --bundle-url https://example.com/download.flatpakpush-oci
Pushes repo commits as tagged OCI images to remote registry:
aetherpak push-oci --app-id org.example.App --gpg-key key.ascbuild-site
Combines build records into public landing indexes:
aetherpak build-site --pages-url https://flatpak.org --site-dir _siteresolve-channel
Resolves Flatpak channel names from Git ref metadata:
aetherpak resolve-channel --ref-type tag --ref-name v1.0.0inspect-repo
Extracts metadata from an existing OSTree repository:
aetherpak inspect-repo --repo-path repoconfig
Gets, sets, or displays configuration parameter settings (supports flat and nested dot-notation keys):
# Get a configuration value
aetherpak config get remote_name
aetherpak config get branding.logo_url
# Set a configuration value
aetherpak config set remote_name custom-remote
aetherpak config set branding.logo_url https://new-logo.png
# Show resolved configuration and active overrides
aetherpak config showPersistent configuration flags applicable to all executions:
--config <path>Custom path to configuration file (default is aetherpak.yaml or aetherpak.yml).--output-dir <path>Base directory for all output assets unless overridden.--no-signDisables GPG signing of repositories and OCI images entirely.--allow-unsignedAllows publishing and building unsigned repositories/images if GPG keys are missing.--linter-exceptions-file <path>Local path to a JSON configuration file containing app-specific or wildcard linter exceptions.--linter-exception <rule>Inline flatpak-builder-lint rule to ignore (can be specified multiple times).-v, --verboseEnables granular log logging.--json-logEmits logs in structured JSON lines for logging backends.--plainDisables terminal color codes, emojis, and styling grids.--no-colorAlias flag for --plain.Developer Configuration
AetherPak CLI loads config instructions dynamically. Below is an example of an aetherpak.yaml configuration mapping multiple source structures:
registry: ghcr.io
oci_repository: my-org/my-app
pages_url: https://flatpak.example.com
remote_name: example-repo
output_dir: .aetherpak-output
no_sign: false
repo_title: "My Custom Flatpak Repository"
channel_mappings:
"main": "beta"
"staging/*": "alpha"
linter:
strict: true
ignore_rules: ["appstream-screenshot-missing"]
exceptions: ["appstream-license-missing"]
exceptions_file: "linter-exceptions.json"
defaults:
ccache: true
run_linter: true
state_dir: ".builder-state"
remotes:
flathub: https://dl.flathub.org/repo/flathub.flatpakrepo
flatpaks:
- remote: flathub
ref: org.gnome.Sdk//45
branding:
logo_url: "https://example.com/logo.png"
accent_color: "#a855f7"
footer_text: "Custom Repo Landing Page Footer"
index_template: "templates/custom_index.html"
apps:
- id: org.example.App
manifest: apps/org.example.App/manifest.json
runtime: gnome-50
arches: [x86_64, aarch64]
run-linter: true
remotes:
repoA: https://example.com/repoA.flatpakrepo
flatpaks:
- remote: repoA
ref: org.gnome.Sdk.ExtensionA//45
- id: com.example.Other
branch: beta
bundles:
x86_64:
url: https://upstream.com/Other_x86_64.flatpak
sha256: 2159fc643175dcf54f8b9293f48fb8b11577fa0ea5514...
Custom Index Templating
AetherPak CLI supports custom landing page templates using Go's html/template engine. This allows you to generate a fully customized HTML index page detailing all the repository applications, releases, and installation steps.
To use a custom template, configure branding.index_template in aetherpak.yaml, or pass the --index-template flag (or AETHERPAK_INDEX_TEMPLATE env var) to aetherpak build-site / aetherpak release.
Template Context Fields
.RemoteNameFlatpak remote repository name..RepoTitleRepository title..PagesURLURL where static pages are hosted..RepoHomepageHomepage URL link..RuntimeRepoUpstream runtime dependency repository URL..LogoURLLogo image URL..LogoHTMLPre-formatted HTML image tag for the logo..FaviconURLPage favicon URL..AccentColorHex color code brand accent..FooterTextCustom footer HTML..Signing.EnabledWhether GPG signing is enabled (bool)..Signing.FingerprintGPG public key fingerprint..Signing.PublicKeyPath to public key file (sigs/key.asc)..AppsList of application records. Each app exposes:
• .ID: App identifier (e.g. org.example.App)•
.Name: App name from AppStream, falling back to ID•
.Summary: App summary from AppStream metadata•
.Icon: URL to 64x64 app icon•
.Branches: Sorted list of release branches
.Apps.BranchesList of branches under an app. Each branch exposes:
• .Branch: Branch name (e.g. stable, beta)•
.Arches: List of supported architectures•
.Timestamp: Latest release UNIX timestamp•
.FormattedDate: Formatted release date (Jan 02, 2006)•
.InstalledSize: Installed size in bytes•
.DownloadSize: Download size in bytes•
.Commit: Flatpak commit identifier•
.RefFile: Path to download flatpakref file•
.InstallCmd: Client-side installation command helper
Template Helper Functions
join <slice> <sep>Joins a string slice. Example: {{join .Arches ", "}}formatSize <bytes>Formats raw bytes to a human-readable size. Example: {{formatSize .InstalledSize}}formatDate <time> <layout>Formats a UNIX timestamp using a Go time layout. Example: {{formatDate .Timestamp "2006-01-02"}}Example Custom Template
<!DOCTYPE html>
<html>
<head>
<title>{{.RepoTitle}}</title>
<link rel="icon" href="{{.FaviconURL}}">
</head>
<body>
<h1>{{.RepoTitle}}</h1>
{{range .Apps}}
<div class="app-card">
{{if .Icon}}<img src="{{.Icon}}" width="64">{{end}}
<h2>{{.Name}} ({{.ID}})</h2>
<p>{{.Summary}}</p>
<h3>Releases</h3>
<ul>
{{range .Branches}}
<li>
Branch: <strong>{{.Branch}}</strong> | Arches: {{join .Arches ", "}}
<br>Released on: {{.FormattedDate}} | Size: {{formatSize .InstalledSize}}
<br>Install: <code>{{.InstallCmd}}</code>
</li>
{{end}}
</ul>
</div>
{{end}}
<footer>{{.FooterText}}</footer>
</body>
</html>