feat(manifest): embed per-build metadata and publish unified firmware manifest#25414
feat(manifest): embed per-build metadata and publish unified firmware manifest#25414mrpollo wants to merge 7 commits into
Conversation
|
The easiest thing would be to generate all of this at build time where everything is easily available, but I think it would depend how and where we want to update the manifest. If the manifest is updated by each build individually that would simplify a lot of things in PX4 itself, but then we'd have more to worry about in atomically updating the manifest.json in S3. Alternatively if we want to do bulk manifest.json updates in a single job maybe we should push everything we possibly need into a .px4 file. |
e34de42 to
4e2ff49
Compare
|
This pull request has been closed after being marked as stale with no further activity. Thank you for the time and effort you put into this contribution. If you’d like to continue the discussion or update the work, please feel free to reopen it or submit a new PR. |
|
@mrpollo I pulled the feature branch, built for the 6xrt target and flashed the .px4 using QGC linux daily and then went back to QGC 4.4.5 and flashed the .px4 file using that and didn't see any issues there flashing either. |
4e2ff49 to
3f7fe9e
Compare
71cdd74 to
3b7a55b
Compare
|
This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there: https://discuss.px4.io/t/px4-dev-call-jan-14-2026-team-sync-and-community-q-a/48289/2 |
|
This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there: https://discuss.px4.io/t/px4-dev-call-jan-21-2026-team-sync-and-community-q-a/48330/3 |
|
I spoke with @bkueng, and we agreed that the better approach would be to unify the JSON for the manifest into a single one that includes all releases and all variants instead of an index manifest and having to fetch the releases indepednently, the main argument for this would be the experience for users when they have a board that might be available for specific releases, for those in the originally proposed approach QGC would have to continuously fetch releases until it finds one that matches the hardware which will add more complexity to QGC. I will be working on an update to this PR that takes this feedback into account, and update ASAP |
3b7a55b to
49c3a94
Compare
Update: Unified single-file manifestPer @bkueng's feedback, this has been reworked from the two-tier approach (per-release What changed
Test manifestA test manifest with 5 real releases (891 firmware builds) is live at: Summary view: {
"format_version": 2,
"latest_stable": "v1.16.1",
"latest_beta": "v1.17.0-beta1",
"latest_dev": "v1.17.0-alpha1",
"releases": {
"v1.15.0": { "channel": "stable", "builds": 93 },
"v1.16.0": { "channel": "stable", "builds": 208 },
"v1.16.1": { "channel": "stable", "builds": 170 },
"v1.17.0-alpha1": { "channel": "dev", "builds": 209 },
"v1.17.0-beta1": { "channel": "beta", "builds": 211 }
}
}Each release entry contains all builds inline with full metadata (board_id, git_hash, image_size, download URL, board manifest when available). Total uncompressed size: ~330KB for 5 releases / 891 builds. Quick jq examples# Get latest pointers
curl -s https://px4-travis.s3.amazonaws.com/Firmware/manifest.json | jq '{latest_stable, latest_beta, latest_dev}'
# Find all firmware for board_id 53 (FMU v6x)
curl -s https://px4-travis.s3.amazonaws.com/Firmware/manifest.json | jq '.releases[].builds[] | select(.board_id == 53) | {version, filename}'
# List all releases
curl -s https://px4-travis.s3.amazonaws.com/Firmware/manifest.json | jq '.releases | to_entries[] | {version: .key, channel: .value.channel, builds: .value.build_count}' |
|
Hell yeah!. Thanks Ramon, looking good. Is this complete on the PX4 side now? Just needing a QGC implementation? |
|
I think this PR still needs to clarify under what circumstances the manifest is built and updated, and ensure those are documented somewhere, otherwise, we might be good for now. Regarding the QGC implementation, here's the early draft mavlink/qgroundcontrol#13966 |
49c3a94 to
0480e51
Compare
0565304 to
96a3570
Compare
|
No flaws found |
Probably not, given there is a fallback. However I would like some screenshots of real examples of what a user sees when this is set - like your image in #25414 (comment) As the image there is now, most of the string is the board type, which is already known by QGC. So you could default those to just the variant string. What would the vehicle type be for your variant |
Let's do it in a follow up PR to keep this clean |
|
This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there: https://discuss.px4.io/t/px4-dev-call-feb-11-2026-team-sync-and-community-q-a/48479/2 |
|
This pull request has been mentioned on Discussion Forum for PX4, Pixhawk, QGroundControl, MAVSDK, MAVLink. There might be relevant details there: https://discuss.px4.io/t/px4-dev-call-feb-18-2026-team-sync-and-community-q-a/48516/2 |
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Replace the two-tier approach (per-release manifest + top-level index) with a single unified manifest containing all releases and their builds inline. This allows QGC to fetch one file to find firmware for any board across all releases, avoiding the need to fetch many per-release manifests. Schema uses format_version 2 with releases as a dict keyed by version for O(1) upserts. The manifest is stored at s3://px4-travis/Firmware/manifest.json and updated on every CI build (tags + main/stable/beta branches). Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Add human-readable labels and firmware classification to the build manifest so ground stations like QGC can display friendly names and filter builds by category. New fields: - label_pretty: human-readable variant name (e.g. "Multicopter") - firmware_category: auto-detected classification - "vehicle" for multicopter, fixedwing, vtol, rover, uuv, spacecraft - "peripheral" for CAN sensor nodes (GPS, flow, mag, etc.) - "bootloader" for bootloader/canbootloader - "dev" for everything else (default, zenoh, mavlink-dev, etc.) Peripheral detection uses ROMFSROOT="cannode" which is shared by all ~18 CAN sensor boards across ARK, Holybro, CUAV, Freefly, Matek, NXP. A build-time warning fires when an unrecognized label falls through to "dev", so new vehicle types are not silently hidden from end users. Boards can override via CONFIG_BOARD_FIRMWARE_CATEGORY in .px4board. CONFIG_BOARD_LABEL_PRETTY set on all px4/fmu-v6x variants as Phase 1. Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Move the shebang to line 1 so direct execution works on Linux; the vim modeline was sitting above it and silently breaking ./Tools/px_mkfw.py. Fix _merge_manifest to only merge dict values into dst["hardware"] when the key is "hardware". The previous structure ran the isinstance check unconditionally, so any dict-valued field in the fragment would have been shoved into dst["hardware"] regardless of its key, and could KeyError if a non-"hardware" dict arrived first. It only worked today because "hardware" happened to be the only dict in the fragment. Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Tag every build entry with artifact_type="px4" so the manifest schema can represent non-.px4 producers in the future (VOXL2 .deb, Linux tarballs, etc.) without a format_version bump. Purely additive: older QGC ignores the unknown field, newer consumers branch on it. Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Add an explicit "variant" field to the per-build manifest, sourced from
CMake's ${LABEL} variable which is already derived from the .px4board
filename stem (e.g. multicopter.px4board → "multicopter"). This is the
authoritative source of the variant name: CMake uses it everywhere else
in the tree for board selection.
Previously the variant was implicit in "target" (last underscore-
separated segment), forcing consumers to string-split and assume the
target always follows <board>_<variant>. Now it's a stable, machine-
readable field alongside target and label_pretty.
detect_firmware_category() now takes the variant as its first argument
instead of re-deriving it from target, removing a duplicated parse.
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
96a3570 to
170b7b4
Compare
💡 Commit messages could be improvedNot blocking, but these commit messages could use some cleanup.
See the commit message convention for details. This comment will be automatically removed once the issues are resolved. |
|
No broken links found in changed files. |
|
What is this waiting on? Can we get this and the QGC PR across the finish line soon? |
|
I just stumbled on this as well. Yes, this or something like that would be great! |


