aetherpak.yaml Configuration Reference#
1. Overview#
aetherpak.yaml is the central configuration file for the AetherPak toolchain. It declares every aspect of your Flatpak repository in a single, version-controllable file: which apps to build and publish, where to host them, how to brand the landing page, which linting rules to enforce, and how to map Git branches to Flatpak release channels.
AetherPak is designed so that the configuration file is optional for one-off operations. All parameters can be supplied as CLI flags or AETHERPAK_-prefixed environment variables, and most individual commands will run without any file on disk. The configuration file becomes essential when you need to :
- Manage multiple apps from a single repository
- Persist build defaults (ccache, linter settings, remote dependencies) so they don't need to be re-specified on every run
- Drive the automated plan / release cycle via the
aetherpak planandaetherpak releasecommands - Customize branding for your landing page beyond what workflow inputs allow
- Define channel mappings that control how Git refs are translated into Flatpak branch names
When used with the AetherPak GitHub Actions reusable workflow , aetherpak.yaml is the primary way to configure multi-app builds. The workflow reads the file via the config: input and orchestrates a parallel build-publish pipeline for all declared apps.
Note: For single-app repositories where you only need to build and publish one manifest, you may not need an
aetherpak.yamlat all — the reusable workflow'smanifest-path:input is sufficient. Reach foraetherpak.yamlwhen you need more than the defaults provide.
2. File Location#
Default discovery#
AetherPak looks for the configuration file in the current working directory — for GitHub Actions workflows, this is the root of your repository checkout. It searches for the following names in order :
aetherpak.yamlaetherpak.yml
If neither is found and no explicit path was given, the CLI continues with built-in defaults (equivalent to an empty config). Commands that require a config — such as aetherpak plan — will report a clear error if no file exists.
Overriding the path#
CLI flag: Pass --config <path> to any command to load a specific file regardless of the current directory :
aetherpak release --config configs/aetherpak-nightly.yaml
Environment variable: Set AETHERPAK_CONFIG to the desired path. This is especially useful in CI environments where you want to vary the config without modifying the command line:
export AETHERPAK_CONFIG=configs/aetherpak-nightly.yaml
aetherpak release
GitHub Actions workflow input: Pass the repository-relative path via the config: input to the reusable workflow :
jobs:
publish:
uses: aetherpak/actions/.github/workflows/publish.yml@v3
with:
config: aetherpak.yaml # default; can be a different path
If you maintain multiple independent publishing configurations (for example, a stable channel and a nightly channel), you can run two workflow jobs pointing to different config files. Give each a unique concurrency-group: to prevent race conditions on the shared index :
jobs:
publish-stable:
uses: aetherpak/actions/.github/workflows/publish.yml@v3
with:
config: aetherpak.yaml
concurrency-group: publish-stable
publish-nightly:
uses: aetherpak/actions/.github/workflows/publish.yml@v3
with:
config: aetherpak-nightly.yaml
concurrency-group: publish-nightly
3. Top-level Fields Reference#
These fields appear at the root of aetherpak.yaml and configure global repository behavior .
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
registry | string | No | ghcr.io | OCI registry hostname where application layers are pushed. Use ghcr.io for GitHub Container Registry, quay.io for Red Hat Quay, or any OCI-compatible registry. |
pages_url | string | No¹ | Project Pages URL | The public base URL where the repository index and landing page are served. Used in .flatpakrepo and .flatpakref files. |
oci_repository | string | No | $GITHUB_REPOSITORY or remote_name | The registry path for OCI image storage (e.g., myorg/myrepo). Defaults to the GitHub repository slug in Actions, or falls back to remote_name if set. |
remote_name | string | No | <owner>-<repo> | The Flatpak remote name users will add with flatpak remote-add. Also the base name for the generated .flatpakrepo file. |
repo_title | string | No | Flatpak Repository | Human-readable title displayed on the landing page and embedded in .flatpakrepo metadata. |
repo_homepage | string | No | — | URL for the repository's homepage, embedded in .flatpakrepo metadata. |
runtime_repo | string | No | Flathub URL | The .flatpakrepo URL used to resolve runtime dependencies. Defaults to https://flathub.org/repo/flathub.flatpakrepo. |
no_sign | boolean | No | false | When true, disables GPG signing entirely. Use this only in development — signed repositories provide cryptographic verification for users. |
output_dir | string | No | — | Base directory for all build outputs (state, site, records, ccache). When set, per-app state_dir and ccache_dir default to subdirectories under this path. |
channel_mappings | map[string]string | No | — | Maps Git ref names or glob patterns to Flatpak branch names. See Section 7 for full details. |
defaults | object | No | — | Inheritable build defaults applied to all apps. See Section 4. |
branding | object | No | — | Landing page customization. See Section 5. |
linter | object | No | — | Global linter configuration. See Section 6. |
apps | list | Yes² | — | List of application definitions. See Section 8. |
¹
pages_urlis technically optional in the config (it can be supplied as thepages-urlworkflow input orAETHERPAK_PAGES_URLenvironment variable), but it must be resolved to a value before publishing. The generated.flatpakrepoand.flatpakreffiles will be incorrect without it.
²
appsis required in config-mode operation. In manifest-mode (using--manifeston the CLI ormanifest-path:in workflows), you do not need anappslist.
Examples#
registry: ghcr.io
pages_url: https://myorg.github.io/myrepo
oci_repository: myorg/myrepo
remote_name: myorg-apps
repo_title: "My Application Repository"
repo_homepage: https://myorg.example.org
# Custom registry (Quay.io)
registry: quay.io
oci_repository: myorg/flatpak-apps
pages_url: https://apps.myorg.example.org
4. defaults Section#
The defaults block sets inheritable build settings that are applied to every app in the apps list. Individual apps can override or extend these settings .
defaults:
ccache: true
ccache_dir: .ccache
state_dir: .state
run_linter: true
builder_args:
- --install-deps-from=flathub
remotes:
flathub: https://flathub.org/repo/flathub.flatpakrepo
custom_repo:
url: https://example.com/repo.flatpakrepo
gpg_verify: true
gpg_key: https://example.com/keys/gpg.key
sig_verify_url: https://example.com/signatures
flatpaks:
- remote: flathub
ref: org.freedesktop.Sdk.Extension.rust-stable
Fields#
| Field | Type | Default | Description |
|---|---|---|---|
ccache | boolean | false | Enable the compiler cache for all builds. Speeds up repeated builds significantly. |
ccache_dir | string | .ccache | Directory for the compiler cache. If output_dir is set at the top level, defaults to <output_dir>/.ccache. |
state_dir | string | .state | Directory for flatpak-builder state (SDK caches, dependencies). If output_dir is set, defaults to <output_dir>/.state. |
run_linter | boolean | false | Run flatpak-builder-lint for all apps by default. Can be overridden per app. |
builder_args | list[string] | [] | Extra command-line arguments passed to flatpak-builder. Applied to all apps; replaced entirely if an app specifies its own builder_args. Note: As of v0.21.0, the CLI automatically injects --install-deps-from flags for each configured remote in the remotes section, so explicitly specifying --install-deps-from in builder_args is typically unnecessary. |
no_install_deps | boolean | false | Disable automatic injection of --install-deps-from flags when running flatpak-builder. |
no_flathub | boolean | false | Disable automatic injection of the flathub remote as a dependency source. |
remotes | map[string, string | RemoteConfig] | {} | Additional Flatpak remotes to configure before building. Each entry can be a simple URL string or an exploded RemoteConfig object with fields: url (string, required), gpg_verify (boolean, optional), gpg_key (string, optional - can be a local path, URL, or inline ASCII-armored GPG public key block), sig_verify_url (string, optional). Merged into each app's remotes; app values override on name conflicts. |
flatpaks | list[{remote, ref}] | [] | Flatpak packages to install before building, referenced by remote name and ref. Prepended to each app's flatpaks list; duplicates are removed. |
Inheritance behavior#
AetherPak's Normalize() function applies defaults to each app according to the following rules :
ccache — Inherited if the app does not explicitly set ccache. If set in defaults but not in an app entry, the app uses the defaults value.
ccache_dir and state_dir — Inherited from defaults if the app does not specify its own value. If output_dir is set at the top level, the defaults are <output_dir>/.ccache and <output_dir>/.state respectively.
run_linter — If defaults.run_linter is true and an app does not explicitly enable linting, the app inherits true. (Inheritance is one-directional: a false default does not force apps to disable linting if they individually enable it.)
builder_args — The defaults list is copied to any app whose builder_args list is empty. If an app specifies any builder_args, the defaults list is not merged — the app's list takes over entirely .
remotes — The defaults map is merged into each app's remotes map. If both defaults and the app define a remote with the same name, the app's definition wins .
flatpaks — The defaults list is prepended to each app's flatpaks list, and duplicates (by remote + ref pair) are removed .
Tip: Use
defaultswhen most of your apps share the same build configuration. Declare the common settings once indefaults, then only specify overrides in individual app entries.
Example: enabling linting globally, disabling for one app#
defaults:
run_linter: true # Lint every app by default
remotes:
flathub: https://flathub.org/repo/flathub.flatpakrepo
apps:
- id: org.example.AppOne
manifest: apps/AppOne/manifest.json
# Inherits run_linter: true from defaults
- id: org.example.AppTwo
manifest: apps/AppTwo/manifest.json
run_linter: false # Override: skip linting for this app
Note: The
--install-deps-from=flathubflag is automatically injected by the CLI whenflathubis configured in theremotessection (as of v0.21.0), so it no longer needs to be specified inbuilder_args.
5. branding Section#
The branding block customizes the appearance of the generated landing page (index.html) without requiring a fully custom template. All fields are optional — omitting the entire branding section produces a clean default page .
branding:
logo_url: https://example.org/logo.png
favicon_url: https://example.org/favicon.ico
accent_color: "#3584e4"
footer_text: "© 2026 My Project. Licensed under GPL-3.0."
index_template: .github/templates/index.html
Fields#
| Field | Type | Description |
|---|---|---|
logo_url | string | Full URL to your project's logo image. Displayed prominently on the landing page header. |
favicon_url | string | Full URL to a favicon image. Used as the browser tab icon. |
accent_color | string | Primary accent color as a CSS hex value (e.g., "#3584e4"). Applied to buttons, links, and highlighted UI elements on the landing page. |
footer_text | string | Text displayed in the landing page footer. HTML is supported, allowing links, bold text, and other inline markup. |
index_template | string | Repository-relative path to a custom Jinja2/Go template file that replaces the default landing page. See note below. |
Custom templates (index_template)#
For complete control over the landing page, provide a custom template via branding.index_template . The path is resolved relative to the repository root when aetherpak build-site runs.
branding:
index_template: .github/templates/index.html
Note:
index_templatecan also be supplied as theindex-template:workflow input or the--index-templateCLI flag. These override the value set inaetherpak.yaml. For the full precedence order and a complete guide to template variables, see Custom Index Landing Page Templates .
Workflow input overrides#
The branding fields set in aetherpak.yaml can be overridden for specific workflow runs using workflow inputs :
| Workflow input | Overrides |
|---|---|
index-template | branding.index_template |
remote-name | remote_name (top-level) |
pages-url | pages_url (top-level) |
landing-page: false | Skips index.html generation entirely |
6. linter Section#
The top-level linter block configures flatpak-builder-lint behavior globally across all apps. Individual app entries can extend this configuration with additional exceptions .
linter:
strict: false
ignore_rules:
- no-appstream-screenshot-urls
- appstream-screenshot-missing
exceptions_file: .linter-exceptions.json
Fields#
| Field | Type | Default | Description |
|---|---|---|---|
strict | boolean | true | When true, any lint failure causes the build to fail immediately. When false, failures are logged as warnings but the build continues. |
ignore_rules | list[string] | [] | List of flatpak-builder-lint rule IDs to suppress globally. |
exceptions | list[string] | [] | Alias for ignore_rules. Both lists are merged and deduplicated before use — you may use either or both . |
exceptions_file | string | — | Repository-relative path to a JSON exceptions file. Uses the same format as upstream flatpak-builder-lint, making it easy to reuse exception files from Flathub workflows. |
Note:
ignore_rulesandexceptionsare functionally identical. They exist as aliases to accommodate different naming conventions. At runtime, both lists are merged, deduplicated, and treated as a single set of suppressed rules .
Strict mode and defaults#
The strict field defaults to true when the linter is enabled, meaning any lint violation fails the build. For repositories that want to run the linter for visibility without blocking on every warning, set strict: false:
linter:
strict: false # Warn but don't fail
ignore_rules:
- appstream-screenshot-missing
Enabling the linter globally#
The linter block configures how the linter behaves; whether it runs at all is controlled by defaults.run_linter (or per-app run_linter). To enable linting for all apps with consistent settings:
defaults:
run_linter: true
linter:
strict: false
ignore_rules:
- no-appstream-screenshot-urls
Per-app overrides#
Apps can define their own linter block that extends (not replaces) the global configuration . Per-app exceptions are additive: they are merged with global exceptions before each lint invocation. For the full per-app linter reference, see Section 8: apps Entries.
See also: Working with Linter Exceptions for a comprehensive guide covering exception file formats, per-app configuration, CLI flags, and environment variable overrides .
7. channel_mappings#
The channel_mappings field controls how Git references (branches and tags) are transformed into Flatpak branch names at publish time . This configuration lets you customize the deployment channel without changing your Git workflow — for example, mapping version tags to the stable channel, main to beta, and feature branches to nightly or custom channel names .
Purpose and behavior#
Without channel mappings, AetherPak applies a base resolution strategy :
- Tags resolve to
stable - Default branch (e.g.
main) resolves tobeta - Any other branch resolves to the Git ref name itself
The channel_mappings dictionary overrides these defaults by mapping Git ref patterns to Flatpak branch names. Mappings support both exact matches and glob patterns, and are applied in a specific lookup order to handle overlapping patterns predictably .
Lookup order#
When resolving a Git ref to a Flatpak channel, AetherPak performs four lookups in sequence and uses the first match :
- Exact match on ref name — if
channel_mappings["main"]exists and the ref name ismain, use that mapping - Glob match on ref name — if a pattern like
release/*matches the ref name viafilepath.Match(), use the mapping - Exact match on base channel — if the base resolution produces
stableandchannel_mappings["stable"]exists, use that mapping - Glob match on base channel — if a pattern matches the base-resolved channel, use the mapping
This order allows you to rename channels, route specific branches, or apply wildcards to branch families.
Pattern precedence#
When multiple glob patterns match the same ref or base channel, AetherPak applies the following tie-breaking rules :
- Longest pattern first — the pattern with the most characters wins
- Alphabetical order — if two patterns have the same length, the lexicographically smaller pattern wins
This ensures deterministic and predictable behavior when overlapping wildcards are defined.
Glob syntax#
Patterns use Go's filepath.Match() syntax :
| Pattern | Matches |
|---|---|
* | Any sequence of characters in a single path segment |
? | Any single character |
[abc] | Any character in the set a, b, or c |
[a-z] | Any character in the range a to z |
Note: Double-star (
**) is not supported —*does not match/, so patterns likerelease/*only match single-level paths likerelease/1.0, notrelease/1.0/patch.
Patterns are validated at configuration load time using filepath.Match() . Invalid patterns cause the configuration to fail validation and stop the workflow.
Common examples#
Example 1: Map default branch to beta#
channel_mappings:
main: beta
Pushes to main publish to the beta channel instead of the default stable .
Example 2: Version tags and releases to stable#
channel_mappings:
"v*": stable
"release/*": stable
- Tags matching
v*(e.g.v1.0.0,v2.1.3) publish tostable - Branches matching
release/*(e.g.release/1.0,release-2.1) publish tostable
Example 3: Multi-channel deployment#
channel_mappings:
main: beta
"staging/*": alpha
"release-*": stable
stable: prod
main→betastaging/patch-1→alpharelease-1.0.0→stable- Tags (base resolution:
stable) →prodvia thestable: prodmapping
This configuration renames the stable channel to prod for tagged releases while routing development branches to dedicated channels .
Example 4: Feature branches to nightly#
channel_mappings:
main: stable
"feature-*": nightly
mainpublishes asstable- Any branch starting with
feature-publishes asnightly
Impact on published artifacts#
The channel name determined by channel_mappings affects:
- OCI image tag — images are tagged as
<app-id>-<branch>-<arch>, so changing the channel changes the tag under which the image is pushed - Flatpak branch — the
org.flatpak.reflabel embedded in the OCI image and theindex/staticentry both use the resolved channel as the branch name - Generated
.flatpakreffiles — each file is named<app-id>-<channel>.flatpakrefand embedsBranch=<channel>in its content - Installation commands — the landing page displays
flatpak install <remote> <app-id>//<channel>using the resolved channel
Global vs per-app scope#
channel_mappings is a global field in aetherpak.yaml . All apps in a multi-app repository use the same mappings.
If an app declares an explicit branch field in its apps entry , that branch name is used as-is and overrides both base resolution and channel_mappings. This per-app override is useful for third-party bundles with fixed channels or when you want one app to always publish to a specific branch regardless of the Git ref .
Pattern validation#
Invalid glob patterns cause configuration validation to fail at load time :
channel_mappings:
"[invalid": stable # unmatched bracket → validation error
Run aetherpak plan --config aetherpak.yaml locally to validate your patterns before pushing.
Use cases#
- Renaming default channels: map
stable→productionto align with your team's terminology - Multi-stage deployments: separate
alpha,beta, andstablechannels driven by branch naming conventions - Third-party bundle ingestion: remap upstream channels (e.g.
master) to your own naming scheme - Custom branch workflows: route experimental branches to a
nightlychannel without changing your CI triggers
8. apps Entries#
The apps list is the core of the AetherPak configuration file. Each entry defines a Flatpak application to build or publish, its source (manifest or pre-built bundles), target architectures, and build/lint overrides .
Field Reference#
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Reverse-DNS Flatpak application identifier (e.g., org.example.App). Must match ^[A-Za-z0-9][A-Za-z0-9._-]{0,254}$ . |
manifest | string | Conditional | Relative path to the Flatpak manifest file. Mutually exclusive with bundles . |
bundles | map[string]Bundle | Conditional | Map of architecture → {url, sha256} for pre-built .flatpak bundles. Mutually exclusive with manifest . |
arches | []string | No | Target architectures (x86_64, aarch64). Defaults to [x86_64] for manifest apps . |
branch | string | No | Flatpak branch/channel name. If not set, automatically resolved from the manifest file's branch field (if present), otherwise defaults to stable. Must match ^[A-Za-z0-9._-]+$ . |
run_linter / run-linter | bool | No | Override global linting setting for this app. Both kebab-case and snake_case are accepted . |
ccache | *bool | No | Override ccache setting from defaults. Inherits from defaults.ccache if not set . |
ccache_dir | string | No | Override ccache directory. Inherits from defaults.ccache_dir or defaults to .ccache . |
state_dir | string | No | Override state directory. Inherits from defaults.state_dir or defaults to .state . |
builder_args | []string | No | Additional flatpak-builder arguments. Replaces defaults.builder_args if non-empty . Note: As of v0.21.0, --install-deps-from flags are auto-injected for remotes configured in the remotes section. |
no_install_deps | *bool | No | Override defaults.no_install_deps. Disable automatic injection of --install-deps-from flags when running flatpak-builder. |
no_flathub | *bool | No | Override defaults.no_flathub. Disable automatic injection of the flathub remote as a dependency source. |
remotes | map[string, string | RemoteConfig] | No | Additional Flatpak remotes. Each entry can be a simple URL string or an exploded RemoteConfig object with fields: url (string, required), gpg_verify (boolean, optional), gpg_key (string, optional - can be a local path, URL, or inline ASCII-armored GPG public key block), sig_verify_url (string, optional). Merged with defaults.remotes, app values override conflicts . |
flatpaks | []FlatpakDep | No | Additional Flatpak dependencies to pre-install ({remote, ref}). Prepended to defaults.flatpaks, deduplicated . |
linter | *LinterConfig | No | Per-app linter config (strict, ignore_rules, exceptions, exceptions_file). Additive to global linter config . |
runtime | string | Deprecated | Deprecated field, no longer used . |
runtime-version | string | Deprecated | Deprecated field, no longer used . |
Note: Each app entry must specify exactly one of
manifestorbundles— not both .
Source: manifest vs bundles#
Apps can be built from source via a Flatpak manifest or imported from pre-built .flatpak bundles.
manifest#
The manifest field points to a relative path to a Flatpak manifest (JSON or YAML format) :
apps:
- id: org.example.MyApp
manifest: apps/org.example.MyApp/org.example.MyApp.json
arches: [x86_64, aarch64]
branch: stable
Validation rules :
- Must be a relative path (no absolute paths starting with
/) - Must not contain
..segments (no path traversal)
bundles#
The bundles field maps architectures to pre-built bundle URLs and checksums :
apps:
- id: com.example.ThirdPartyApp
bundles:
x86_64:
url: https://upstream.example.com/app_x86_64.flatpak
sha256: "abc123...64hexchars"
aarch64:
url: https://upstream.example.com/app_aarch64.flatpak
sha256: "def456...64hexchars"
branch: stable
Bundle validation rules :
- Only
x86_64andaarch64architectures are supported urlmust start withhttp://orhttps://sha256must be exactly 64 lowercase hexadecimal characters- Both
urlandsha256are required for each architecture
Use bundles for third-party upstream apps or pre-built binaries from other build systems .
Architectures and Branches#
arches#
The arches field specifies target architectures for the app . Supported values are x86_64 and aarch64 . For manifest-based apps, defaults to [x86_64] .
apps:
- id: org.example.App
manifest: app.json
arches: [x86_64, aarch64] # Build for both architectures
branch#
The branch field sets the Flatpak branch name, which determines the release channel . Must match the pattern ^[A-Za-z0-9._-]+$ .
apps:
- id: org.example.App
manifest: app.json
branch: beta # Publish to the 'beta' branch
Branch resolution order:
When branch is not explicitly set in aetherpak.yaml, AetherPak attempts to resolve it automatically :
- If the
manifestfile path is specified, parse the manifest and use thebranchfield from the Flatpak manifest if it exists - If no branch is found in the manifest (or no manifest is specified), default to
stable
This automatic resolution is useful when the Flatpak manifest already declares a branch (e.g., for nightly builds or beta channels), allowing you to avoid duplicating that value in aetherpak.yaml.
Branch names affect how users install the app and are visible in .flatpakref files. The global channel_mappings configuration can automatically map git branches to Flatpak branch names.
Build and Linter Overrides#
run_linter / run-linter#
Both run_linter (snake_case) and run-linter (kebab-case) are accepted and control whether linting runs for this app . If defaults.run_linter is true and the app does not explicitly disable it, linting is inherited .
defaults:
run_linter: true
apps:
- id: org.example.AppOne
manifest: app1.json
run-linter: false # Disable linting for this app
- id: org.example.AppTwo
manifest: app2.json
# Inherits run_linter: true from defaults
linter#
Per-app linter configuration overrides or extends the global linter block . Supported fields: strict, ignore_rules, exceptions, exceptions_file .
linter:
strict: true
exceptions:
- global-exception
apps:
- id: org.example.App
manifest: app.json
linter:
strict: false # Override strictness for this app
exceptions:
- app-specific-exception # Merged with global exceptions
exceptions_file: app-exceptions.json # Overrides global file
Behavior:
strict: Overrides global strict modeignore_rulesandexceptions: Merged with global lists (additive)exceptions_file: Overrides global exceptions file if specified
ccache, ccache_dir, state_dir#
These fields override build caching and state storage :
defaults:
ccache: true
ccache_dir: .ccache
state_dir: .state
apps:
- id: org.example.App
manifest: app.json
ccache: false # Disable ccache for this app
state_dir: custom-state # Use custom state directory
Inheritance rules :
ccache: Inherits fromdefaults.ccacheif not setccache_dir: Inherits fromdefaults.ccache_dir, defaults to.ccache(or<output_dir>/.ccache)state_dir: Inherits fromdefaults.state_dir, defaults to.state(or<output_dir>/.state)
builder_args#
Additional arguments passed to flatpak-builder . If the app specifies builder_args, they replace (not merge with) defaults.builder_args .
defaults:
remotes:
flathub: https://flathub.org/repo/flathub.flatpakrepo
apps:
- id: org.example.App
manifest: app.json
builder_args:
- --disable-updates # Replaces defaults.builder_args entirely
Note: As of v0.21.0, the CLI automatically injects
--install-deps-fromflags for each remote configured in theremotessection, so you typically do not need to manually specify--install-deps-frominbuilder_argsunless you want to control this behavior explicitly.
Remotes and Dependencies#
remotes#
Additional Flatpak remotes to add before building . Each entry maps a remote name to either a simple flatpakrepo URL string or an exploded RemoteConfig object. Merged with defaults.remotes, with app values overriding conflicts .
defaults:
remotes:
flathub: https://flathub.org/repo/flathub.flatpakrepo
apps:
- id: org.example.App
manifest: app.json
remotes:
flathub-beta: https://flathub.org/beta-repo/flathub-beta.flatpakrepo
custom_repo:
url: https://example.com/repo.flatpakrepo
gpg_verify: true
gpg_key: https://example.com/keys/gpg.key
sig_verify_url: https://example.com/signatures
# flathub from defaults is also included
RemoteConfig fields:
url(string, required): The flatpakrepo URLgpg_verify(boolean, optional): Enable/disable GPG verification for this remotegpg_key(string, optional): GPG public key (can be a local path, URL, or inline ASCII-armored GPG public key block)sig_verify_url(string, optional): Signature lookaside URL
Validation rules :
- Remote names and URLs must be non-empty
- URLs must start with
http://orhttps://
flatpaks#
Flatpak dependencies to pre-install before building . Each entry requires remote and ref fields. App dependencies are appended to defaults.flatpaks with deduplication .
defaults:
flatpaks:
- remote: flathub
ref: org.freedesktop.Platform//23.08
apps:
- id: org.example.App
manifest: app.json
flatpaks:
- remote: flathub
ref: org.freedesktop.Sdk.Extension.llvm17//23.08
# org.freedesktop.Platform from defaults is also included
Validation rules :
remotemust be non-emptyrefmust be non-empty
Complete Example#
# aetherpak.yaml
defaults:
ccache: true
run_linter: true
remotes:
flathub: https://flathub.org/repo/flathub.flatpakrepo
flatpaks:
- remote: flathub
ref: org.freedesktop.Platform//23.08
linter:
strict: true
exceptions:
- appstream-screenshot-missing
apps:
# Manifest-based app with overrides
- id: org.example.AppOne
manifest: apps/org.example.AppOne/app.json
arches: [x86_64, aarch64]
branch: stable
run-linter: true
ccache: true
builder_args:
- --disable-updates
linter:
strict: false
exceptions:
- app-specific-exception
# Bundle-based app
- id: com.example.ThirdPartyApp
bundles:
x86_64:
url: https://upstream.example.com/app_x86_64.flatpak
sha256: "abc123def456...64hexchars"
aarch64:
url: https://upstream.example.com/app_aarch64.flatpak
sha256: "789012fed654...64hexchars"
branch: stable
run_linter: false
# Minimal manifest app (inherits defaults)
- id: org.example.AppTwo
manifest: apps/org.example.AppTwo/app.json
# Inherits: arches=[x86_64], branch=stable, run_linter=true, ccache=true
Note: The
--install-deps-from=flathubflag is automatically injected by the CLI (as of v0.21.0) whenflathubis configured in theremotessection, so it no longer needs to be specified inbuilder_args.
9. bundles Map#
The bundles field allows you to ingest pre-built Flatpak bundles (.flatpak files) instead of building from a manifest. This is useful for third-party apps, vendor-provided binaries, or situations where you want to distribute an existing .flatpak file through your repository.
Structure#
bundles is a map from architecture name to a Bundle object containing a URL and SHA-256 checksum :
apps:
- id: com.example.ThirdPartyApp
branch: stable
bundles:
x86_64:
url: https://releases.example.com/ThirdPartyApp_x86_64.flatpak
sha256: "2159fc643175dcf54f8b9293f48fb8b11c41a87fe31684ee4c5d4e94c6f37a42"
aarch64:
url: https://releases.example.com/ThirdPartyApp_aarch64.flatpak
sha256: "a7b3c9d2e1f04586738c9d2b4f1e3a6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2"
Fields#
Each bundle entry has two required fields :
url: string, required. Must start withhttp://orhttps://.sha256: string, required. Must be exactly 64 lowercase hexadecimal characters .
Supported Architectures#
Only x86_64 and aarch64 are supported as bundle keys . Apps using bundles do not need to set the arches field separately; architectures are derived from the keys in the bundles map .
Rebind Behavior#
AetherPak downloads each bundle, verifies its SHA-256 checksum, imports it into an OSTree repository, and rebinds the commit to the declared branch name . This rebind step is critical because upstream bundles often embed the wrong branch name (such as app/<id>/<arch>/master). The prep-bundle action rewrites both the ref name and the xa.ref binding to match your declared branch, ensuring that flatpak install accepts the bundle correctly.
When to Use bundles vs manifest#
-
Use
bundleswhen:- You are redistributing a third-party app where you don't control the source.
- An upstream vendor provides ready-made
.flatpakfiles. - Your build framework (e.g., Electron or Tauri) produces a
.flatpakdirectly. - You want to mirror another project's
.flatpakfrom GitHub Releases or another artifact store.
-
Use
manifestwhen:- You are building your own app from source.
- You need control over build options, dependencies, or the build environment.
- You want to customize the Flatpak manifest for your application.
An app must specify exactly one of manifest or bundles .
Adding Bundles with the CLI#
The aetherpak add --bundle-url <url> command automatically downloads the bundle, computes its SHA-256, and adds it to your aetherpak.yaml, saving manual checksum calculation.
SHA-256 Update Warning#
If the upstream URL points to a static location that is updated over time (e.g., a "latest" URL), the SHA-256 checksum in your configuration must be updated whenever the file changes. AetherPak will fail verification if the downloaded file does not match the declared checksum.
Example with Both Architectures#
apps:
- id: com.example.ThirdPartyApp
branch: stable
bundles:
x86_64:
url: https://releases.example.com/ThirdPartyApp_x86_64.flatpak
sha256: "2159fc643175dcf54f8b9293f48fb8b11c41a87fe31684ee4c5d4e94c6f37a42"
aarch64:
url: https://releases.example.com/ThirdPartyApp_aarch64.flatpak
sha256: "a7b3c9d2e1f04586738c9d2b4f1e3a6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2"
10. Validation Rules#
AetherPak validates all configuration at load time to catch errors early and provide clear feedback. Validation checks ensure that app IDs follow the correct format, paths are safe, URLs are well-formed, and required fields are present. If validation fails, the CLI reports the specific error and exits before any build or release operation begins .
App ID#
The id field is required for every app and must follow a strict format .
Requirements:
- Cannot be empty
- Must match the regular expression:
^[A-Za-z0-9][A-Za-z0-9._-]{0,254}$
Rules:
- First character must be alphanumeric (
A-Z,a-z, or0-9) - Remaining characters (up to 254 additional characters) can be alphanumeric, dot (
.), underscore (_), or hyphen (-) - Maximum total length: 255 characters
Valid examples:
org.gnome.Sudokucom.example.Appio.github.MyApp
Invalid examples:
.BadStart— cannot start with a dotmy app— spaces not allowedapp/id— slashes not allowed- A string with more than 255 characters
Branch#
The branch field must follow a simple naming pattern .
Requirements:
- Must match the regular expression:
^[A-Za-z0-9._-]+$
Rules:
- Only alphanumeric characters, dots (
.), underscores (_), and hyphens (-) are allowed - No slashes or spaces
- Cannot be empty (defaults to
"stable"if not specified)
Valid examples:
stablebeta1.0my-branchv2.0-rc1
Invalid examples:
my/branch— slashes not allowedmy branch— spaces not allowed
Architectures#
AetherPak supports only two architectures .
Supported architectures:
x86_64aarch64
Any other value will cause a validation error. This applies to both the arches list for manifest-based apps and the keys in the bundles map for bundle-based apps.
Error example:
app "org.example.App": unsupported arch "arm"
Manifest vs Bundles#
Every app must specify exactly one of manifest or bundles .
Rules:
- If both are set, validation fails
- If neither is set, validation fails
- Only one source type is allowed per app
Error examples:
app "org.example.App": exactly one of 'manifest' or 'bundles' is required
Manifest Path#
When using a manifest field, the path must be relative and safe .
Requirements:
- Must be a relative path
- Cannot start with
/(no absolute paths) - Cannot contain path traversal segments (
..)
Valid examples:
flatpak-manifest.jsonmanifests/org.example.App.jsonbuild/manifest.yaml
Invalid examples:
/etc/manifest.json— absolute path not allowed../manifests/app.json— path traversal not allowed../../etc/passwd— path traversal not allowed
Error examples:
app "org.example.App": 'manifest' must be a relative path, cannot be absolute
app "org.example.App": 'manifest' must be a relative path with no '..' segments
Bundle URL and SHA256#
When using bundles, each architecture entry must include both a url and a sha256 field .
Requirements:
- Architecture key must be a supported architecture (
x86_64oraarch64) urlis required and must start withhttp://orhttps://sha256is required and must be exactly 64 lowercase hexadecimal characters
Valid example:
bundles:
x86_64:
url: https://example.com/app.flatpak
sha256: a3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Invalid examples:
ftp://example.com/app.flatpak— only HTTP/HTTPS allowedA3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855— uppercase not alloweda3b0c442— too short (must be exactly 64 characters)
Error examples:
app "org.example.App": unsupported bundle arch "arm64"
app "org.example.App" bundle "x86_64": 'url' and 'sha256' are required
app "org.example.App" bundle "x86_64": 'url' must start with http:// or https://
app "org.example.App" bundle "x86_64": 'sha256' must be 64 lowercase hex characters
Remote Validation#
Both the defaults.remotes and per-app remotes fields are validated .
Requirements:
- Remote name cannot be empty
- Remote URL cannot be empty
- Remote URL must start with
http://orhttps://
Valid example:
remotes:
flathub-beta: https://flathub.org/beta-repo/flathub-beta.flatpakrepo
Invalid examples:
- Empty name as a map key
- Empty string as URL value
ftp://example.com/repo.flatpakrepo— only HTTP/HTTPS allowed
Error examples:
app "org.example.App": flatpak remote name cannot be empty
app "org.example.App": flatpak remote "my-remote" URL cannot be empty
app "org.example.App": flatpak remote "my-remote" URL "ftp://..." must start with http:// or https://
Flatpak Dependency Validation#
Both the defaults.flatpaks and per-app flatpaks fields are validated .
Requirements:
remotefield cannot be emptyreffield cannot be empty
Valid example:
flatpaks:
- remote: flathub
ref: org.freedesktop.Platform//23.08
Invalid examples:
- Missing
remotefield - Missing
reffield - Empty string for either field
Error examples:
app "org.example.App": flatpak dependency remote cannot be empty
app "org.example.App": flatpak dependency ref cannot be empty
Channel Mappings Pattern Validation#
The channel_mappings field uses glob patterns that are validated at config load time .
Requirements:
- Each pattern key must be valid glob syntax according to Go's
filepath.Matchfunction
Valid examples:
main— exact matchrelease/*— glob wildcardv*— prefix glob
Invalid examples:
[— unmatched bracketrelease/[abc— unclosed character class
Error example:
invalid channel mapping pattern "release/[abc": syntax error in pattern
Warning: Pattern validation occurs at load time. Invalid patterns prevent the entire configuration from loading, so test your patterns carefully.
Common Validation Errors#
| Error Message | Cause | Fix |
|---|---|---|
app entry missing 'id' | The id field is empty or not set | Add a valid reverse-DNS app ID |
'id' must match format ... | App ID contains invalid characters or format | Use only alphanumeric, ., _, -, and start with alphanumeric |
'branch' must match format ... | Branch name contains slashes or spaces | Use only alphanumeric, ., _, - |
unsupported arch "arm" | Architecture is not x86_64 or aarch64 | Use only x86_64 or aarch64 |
exactly one of 'manifest' or 'bundles' is required | Both or neither are specified | Specify exactly one: either manifest or bundles |
'manifest' must be a relative path | Path starts with / or contains .. | Use a relative path without traversal |
'url' must start with http:// or https:// | Bundle URL uses unsupported protocol | Use HTTP or HTTPS only |
'sha256' must be 64 lowercase hex characters | SHA256 is wrong length or has uppercase | Use exactly 64 lowercase hex characters |
flatpak remote name cannot be empty | Remote map has empty key | Provide a non-empty remote name |
flatpak dependency ref cannot be empty | Flatpak ref is missing or empty | Provide a valid Flatpak ref string |
invalid channel mapping pattern | Glob syntax error | Fix the glob pattern syntax |
11. Precedence and Overrides#
AetherPak configuration follows a well-defined precedence hierarchy, allowing you to set defaults in aetherpak.yaml while selectively overriding them for specific environments or one-off operations. Understanding this hierarchy is essential for managing multi-environment workflows and debugging configuration issues.
Configuration Precedence Stack#
Configuration values are resolved from multiple sources in the following order, from highest to lowest priority :
- CLI flags — Explicit command-line flags like
--config,--output-dir,--run-linter - Environment variables — Variables with the
AETHERPAK_prefix (and special casesOCI_USERNAME,OCI_PASSWORD) - Configuration file — Settings in
aetherpak.yamlor the file specified by--config - Built-in defaults — Fallback values applied by the
Normalize()method when no other source provides a value
Higher-priority sources always override lower-priority ones. For example, --output-dir=/tmp/build on the command line takes precedence over output_dir: dist in aetherpak.yaml, which in turn overrides the built-in default.
Where GitHub Actions Fit#
GitHub Actions workflow inputs translate directly to environment variables with the AETHERPAK_ prefix . This means workflow inputs sit at precedence level 2 — higher than the config file but lower than explicit CLI flags.
Practical implication: If you pass config: staging.yaml as a workflow input but then run a custom step with aetherpak build --config production.yaml, the CLI flag wins. This allows debugging and selective overrides even within automated workflows.
Environment Variable Mapping#
The CLI uses Viper for configuration management with the following mapping rules :
- All environment variables are prefixed with
AETHERPAK_ - Both
.(dot) and-(hyphen) in config keys are replaced with_(underscore) for environment variables - Environment variable names are case-insensitive but conventionally uppercase
Examples:
| Config Key | Environment Variable |
|---|---|
registry | AETHERPAK_REGISTRY |
pages_url | AETHERPAK_PAGES_URL |
oci_repository | AETHERPAK_OCI_REPOSITORY |
remote_name | AETHERPAK_REMOTE_NAME |
output_dir | AETHERPAK_OUTPUT_DIR |
branding.index_template | AETHERPAK_BRANDING_INDEX_TEMPLATE |
linter.strict | AETHERPAK_LINTER_STRICT |
channel_mappings.main | AETHERPAK_CHANNEL_MAPPINGS_MAIN |
Special cases without the prefix :
OCI_USERNAME→oci_usernameOCI_PASSWORD→oci_password
These are non-prefixed for compatibility with standard container registry authentication patterns.
Fields That Can Be Overridden#
The following table shows which configuration fields support override from environment variables or CLI flags:
| Field | Environment Variable | CLI Flag | Notes |
|---|---|---|---|
registry | AETHERPAK_REGISTRY | — | OCI registry host |
pages_url | AETHERPAK_PAGES_URL | — | Public hosting URL |
oci_repository | AETHERPAK_OCI_REPOSITORY | — | Registry image path |
remote_name | AETHERPAK_REMOTE_NAME | — | Flatpak remote name |
output_dir | AETHERPAK_OUTPUT_DIR | --output-dir | Base directory for artifacts |
defaults.run_linter | AETHERPAK_DEFAULTS_RUN_LINTER | --run-linter | Enable/disable linting |
defaults.ccache_dir | AETHERPAK_DEFAULTS_CCACHE_DIR | --ccache-dir | ccache directory |
defaults.state_dir | AETHERPAK_DEFAULTS_STATE_DIR | --state-dir | State directory |
defaults.builder_args | AETHERPAK_DEFAULTS_BUILDER_ARGS | --builder-arg | Extra flatpak-builder flags |
defaults.remotes | — | --flatpak-remote | Additional Flatpak remotes |
defaults.flatpaks | — | --flatpak-dep | Additional packages to install |
linter.exceptions | AETHERPAK_LINTER_EXCEPTIONS | --linter-exception | Linter rule suppressions |
linter.exceptions_file | AETHERPAK_LINTER_EXCEPTIONS_FILE | --linter-exceptions-file | Path to exceptions JSON file |
branding.index_template | AETHERPAK_INDEX_TEMPLATE | --index-template | Custom landing page template |
Fields That Cannot Be Overridden#
Some configuration fields must be defined in aetherpak.yaml and cannot be overridden from the environment or CLI:
appslist — The registry of applications must be in the config filedefaultssection — While individual defaults can be overridden (see table above), the defaults block itself must be in the configbrandingsection — Onlyindex_templatecan be overridden; other branding fields likelogo_url,accent_color,footer_textmust be in the configchannel_mappingspatterns — Individual mappings can be set viaAETHERPAK_CHANNEL_MAPPINGS_<KEY>, but the full pattern set is best managed in the config file
Override Examples#
Example 1: Using a Staging Registry#
Override the registry for a staging deployment without modifying aetherpak.yaml:
AETHERPAK_REGISTRY=ghcr.io/myorg/staging aetherpak plan
This builds the plan using the staging registry while keeping all other config values from aetherpak.yaml.
Example 2: Per-Environment Output Directories#
Use different output directories for local development vs. CI:
# aetherpak.yaml
output_dir: dist
# Local development — override to keep builds isolated
aetherpak build --output-dir=/tmp/aetherpak-builds
# CI — use the config default (dist)
aetherpak build
Example 3: Suppressing Linter Rules in CI#
Temporarily suppress a linter rule for a known issue without editing the config :
aetherpak build \
--manifest apps/org.example.App/manifest.json \
--run-linter \
--linter-exception appstream-screenshot-missing
CLI flags have the highest precedence , so this override applies even if aetherpak.yaml specifies different exceptions.
Example 4: Custom Index Template in Workflow#
Override the landing page template using a workflow input :
jobs:
publish:
uses: aetherpak/actions/.github/workflows/publish.yml@v3
with:
config: aetherpak.yaml
index-template: .github/workflows/templates/custom-index.html
The workflow input is translated to AETHERPAK_INDEX_TEMPLATE, which overrides the branding.index_template setting in the config file.
How Overrides Are Applied#
The override mechanism works differently depending on the configuration source :
- At startup, Viper loads environment variables with the
AETHERPAK_prefix - During command initialization, the
bindFlags()function automatically populates unset CLI flags from Viper (which includes both env vars and config file values) - Flags explicitly set on the command line are marked as "changed" and skip the Viper population step, ensuring CLI flags always win
- Per-command logic checks
cmd.Flags().Changed("flag-name")to determine whether a flag was explicitly set and should override config/defaults
This design ensures a clear and predictable precedence order while allowing flexible per-environment and per-command customization.
Tip: Use
aetherpak --verboseto see which config file is loaded and which values are applied. Debug output includes lines likeUsing config file: aetherpak.yamland shows the final resolved configuration.
Tip: For reproducible CI builds, prefer setting values in
aetherpak.yamlrather than environment variables. Use env vars and CLI flags for overrides specific to a deployment environment or debugging scenario.
12. Minimal Example#
The following is the smallest valid aetherpak.yaml for a single manifest-based app. Every line is required or strongly recommended for a working deployment .
# aetherpak.yaml — minimal single-app configuration
# Where to push OCI application layers (host + path)
registry: ghcr.io
oci_repository: myorg/myrepo # typically matches your GitHub repo slug
# Where the index and landing page are publicly served
pages_url: https://myorg.github.io/myrepo
# One app to build and publish
apps:
- id: org.example.MyApp # Reverse-DNS Flatpak application ID
manifest: org.example.MyApp.json # Path to your Flatpak manifest (relative to repo root)
This configuration:
- Builds
org.example.MyAppforx86_64(the default architecture) - Publishes it to the
stableFlatpak branch (the default) - Stores layers in
ghcr.io/myorg/myrepo - Generates a landing page and
.flatpakreposerved fromhttps://myorg.github.io/myrepo
Note:
pages_urlandoci_repositorycan be omitted if they are passed as workflow inputs (pages-url:andoci-repository:) or environment variables (AETHERPAK_PAGES_URL,AETHERPAK_OCI_REPOSITORY). Declaring them in the file is recommended for consistency.
13. Full Example#
This comprehensive example demonstrates every feature of aetherpak.yaml, including global defaults, branding, linting, channel mappings, and multiple apps with different configurations.
# aetherpak.yaml - Full configuration example demonstrating all features
# ──────────────────────────────────────────────────────────────────────────────
# Global Settings
# ──────────────────────────────────────────────────────────────────────────────
# The OCI registry host where images will be pushed (default: "ghcr.io")
registry: ghcr.io
# The public URL where your repository landing page and index files are hosted
# (required for full publish cycle)
pages_url: https://flatpak.example.com
# The OCI repository path where images are stored (defaults to GITHUB_REPOSITORY)
# Format: owner/repo
oci_repository: example-org/flatpak-apps
# The Flatpak remote name shown to users (also the .flatpakrepo filename)
# Defaults to "<owner>-<repo>" format
remote_name: example-apps
# Human-readable repository title shown on the landing page
# Default: "Flatpak Repository"
repo_title: "Example Organization App Repository"
# URL shown as the repository homepage in metadata (optional)
repo_homepage: https://example.org
# Fallback .flatpakrepo URL for runtime dependency resolution
# Default: Flathub URL (https://dl.flathub.org/repo/flathub.flatpakrepo)
runtime_repo: https://dl.flathub.org/repo/flathub.flatpakrepo
# Disable GPG signing entirely (default: false)
# Set to true to skip signing; end-users will install with --no-gpg-verify
no_sign: false
# Base directory for all output artifacts (optional)
# When set, all output paths default to subdirectories under this path
output_dir: _output
# ──────────────────────────────────────────────────────────────────────────────
# Channel Mappings
# ──────────────────────────────────────────────────────────────────────────────
# Map git references (branches/tags) to Flatpak branch names
# Supports glob patterns (filepath.Match syntax)
# Resolution order: exact match first, then glob patterns (longest pattern wins)
channel_mappings:
main: beta # Push to 'main' branch → 'beta' channel
"release/*": stable # All release/* branches → 'stable' channel
"v*": stable # Version tags (v1.0, v2.1.0, etc.) → 'stable' channel
"staging/*": alpha # Staging branches → 'alpha' channel
# ──────────────────────────────────────────────────────────────────────────────
# Defaults Section
# ──────────────────────────────────────────────────────────────────────────────
# Global build defaults inherited by all apps (unless overridden per-app)
defaults:
# Enable compiler cache (default: nil/disabled)
ccache: true
# Directory to store ccache artifacts (default: ".ccache")
ccache_dir: .build-cache/ccache
# Directory for flatpak-builder state (default: ".state")
state_dir: .build-cache/state
# Run linter checks for all apps by default (default: false)
run_linter: true
# Additional flatpak-builder command-line arguments
# Applied to all apps; individual apps can override by providing their own non-empty list
# Note: As of v0.21.0, --install-deps-from flags are auto-injected for remotes configured
# in the remotes section, so you typically don't need to specify them here manually
builder_args:
- --sandbox
- --disable-rofiles-fuse
# Additional Flatpak remotes to register before building
# Merged with per-app remotes (app values win on conflicts)
remotes:
flathub: https://dl.flathub.org/repo/flathub.flatpakrepo
gnome-nightly: https://nightly.gnome.org/gnome-nightly.flatpakrepo
# Flatpak runtimes/SDKs to pre-install before building
# Prepended to per-app flatpaks; duplicates are automatically deduplicated
flatpaks:
- remote: flathub
ref: org.freedesktop.Platform//23.08
- remote: flathub
ref: org.freedesktop.Sdk//23.08
# ──────────────────────────────────────────────────────────────────────────────
# Branding Section
# ──────────────────────────────────────────────────────────────────────────────
# Customize the look and feel of the generated landing page
branding:
# Full URL to your project logo (displayed in the landing page header)
logo_url: "https://example.org/assets/logo.png"
# Full URL to your favicon (browser tab icon)
favicon_url: "https://example.org/assets/favicon.ico"
# Primary accent color for the landing page (CSS hex color)
# Default: "#8b5cf6"
accent_color: "#3584e4"
# Footer text displayed at the bottom of the landing page
# Supports HTML markup
footer_text: "© 2025 Example Organization | Powered by AetherPak"
# Path to a custom Jinja2/Go HTML template for the index page
# Replaces the default landing page entirely
# See documentation for template context structure and helper functions
index_template: templates/custom-index.html
# ──────────────────────────────────────────────────────────────────────────────
# Linter Section
# ──────────────────────────────────────────────────────────────────────────────
# Global linter configuration (can be overridden per-app)
linter:
# Treat linter warnings/errors as fatal (default: true)
# Set to false to report issues without failing the build
strict: false
# List of flatpak-builder-lint rule IDs to bypass globally
ignore_rules:
- appstream-screenshot-missing
- appstream-license-missing
# Alternative/alias for ignore_rules (both lists are merged)
# Can be overridden via AETHERPAK_LINTER_EXCEPTIONS or --linter-exception flag
exceptions:
- desktop-file-icon-key-absent
# Path to a JSON file containing app-specific linter exceptions
# Format: {"org.example.App": ["rule1"], "*": ["rule2"]}
# Can be overridden via AETHERPAK_LINTER_EXCEPTIONS_FILE env var
exceptions_file: linter-exceptions.json
# ──────────────────────────────────────────────────────────────────────────────
# Apps
# ──────────────────────────────────────────────────────────────────────────────
apps:
# ─────────────────────────────────────────────────────────────────────────
# App 1: Manifest-based, multi-arch, with per-app overrides
# ─────────────────────────────────────────────────────────────────────────
- id: org.example.AppOne
# Relative path to the Flatpak manifest file (mutually exclusive with bundles)
manifest: apps/org.example.AppOne/org.example.AppOne.json
# Target architectures to build
# Default for manifest apps: ["x86_64"]
arches:
- x86_64
- aarch64
# Flatpak branch/channel (default: "stable")
branch: stable
# Override global run_linter setting for this app
# Supports both run_linter and run-linter forms (kebab-case is normalized)
run-linter: true
# Per-app linter configuration
# Additive to global linter config (rules are merged, not replaced)
linter:
strict: true
ignore_rules:
- appstream-summary-too-long
exceptions:
- finish-args-arbitrary-dbus-access
# Enable ccache for this app (overrides defaults.ccache)
ccache: true
# Custom ccache directory for this app
ccache_dir: .build-cache/ccache-appone
# Custom state directory for this app
state_dir: .build-cache/state-appone
# Per-app builder arguments
# If non-empty, replaces defaults.builder_args (does not merge)
builder_args:
- --sandbox
- --ccache
# Per-app remotes (merged with defaults.remotes; app values win on conflicts)
remotes:
kde-runtime: https://distribute.kde.org/kderuntime.flatpakrepo
# Per-app flatpaks (prepended to defaults.flatpaks; duplicates are deduplicated)
flatpaks:
- remote: kde-runtime
ref: org.kde.Platform//6.5
# ─────────────────────────────────────────────────────────────────────────
# App 2: Manifest-based, minimal (inherits most defaults)
# ─────────────────────────────────────────────────────────────────────────
- id: com.example.AppTwo
# Minimal configuration: inherits all defaults
manifest: apps/com.example.AppTwo/com.example.AppTwo.yaml
# Single architecture (default: ["x86_64"])
# Explicitly declared here for clarity
arches:
- x86_64
# Uses default branch (stable), default run_linter (true from defaults),
# default builder_args, remotes, and flatpaks
# ─────────────────────────────────────────────────────────────────────────
# App 3: Bundle-based, multi-arch, different branch
# ─────────────────────────────────────────────────────────────────────────
- id: net.example.ThirdPartyApp
# Bundles field: map of arch → {url, sha256} for prebuilt .flatpak files
# Mutually exclusive with manifest (exactly one required)
bundles:
x86_64:
# URL must start with http:// or https://
url: https://releases.example.net/ThirdPartyApp_x86_64.flatpak
# SHA256 must be exactly 64 lowercase hex characters
sha256: 2159fc643175dcf54f8b9293f48fb8b11c41a87fe31684ee4c5d4e94c6f37a42
aarch64:
url: https://releases.example.net/ThirdPartyApp_aarch64.flatpak
sha256: a7b3c9d2e1f04586738c9d2b4f1e3a6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2
# Bundles are fetched, verified, imported, and rebound to this branch
branch: beta
# Disable linting for bundle-based apps (linting only applies to manifest builds)
run_linter: false
# Note: ccache, builder_args, remotes, and flatpaks are ignored for bundle apps
# (they only apply to manifest-based builds)
What this example demonstrates#
This configuration showcases:
- Top-level global settings — registry, pages_url, oci_repository, remote_name, repo_title, repo_homepage, runtime_repo, no_sign, output_dir
- Channel mappings — glob patterns mapping git refs to Flatpak branches (
main → beta,release/* → stable,v* → stable,staging/* → alpha) - Defaults section — ccache, ccache_dir, state_dir, run_linter, builder_args, remotes, and flatpaks that are inherited by all apps
- Branding section — logo_url, favicon_url, accent_color, footer_text, and index_template for customizing the landing page
- Linter section — strict mode, ignore_rules, exceptions, and exceptions_file for controlling linter behavior
- Manifest-based app (AppOne) with both arches, per-app linter overrides, custom branch, builder_args, remotes, and flatpaks
- Minimal manifest app (AppTwo) that inherits most defaults, demonstrating the simplest manifest-based configuration
- Bundle-based app (ThirdPartyApp) with both architectures, URL + SHA256 checksums, different branch, and linting disabled
- Both kebab-case and snake_case forms —
run-linterandrun_linter(both are accepted and normalized) - Per-app overrides — showing how individual apps can override ccache, ccache_dir, state_dir, builder_args, remotes, and flatpaks
- Inheritance and merging behavior — remotes are merged (app wins conflicts), flatpaks are prepended and deduplicated, builder_args are replaced if non-empty