diff --git a/package_release.py b/package_release.py
new file mode 100755
index 0000000000000000000000000000000000000000..9cf0c597227ff18387459f6f7bb45785b48dd1c1
--- /dev/null
+++ b/package_release.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+import argparse
+import glob
+import json
+import os
+import sys
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--images-dir",
+        help="""Yocto images directory""",
+        dest="images_dir",
+        required=True,
+    )
+    parser.add_argument(
+        "--release-dir",
+        help="""release directory""",
+        dest="release_dir",
+        required=True,
+    )
+
+    args, _ = parser.parse_known_args()
+
+    # Get bitbake variables from testdata.json file
+    testdata_files = glob.glob(args.images_dir + "/*.testdata.json")
+    if not testdata_files:
+        sys.exit("ERROR: no *.testdata.json file found in images directory")
+
+    with open(testdata_files[0], "r") as f:
+        buildvars = json.load(f)
+
+    machine = buildvars["MACHINE"]
+    version = buildvars["DISTRO_VERSION"]
+    fstypes = buildvars["IMAGE_FSTYPES"].split()
+    image = buildvars["IMAGE_NAME"] + buildvars["IMAGE_NAME_SUFFIX"]
+
+    # Set directories (use relative path)
+    release_name = "GUF-Yocto-%s" % version
+    output_dir = "%s/%s/prebuilt_images" % (args.release_dir, release_name)
+    images_dir = os.path.relpath(args.images_dir, output_dir)
+
+    # Create output directory
+    os.makedirs(output_dir, exist_ok=True)
+
+    # Create symlinks for all rootfs images
+    for fstype in fstypes:
+        filename = "%s.%s" % (image, fstype)
+        source_file = "%s/%s" % (images_dir, filename)
+        target_file = "%s/%s-%s-root.%s" % (output_dir, release_name, machine, fstype)
+        print("%s -> %s" % (target_file, source_file))
+        os.symlink(source_file, target_file)
+
+
+if __name__ == "__main__":
+    main()