This PR adds comprehensive firmware manifest metadata to PX4 builds, enabling better firmware discovery and management for tools like QGroundControl. Per-build metadata is generated from the defconfig and CMake board variables, embedded into each
.px4file, and aggregated into a single unified manifest on S3 that QGC and other tools can consume.Changes
1. Board-level manifest generation
Files:
Tools/manifest/gen_board_manifest_from_defconfig.py,platforms/nuttx/CMakeLists.txtvariantfield sourced from CMake's${LABEL}(the.px4boardfilename stem, e.g.multicopter.px4board→"multicopter")add_custom_command2. Manifest bundled into *.px4 files
Files:
Tools/px_mkfw.py.px4file now contains amanifestobject with board metadatamanifest_versionandsha256sumfields_merge_manifesthelper merges the per-build JSON fragment into the firmware descriptor3. Label and category fields
Files:
Kconfig,Tools/manifest/gen_board_manifest_from_defconfig.py,boards/px4/fmu-v6x/*.px4boardCONFIG_BOARD_LABEL_PRETTY: human-readable variant name shown in QGC (e.g. "Multicopter")CONFIG_BOARD_FIRMWARE_CATEGORY: override for auto-detected category (vehicle,peripheral,dev,bootloader)CONFIG_BOARD_ROMFSROOT(cannode→ peripheral)px4/fmu-v6xvariants; follow-up PR will cover the remaining ~258.px4boardfilesartifact_typediscriminator (flat field, value"px4") to allow future non-.px4producers (VOXL2.deb, Linux tarballs) to coexist in the same manifest without aformat_versionbump4. Unified firmware manifest
Files:
Tools/manifest/update_firmware_manifest.py*.px4files in an artifacts directory and extracts their embedded metadatas3://px4-travis/Firmware/manifest.jsoncontains all releases and all builds for O(1) lookupformat_version: 2withreleasesas a dict keyed by versionlatest_*per channel5. CI integration
Files:
.github/workflows/build_all_targets.ymlOn version tag releases:
manifest.jsonfrom S3 as a workflow artifact (90-day retention)update_firmware_manifest.pyto upsert this release into the unified manifestmanifest.jsonto S3 and attaches it to the GitHub releaseArchitecture
Example Manifest
{ "format_version": 2, "updated_at": 1738890000, "latest_stable": "v1.16.1", "latest_beta": "v1.17.0-beta1", "latest_dev": "v1.17.0-alpha1", "releases": { "v1.16.1": { "channel": "stable", "release_date": "2026-01-15", "build_count": 170, "builds": [ { "filename": "px4_fmu-v6x_multicopter.px4", "url": "https://github.com/PX4/PX4-Autopilot/releases/download/v1.16.1/px4_fmu-v6x_multicopter.px4", "sha256sum": "abc123...", "image_size": 1234567, "board_id": 53, "artifact_type": "px4", "manifest": { "name": "px4_fmu-v6x", "target": "px4_fmu-v6x_multicopter", "variant": "multicopter", "label_pretty": "Multicopter", "firmware_category": "vehicle", "manufacturer": "Holybro", "hardware": { "architecture": "arm", "chip": "stm32h753ii", "vendor_id": "0x3185", "product_id": "0x0038", "productstr": "Pixhawk 6X" } } } ] } } }A live test manifest with 5 real releases and 891 firmware builds is published at px4-travis.s3.amazonaws.com/Firmware/manifest.json.
Scope
Manifest generation currently runs only for NuttX targets (via
platforms/nuttx/CMakeLists.txt). VOXL2 (qurt/posix), Linux SBCs, and SITL targets are not yet indexed; extending coverage to non-NuttX producers is a follow-up. Theartifact_typediscriminator is in place so those can land additively without a schema break.Related
CONFIG_BOARD_LABEL_PRETTYacross remaining ~258.px4boardfiles