Compose generation
A Fedora compose is a single run of Pungi that produces a complete set of repositories, installation trees, and images for a given point in the distribution’s development. This page covers how composes are generated for both Rawhide and branched releases.
For where composes fit in the broader release lifecycle, see Fedora release process.
Overview
Pungi is the compose tool Fedora uses to assemble distribution trees. Fedora-specific configuration lives in pungi-fedora; upstream Pungi development is on Pagure.
A typical compose run proceeds through several phases:
-
Init : load variant definitions, fetch comps files, prepare work directories
-
Pkgset : query Koji for the latest builds in the configured tags, resolve dependencies, and determine the package set for each arch and variant
-
Gather : assemble package repositories (createrepo) for each variant
-
Buildinstall / image phases : submit Koji jobs for installer trees (Lorax), live/cloud images (Kiwi), OSTree commits, and container images
-
Createiso : produce ISO and disk images from completed Koji tasks
-
Extra files and checksums : generate metadata, CHECKSUM files, and compose reports
Most image build work happens in Koji, not on the compose host directly. Pungi submits tasks to Koji builders and waits for them to complete. Koji job templates for Kiwi images are defined in spin-kickstarts and fedora-kiwi-descriptions. Lorax handles network-install and some legacy installer media. Newer atomic and container-native images may use bootc or image-mode tooling alongside the traditional Kiwi and OSTree paths.
The compose driver on Fedora systems is pungi-koji, which integrates Pungi with Koji
task submission and fedora-messaging notifications.
|
If you want to understand what Pungi is doing at any moment, start with
|
Rawhide composes
Trigger and schedule
Rawhide composes run automatically every day at 05:15 UTC on
compose-rawhide01.rdu3.fedoraproject.org.
The cron entry is defined in
roles/releng/templates/rawhide.j2 in the Infra Ansible repo:
15 5 * * * root touch /tmp/fedora-compose-rawhide && TMPDIR=`mktemp -d /tmp/rawhide.XXXXXX` && \
chmod 755 $TMPDIR && cd $TMPDIR && \
git clone https://forge.fedoraproject.org/releng/pungi-fedora.git && \
cd pungi-fedora && \
/usr/local/bin/lock-wrapper rawhide-compose "LANG=en_US.UTF-8 ./nightly.sh" && \
sudo -u ftpsync /usr/local/bin/update-fullfiletimelist ...
nightly.sh clones releng tooling, invokes pungi-koji with
fedora.conf and the --nightly flag, then rsyncs the result to /pub/fedora/linux/development/rawhide,
sends fedora-messaging events, and emails a compose report.
Output location
Composes are stored on koji storage and published at:
-
Compose root:
/compose/rawhide/ -
Latest symlink:
/compose/rawhide/latest-Fedora-Rawhide/
Each compose is a directory named Fedora-Rawhide-YYYYMMDD.n.R where n means nightly
and R is the respin number (.0 for the first run that day, .1 for a same-day respin).
The latest-Fedora-Rawhide symlink updates when a new compose starts, so it always
points at the current or most recent run.
Reading the global log
The file pungi.global.log is the primary diagnostic log.
A successful run shows a sequence of [BEGIN] and [DONE] markers for each phase:
2026-06-08 05:15:03 [INFO ] [BEGIN] ---------- PHASE: INIT ----------
2026-06-08 05:15:18 [INFO ] [DONE ] ---------- PHASE: INIT ----------
2026-06-08 05:15:18 [INFO ] [BEGIN] ---------- PHASE: PKGSET ----------
...
To trace Koji tasks, search the global log (and per-variant logs under logs/) for lines
containing task IDs or Koji URLs.
Pungi logs task submission during buildinstall, createiso, live_media, ostree,
and related phases.
Open the task in the Koji web UI at
https://koji.fedoraproject.org/koji/taskinfo?taskID=<ID> to inspect build logs and failure reasons.
Per-arch and per-variant logs live under logs/<arch>/ and logs/<variant>/.
The logs/depcheck output lists broken dependencies found during the compose.
logs/*verbose files are included in the nightly email report.
Compose STATUS values
Every compose directory contains a STATUS file written by Pungi when the run completes.
The possible values are:
| STATUS | Meaning |
|---|---|
|
Compose is in progress; |
|
All phases completed successfully |
|
Compose finished but one or more optional variants or arches failed; inspect logs for the failing phase |
|
A required phase failed; the compose did not produce a complete tree |
Check STATUS before assuming a compose is usable for testing.
A FINISHED_INCOMPLETE Rawhide compose may still be rsynced to development mirrors if
the primary arches succeeded, but the email report and fedora-messaging events will reflect
the partial failure.
Common failure scenarios
- Broken dependencies in pkgset
-
The pkgset phase cannot resolve all required packages. Check
logs/depcheckand the global log for the specific missing or conflicting RPMs. Fix the offending Koji builds or comps entries, then wait for the next nightly or trigger a respin. - Koji image build failure
-
A Kiwi or Lorax task failed on a Koji builder. Find the task ID in
pungi.global.logor the variant-specific log, then open the task in Koji for the builder log. Common causes include kickstart errors, missing packages in the compose tree, or builder resource limits. - Unsigned builds
-
Pungi may skip or fail on packages that have not been signed yet. Check whether robosignatory is running and whether the build is stuck in a
-signing-pendingtag. See Sign the packages. - OSTree signing wait
-
Rawhide composes use the
pungi-wait-for-signed-ostree-handlernotification script. Atomic variants (Silverblue, Kinoite, and related) may block until OSTree commits are signed. Checklogs/for ostree phase output and Sigul/robosignatory status. - Compose host issues
-
Disk space, git clone failures, or lock contention (
lock-wrapper rawhide-compose) can prevent a compose from starting. Check/tmp/fedora-compose-rawhideon the compose host and releng cron mail (releng-cron@lists.fedoraproject.org).
|
To resume a failed compose in debug mode, set |
Release composes
How release composes differ from Rawhide
Branched and milestone composes use the same Pungi machinery but differ in several ways:
-
Freeze enforcement : compose tags draw from locked Koji tags; only approved builds enter
-
Milestone labels : Beta and Final RC composes carry labels like
Beta-1.5orRC-1.3 -
Manual trigger : RC composes are requested via RelEng tickets, not cron
-
Compose tag snapshot : specific builds are tagged into
f*-composebefore the run -
Configuration : branch-specific configs (
fedora-branched.conf,fedora-beta.conf,fedora-final.conf)
Branched development composes follow a schedule defined in Ansible cron templates for the release branch, similar to Rawhide. Milestone RC composes are one-off runs coordinated with QE.
Running Pungi for a branched release
For day-to-day branched composes, the branch-specific script and config in pungi-fedora
replace nightly.sh / fedora.conf.
The general pungi-koji invocation pattern is:
cd pungi-fedora/
pungi-koji \
--notification-script=/usr/bin/pungi-fedmsg-notification \
--notification-script=pungi-wait-for-signed-ostree-handler \
--config=fedora-branched.conf \
--old-composes=/mnt/koji/compose/{branched} \
--target-dir=/mnt/koji/compose/{branched}
For Beta or Final Release Candidates, RelEng first generates a candidate config:
./create-candidate-configs.py --minor=5 beta
Then reviews the f{branched}-compose tag, tags requested builds, and runs:
./release-candidate.sh
See Beta RC Compose SOP and Final RC Compose SOP for the full tagging and review steps.
Output location
Release composes are published under:
where <BRANCH> is the release number (for example 44 for Fedora 44).
Within that directory, compose IDs follow the pattern Fedora-<BRANCH>-YYYYMMDD.n.R
for development composes or carry milestone labels for RC composes.
As with Rawhide, a latest-Fedora-<name> symlink points at the current compose, and
each directory contains COMPOSE_ID, STATUS, compose/, logs/, and work/ subdirectories.
Composes and the Go/No-Go process
QE validates a specific RC compose against the release validation test plan. The nominated compose ID is recorded in the RelEng ticket and the Go/No-Go meeting agenda.
If the meeting votes Go, RelEng stages that exact compose for mirror publication.
If the vote is No-Go, builds are fixed, a new RC compose is produced with an incremented
global_release minor version, and validation runs again.
See Go/No-Go process for the full lifecycle from compose to mirror publication.
|
Do not stage a compose for public release until Go/No-Go has approved the specific compose ID. Staging the wrong compose means re-running signing and mirror steps. |
Signing
All official Fedora compose artifacts are GPG-signed before they reach public mirrors.
RPM signing
RPMs are signed automatically as they pass through Koji tags via robosignatory. Pungi expects signed builds in the compose tags; unsigned builds can cause compose failures or delays in the OSTree signing handler.
Image and CHECKSUM signing
After a compose is approved for release, RelEng runs staging scripts from releng/tooling:
release-process/staging/stage_release_checksum_sign.sh {branched}_Beta Fedora-{branched}-YYYYMMDD.0 fedora-{branched} 1
release-process/staging/stage_release.sh {branched}_Beta Fedora-{branched}-YYYYMMDD.0 fedora-{branched} 1
stage_release_checksum_sign.sh signs all *CHECKSUM files in the compose tree.
stage_release.sh copies the signed tree to the staging area on mirror master.
|
If signing fails, do not push the compose to mirrors. Fix the signing issue, re-run the staging scripts, and verify signatures before the mirror bit-flip. Unsigned CHECKSUM files or images will break mirror consistency and user verification. |
Verification
Confirm signatures on CHECKSUM files before notifying mirror admins.
After the bit-flip, verify that dl.fedoraproject.org serves the signed tree and that
MirrorManager reports the new release correctly.
For day-to-day signing troubleshooting, see Sign the packages.
Want to help? Learn how to contribute to Fedora Docs ›