diff --git a/apps/artcraft-launcher-web/src/web.rs b/apps/artcraft-launcher-web/src/web.rs
--- a/apps/artcraft-launcher-web/src/web.rs
+++ b/apps/artcraft-launcher-web/src/web.rs
@@ -329,7 +329,7 @@ impl Backend for WebBackend {
     }
 
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: false, reveal_label: "", self_update: false }
+        Capabilities { manage_apps: false, reveal_label: "", self_update: false, install_kinds: Vec::new() }
     }
 
     fn platform(&self) -> Option<Platform> {
diff --git a/apps/artcraft-launcher/src/main.rs b/apps/artcraft-launcher/src/main.rs
--- a/apps/artcraft-launcher/src/main.rs
+++ b/apps/artcraft-launcher/src/main.rs
@@ -768,7 +768,7 @@ mod tests {
             std::mem::take(&mut *self.0.news.lock().unwrap_or_else(PoisonError::into_inner))
         }
         fn capabilities(&self) -> Capabilities {
-            Capabilities { manage_apps: true, reveal_label: "Show in Files", self_update: false }
+            Capabilities { manage_apps: true, reveal_label: "Show in Files", self_update: false, install_kinds: Vec::new() }
         }
         fn platform(&self) -> Option<artcraft_launcher_core::Platform> {
             None
diff --git a/crates/core/src/protocol.rs b/crates/core/src/protocol.rs
--- a/crates/core/src/protocol.rs
+++ b/crates/core/src/protocol.rs
@@ -211,7 +211,7 @@ pub enum Event {
 }
 
 /// What a backend can do on this platform.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Capabilities {
     /// Install, update, remove and launch apps (desktop). Without it the UI offers downloads.
     pub manage_apps: bool,
@@ -220,6 +220,9 @@ pub struct Capabilities {
     /// The launcher can update itself in place and restart (an installed build, not a dev build or
     /// a Flatpak). Without it the UI offers the download instead.
     pub self_update: bool,
+    /// Package formats this backend can install, best first (probed once). Empty means
+    /// unknown: the UI falls back to the platform's download list.
+    pub install_kinds: Vec<PackageKind>,
 }
 
 /// The UI's view of a backend.
diff --git a/crates/core/src/status.rs b/crates/core/src/status.rs
--- a/crates/core/src/status.rs
+++ b/crates/core/src/status.rs
@@ -2,6 +2,7 @@
 
 use serde::{Deserialize, Serialize};
 
+use crate::platform::PackageKind;
 use crate::version::{self, Version};
 
 /// How an installed copy got onto the machine, which decides how to update and remove it.
@@ -47,6 +48,21 @@ impl InstallSource {
     pub fn launcher_can_update(self) -> bool {
         matches!(self, Self::Launcher | Self::MacApp | Self::Msi | Self::AppImage)
     }
+
+    /// The release package format this source corresponds to, if any: a launcher-managed
+    /// copy reports its record's kind instead, and a system package or stray binary has
+    /// no release asset behind it.
+    pub fn package_kind(self) -> Option<PackageKind> {
+        match self {
+            Self::Msi => Some(PackageKind::Msi),
+            Self::Deb => Some(PackageKind::Deb),
+            Self::Rpm => Some(PackageKind::Rpm),
+            Self::Flatpak => Some(PackageKind::Flatpak),
+            Self::AppImage => Some(PackageKind::AppImage),
+            Self::MacApp => Some(PackageKind::Dmg),
+            Self::Launcher | Self::Pacman | Self::Binary => None,
+        }
+    }
 }
 
 /// An installed copy of an app.
@@ -60,6 +76,10 @@ pub struct Installed {
     /// The package that installed it, for package-manager installs (`photocraft-bin`).
     #[serde(default)]
     pub package: Option<String>,
+    /// The package format, when the copy came from a release asset (`None` for copies
+    /// found outside any install the launcher knows: system binaries, AUR packages).
+    #[serde(default)]
+    pub kind: Option<PackageKind>,
 }
 
 /// The status shown on an app's card or row.
@@ -123,7 +143,7 @@ mod tests {
     use super::*;
 
     fn inst(v: &str) -> Installed {
-        Installed { version: version::parse(v), source: InstallSource::Launcher, location: String::new(), package: None }
+        Installed { version: version::parse(v), source: InstallSource::Launcher, location: String::new(), package: None, kind: None }
     }
 
     #[test]
@@ -142,4 +162,18 @@ mod tests {
         assert_eq!(status(Some(&inst("garbage")), found(true)), AppStatus::Installed);
         assert!(AppStatus::UpdateAvailable.is_installed() && !AppStatus::Available.is_installed());
     }
+
+    #[test]
+    fn sources_map_to_their_release_format() {
+        use InstallSource::*;
+        assert_eq!(Msi.package_kind(), Some(PackageKind::Msi));
+        assert_eq!(Deb.package_kind(), Some(PackageKind::Deb));
+        assert_eq!(Rpm.package_kind(), Some(PackageKind::Rpm));
+        assert_eq!(Flatpak.package_kind(), Some(PackageKind::Flatpak));
+        assert_eq!(AppImage.package_kind(), Some(PackageKind::AppImage));
+        assert_eq!(MacApp.package_kind(), Some(PackageKind::Dmg));
+        assert_eq!(Launcher.package_kind(), None, "the record decides");
+        assert_eq!(Pacman.package_kind(), None, "no release asset behind it");
+        assert_eq!(Binary.package_kind(), None, "no release asset behind it");
+    }
 }
diff --git a/crates/native/src/backend.rs b/crates/native/src/backend.rs
--- a/crates/native/src/backend.rs
+++ b/crates/native/src/backend.rs
@@ -969,7 +969,7 @@ impl Backend for NativeBackend {
             Some(Os::Windows) => "Show in Explorer",
             _ => "Show in Files",
         };
-        Capabilities { manage_apps: true, reveal_label, self_update: self.self_install.is_some() }
+        Capabilities { manage_apps: true, reveal_label, self_update: self.self_install.is_some(), install_kinds: crate::install::available_kinds() }
     }
 
     fn platform(&self) -> Option<Platform> {
@@ -1313,7 +1313,7 @@ mod tests {
     }
 
     fn copy(v: &str) -> Installed {
-        Installed { version: version::parse(v), source: InstallSource::Deb, location: String::new(), package: None }
+        Installed { version: version::parse(v), source: InstallSource::Deb, location: String::new(), package: None, kind: None }
     }
 
     #[test]
diff --git a/crates/native/src/detect.rs b/crates/native/src/detect.rs
--- a/crates/native/src/detect.rs
+++ b/crates/native/src/detect.rs
@@ -67,6 +67,7 @@ fn from_manifest(app: &CraftApp, manifest: &Manifest) -> Option<Installed> {
         source: InstallSource::Launcher,
         location: rec.path.display().to_string(),
         package: None,
+        kind: Some(rec.kind),
     })
 }
 
@@ -169,7 +170,13 @@ pub mod macos {
         let full_key = format!("{}Version", app.name);
         let text =
             [full_key.as_str(), "CFBundleShortVersionString", "CFBundleVersion"].iter().find_map(|k| dict.get(k).and_then(plist::Value::as_string));
-        Some(Installed { version: text.and_then(version::parse), source: InstallSource::MacApp, location: path.display().to_string(), package: None })
+        Some(Installed {
+            version: text.and_then(version::parse),
+            source: InstallSource::MacApp,
+            location: path.display().to_string(),
+            package: None,
+            kind: InstallSource::MacApp.package_kind(),
+        })
     }
 }
 
@@ -249,6 +256,7 @@ pub mod windows {
             source: InstallSource::Msi,
             location: m.exe.map_or_else(|| app.name.to_string(), |p| p.display().to_string()),
             package: Some(m.product_code),
+            kind: InstallSource::Msi.package_kind(),
         })
     }
 }
@@ -374,12 +382,24 @@ pub mod linux {
 
     pub fn detect(app: &CraftApp, snapshot: &Snapshot) -> Option<Installed> {
         if let Some((path, version)) = appimages(app).into_iter().next() {
-            return Some(Installed { version, source: InstallSource::AppImage, location: path.display().to_string(), package: None });
+            return Some(Installed {
+                version,
+                source: InstallSource::AppImage,
+                location: path.display().to_string(),
+                package: None,
+                kind: InstallSource::AppImage.package_kind(),
+            });
         }
         let order = [InstallSource::Deb, InstallSource::Rpm, InstallSource::Pacman, InstallSource::Flatpak];
         if let Some(p) = packages::find(app, &snapshot.packages, &order) {
             let location = if p.manager == InstallSource::Flatpak { app.bundle_id() } else { binary_on_path(app.id) };
-            return Some(Installed { version: packages::version_of(p), source: p.manager, location, package: Some(p.name.clone()) });
+            return Some(Installed {
+                version: packages::version_of(p),
+                source: p.manager,
+                location,
+                package: Some(p.name.clone()),
+                kind: p.manager.package_kind(),
+            });
         }
         detect_system_install(app)
     }
@@ -390,7 +410,13 @@ pub mod linux {
     /// to whatever installed it, since it can't tell which package manager that was.
     fn detect_system_install(app: &CraftApp) -> Option<Installed> {
         let bin = find_binary(app.id)?;
-        Some(Installed { version: binary_version(&bin, app), source: InstallSource::Binary, location: bin.display().to_string(), package: None })
+        Some(Installed {
+            version: binary_version(&bin, app),
+            source: InstallSource::Binary,
+            location: bin.display().to_string(),
+            package: None,
+            kind: InstallSource::Binary.package_kind(),
+        })
     }
 
     fn find_binary(id: &str) -> Option<PathBuf> {
@@ -417,7 +443,13 @@ pub mod freebsd {
         if !bin.exists() {
             return None;
         }
-        Some(Installed { version: binary_version(&bin, app), source: InstallSource::Binary, location: bin.display().to_string(), package: None })
+        Some(Installed {
+            version: binary_version(&bin, app),
+            source: InstallSource::Binary,
+            location: bin.display().to_string(),
+            package: None,
+            kind: InstallSource::Binary.package_kind(),
+        })
     }
 
     /// `<app> --version` prints `<app> 0.5.0 (sha, date)`.
@@ -525,6 +557,24 @@ mod tests {
         assert!(strip_cli_prefix("photocraft-cli 1.0.0", "photocraft").is_none());
     }
 
+    #[test]
+    fn manifest_records_carry_their_package_format() {
+        use crate::manifest::{Manifest, Record};
+        use artcraft_launcher_core::PackageKind;
+        let dir = tempfile::tempdir().unwrap();
+        let exe = dir.path().join("wordcraft.exe");
+        std::fs::write(&exe, "x").unwrap();
+        let app = CraftApp::by_id("wordcraft").unwrap();
+        let mut manifest = Manifest::default();
+        manifest.apps.insert(
+            app.id.into(),
+            Record { version: "0.5.0".into(), kind: PackageKind::PortableZip, path: exe, installed_at: 0, files: Vec::new(), needs_root: false },
+        );
+        let found = from_manifest(app, &manifest).unwrap();
+        assert_eq!(found.source, InstallSource::Launcher);
+        assert_eq!(found.kind, Some(PackageKind::PortableZip));
+    }
+
     #[cfg(target_os = "linux")]
     #[test]
     fn finds_appimages_in_every_folder_newest_first() {
diff --git a/crates/native/src/install.rs b/crates/native/src/install.rs
--- a/crates/native/src/install.rs
+++ b/crates/native/src/install.rs
@@ -1645,7 +1645,7 @@ mod tests {
 
     #[test]
     fn updates_keep_the_installed_format() {
-        let inst = |source| Installed { version: None, source, location: String::new(), package: None };
+        let inst = |source| Installed { version: None, source, location: String::new(), package: None, kind: None };
         let available = available_kinds();
         if let Some(first) = available.first() {
             assert_eq!(choose_kinds(None, None, &[]).first(), Some(first));
@@ -1769,7 +1769,8 @@ mod tests {
             let dir = tempfile::tempdir().unwrap();
             let apps = dir.path().join("Applications");
             let current = bundle(&apps, "0.5.0");
-            let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None };
+            let existing =
+                Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None, kind: None };
             let paths = Paths::under(dir.path());
             let image = dmg(dir.path(), "0.6.0");
 
@@ -1799,7 +1800,8 @@ mod tests {
             let dir = tempfile::tempdir().unwrap();
             let apps = dir.path().join("Applications");
             let current = bundle(&apps, "0.5.0");
-            let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None };
+            let existing =
+                Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None, kind: None };
             let image = dmg(dir.path(), "0.6.0");
             let release = Release { tag: "v0.6.0".into(), version: version::parse("0.6.0"), ..Release::default() };
 
diff --git a/crates/native/src/self_update.rs b/crates/native/src/self_update.rs
--- a/crates/native/src/self_update.rs
+++ b/crates/native/src/self_update.rs
@@ -180,7 +180,8 @@ pub fn update(
     match install {
         #[cfg(target_os = "macos")]
         Install::MacApp(bundle) => {
-            let existing = Installed { version: None, source: InstallSource::MacApp, location: bundle.display().to_string(), package: None };
+            let existing =
+                Installed { version: None, source: InstallSource::MacApp, location: bundle.display().to_string(), package: None, kind: None };
             let placed = install::macos::install_dmg(&LAUNCHER, &file, Some(&existing), paths, &install::macos::Expect::release(release));
             let _ = std::fs::remove_file(&file);
             let placed = placed?;
@@ -368,7 +369,7 @@ mod tests {
         assert!(ok, "hdiutil create failed");
         drop(one_at_a_time);
         let current = apps.join("ArtCraft Launcher.app");
-        let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None };
+        let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None, kind: None };
         // An unsigned test bundle: the signature check has its own tests in `install`.
         let expect = install::macos::Expect { team: None, version: None };
         let placed = install::macos::install_dmg(&LAUNCHER, &dmg, Some(&existing), &Paths::under(dir.path()), &expect).unwrap();
diff --git a/crates/ui-egui/src/details.rs b/crates/ui-egui/src/details.rs
--- a/crates/ui-egui/src/details.rs
+++ b/crates/ui-egui/src/details.rs
@@ -230,6 +230,17 @@ impl LauncherUi {
                     if !version.trim().is_empty() {
                         ui.label(RichText::new(version).size(12.5).color(t.muted));
                     }
+                    // What it is, like the grid and table badges.
+                    if let Some(format) = match &entry.installed {
+                        Some(_) => entry.installed_kind_label(),
+                        None => entry.planned_kind_label(self.platform, &self.settings.preferred_kinds, &self.caps.install_kinds),
+                    } {
+                        ui.add_space(4.0);
+                        ui.horizontal(|ui| {
+                            let (_, tone) = crate::model::entry_status_text(entry, &status, self.caps.manage_apps);
+                            crate::widgets::badge(ui, format, crate::widgets::tone_color(t, tone));
+                        });
+                    }
                 });
             });
             ui.add_space(14.0);
diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv
--- a/crates/ui-egui/src/i18n/cs.tsv
+++ b/crates/ui-egui/src/i18n/cs.tsv
@@ -237,6 +237,7 @@ column	App	Aplikace
 column	Installed	Nainstalováno
 column	Latest	Nejnovější
 column	Released	Vydáno
+column	Format	Formát
 filter	Installed	Nainstalováno
 	App details	Podrobnosti o aplikaci
 	Close (Esc)	Zavřít (Esc)
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -258,6 +258,7 @@ column	App	App
 column	Installed	Lokal
 column	Latest	Neueste
 column	Released	Datum
+column	Format	Format
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Installiert
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -250,6 +250,7 @@ column	App	Aplicación
 column	Installed	Instalada
 column	Latest	Última
 column	Released	Publicada
+column	Format	Formato
 filter	Installed	Instaladas
 	App details	Detalles de la app
 	Close (Esc)	Cerrar (Esc)
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -256,6 +256,7 @@ column	App	Application
 column	Installed	Installée
 column	Latest	Dernière
 column	Released	Date de publication
+column	Format	Format
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Installées
diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv
--- a/crates/ui-egui/src/i18n/hu.tsv
+++ b/crates/ui-egui/src/i18n/hu.tsv
@@ -259,6 +259,7 @@ column	App	Alkalmazás
 column	Installed	Telepített
 column	Latest	Legújabb
 column	Released	Dátum
+column	Format	Formátum
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Telepítve
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -261,6 +261,7 @@ column	App	アプリ
 column	Installed	インストール済みバージョン
 column	Latest	最新バージョン
 column	Released	公開日
+column	Format	形式
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	インストール済み
diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv
--- a/crates/ui-egui/src/i18n/pl.tsv
+++ b/crates/ui-egui/src/i18n/pl.tsv
@@ -260,6 +260,7 @@ column	App	Aplikacja
 column	Installed	Zainstalowana
 column	Latest	Najnowsza
 column	Released	Data wydania
+column	Format	Format
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Zainstalowane
diff --git a/crates/ui-egui/src/i18n/pt-BR.tsv b/crates/ui-egui/src/i18n/pt-BR.tsv
--- a/crates/ui-egui/src/i18n/pt-BR.tsv
+++ b/crates/ui-egui/src/i18n/pt-BR.tsv
@@ -246,6 +246,7 @@ column	App	Aplicativo
 column	Installed	Instalada
 column	Latest	Última
 column	Released	Lançamento
+column	Format	Formato
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Instalados
diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv
--- a/crates/ui-egui/src/i18n/ru.tsv
+++ b/crates/ui-egui/src/i18n/ru.tsv
@@ -255,6 +255,7 @@ column	App	Приложение
 column	Installed	Текущая
 column	Latest	Последняя
 column	Released	Дата релиза
+column	Format	Формат
 
 # Contextual: the filter tab names a group (the status pill says "Installed")
 filter	Installed	Установлены
diff --git a/crates/ui-egui/src/i18n/zh-CN.tsv b/crates/ui-egui/src/i18n/zh-CN.tsv
--- a/crates/ui-egui/src/i18n/zh-CN.tsv
+++ b/crates/ui-egui/src/i18n/zh-CN.tsv
@@ -173,6 +173,7 @@ column	App	应用
 column	Installed	已安装版本
 column	Latest	最新版本
 column	Released	发布日期
+column	Format	格式
 filter	Installed	已安装
 	{name} details	{name} 详情
 @plural	{n} min ago|{n} min ago	{n} 分钟前
diff --git a/crates/ui-egui/src/model.rs b/crates/ui-egui/src/model.rs
--- a/crates/ui-egui/src/model.rs
+++ b/crates/ui-egui/src/model.rs
@@ -1,6 +1,6 @@
 //! What the UI knows about each app.
 
-use artcraft_launcher_core::platform::{Platform, pick_asset};
+use artcraft_launcher_core::platform::{PackageKind, Platform, pick_asset};
 use artcraft_launcher_core::protocol::{JobPhase, LatestRelease, PausedDownload};
 use artcraft_launcher_core::release::Release;
 use artcraft_launcher_core::status::{self, AppStatus, Latest};
@@ -60,6 +60,27 @@ impl AppEntry {
         self.installed.as_ref().map(|i| i.version.as_ref().map(ToString::to_string).unwrap_or_else(|| t("Installed").to_string()))
     }
 
+    /// How the installed copy arrived, for the badge: the release format when known,
+    /// else where it was found (`None` when nothing is installed).
+    pub fn installed_kind_label(&self) -> Option<&'static str> {
+        let installed = self.installed.as_ref()?;
+        Some(installed.kind.map(|k| k.label()).unwrap_or(installed.source.label()))
+    }
+
+    /// What `Install` would download now: the preferred formats the backend can install,
+    /// then what it can install, first published asset wins. Empty `installable` (an old
+    /// backend) falls back to the platform's download list. A label only; the backend
+    /// decides the real one at install time.
+    pub fn planned_kind_label(&self, platform: Option<Platform>, preferred: &[PackageKind], installable: &[PackageKind]) -> Option<&'static str> {
+        let (release, platform) = (self.release()?, platform?);
+        let stems: Vec<&str> = self.app.stems().collect();
+        let base: &[PackageKind] = if installable.is_empty() { platform.download_kinds() } else { installable };
+        let mut kinds: Vec<PackageKind> = preferred.iter().copied().filter(|k| base.contains(k)).collect();
+        let rest: Vec<PackageKind> = base.iter().copied().filter(|k| !kinds.contains(k)).collect();
+        kinds.extend(rest);
+        kinds.into_iter().find_map(|k| pick_asset(release, &stems, platform, &[k]).map(|(_, kind)| kind.label()))
+    }
+
     pub fn latest_label(&self) -> Option<String> {
         self.release().map(Release::version_label)
     }
diff --git a/crates/ui-egui/src/views.rs b/crates/ui-egui/src/views.rs
--- a/crates/ui-egui/src/views.rs
+++ b/crates/ui-egui/src/views.rs
@@ -480,6 +480,15 @@ impl LauncherUi {
             if let Some(f) = entry.failure() {
                 r.on_hover_text(fmt(tl!("Couldn't check for updates: {f}"), &[("f", f)]));
             }
+            // What it is: the installed format, else what Install would download.
+            let format = match &entry.installed {
+                Some(_) => entry.installed_kind_label(),
+                None => entry.planned_kind_label(self.platform, &self.settings.preferred_kinds, &self.caps.install_kinds),
+            };
+            if let Some(format) = format {
+                ui.add_space(6.0);
+                widgets::badge(ui, format, widgets::tone_color(&t, tone));
+            }
         });
         ui.add_space(4.0);
         ui.label(RichText::new(version_line(&entry, &status)).size(12.5).color(t.muted));
@@ -516,6 +525,7 @@ impl LauncherUi {
                 .cell_layout(egui::Layout::left_to_right(egui::Align::Center))
                 .column(Column::remainder().at_least(220.0).clip(true))
                 .column(Column::exact(176.0))
+                .column(Column::exact(150.0))
                 .column(Column::exact(84.0))
                 .column(Column::exact(84.0))
                 .column(Column::exact(104.0))
@@ -524,6 +534,7 @@ impl LauncherUi {
                     for (key, label) in [
                         (Some(SortKey::Name), tl!("App")),
                         (Some(SortKey::Status), tl!("Status")),
+                        (None, tr_ctx(current(), "column", "Format")),
                         (Some(SortKey::Installed), tr_ctx(current(), "column", "Installed")),
                         (Some(SortKey::Latest), tr_ctx(current(), "column", "Latest")),
                         (Some(SortKey::Released), tr_ctx(current(), "column", "Released")),
@@ -533,7 +544,17 @@ impl LauncherUi {
                             if key == Some(SortKey::Name) {
                                 rule(ui);
                             }
-                            let Some(k) = key else { return };
+                            let Some(k) = key else {
+                                // A titled column without sorting: paint the label and stop.
+                                if !label.is_empty() {
+                                    let (rect, resp) = ui.allocate_exact_size(ui.available_size(), Sense::hover());
+                                    let galley = widgets::hud_galley(ui, label, t.faint);
+                                    let at = egui::pos2(rect.left(), rect.center().y - galley.size().y / 2.0);
+                                    ui.painter().galley(at, galley, t.faint);
+                                    resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Label, true, label));
+                                }
+                                return;
+                            };
                             let active = k == self.settings.sort;
                             let tip = if active { tl!("Click to reverse the order") } else { tl!("Click to sort by this column") };
                             // Measure first so the whole header cell (label + arrow) is the target.
@@ -617,6 +638,22 @@ impl LauncherUi {
                                     r.on_hover_text(fmt(tl!("Couldn't check for updates: {f}"), &[("f", f)]));
                                 }
                             });
+                            row.col(|ui| {
+                                // What it is: the installed format, else what Install would download.
+                                let format = match &entry.installed {
+                                    Some(_) => entry.installed_kind_label(),
+                                    None => entry.planned_kind_label(self.platform, &self.settings.preferred_kinds, &self.caps.install_kinds),
+                                };
+                                match format {
+                                    Some(format) => {
+                                        let (_, tone) = model::entry_status_text(&entry, &status, self.caps.manage_apps);
+                                        widgets::badge(ui, format, widgets::tone_color(&t, tone));
+                                    }
+                                    None => {
+                                        ui.label(RichText::new("—").color(t.faint));
+                                    }
+                                }
+                            });
                             row.col(|ui| {
                                 let installed = entry.installed_label();
                                 let color = if installed.is_some() { t.ink } else { t.faint };
diff --git a/crates/ui-egui/tests/chinese.rs b/crates/ui-egui/tests/chinese.rs
--- a/crates/ui-egui/tests/chinese.rs
+++ b/crates/ui-egui/tests/chinese.rs
@@ -32,7 +32,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: self.manage, reveal_label: "Show in Finder", self_update: self.manage }
+        Capabilities {
+            manage_apps: self.manage,
+            reveal_label: "Show in Finder",
+            self_update: self.manage,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -95,6 +100,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed: inst });
     }
diff --git a/crates/ui-egui/tests/french.rs b/crates/ui-egui/tests/french.rs
--- a/crates/ui-egui/tests/french.rs
+++ b/crates/ui-egui/tests/french.rs
@@ -27,7 +27,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Finder",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -69,6 +74,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/german.rs b/crates/ui-egui/tests/german.rs
--- a/crates/ui-egui/tests/german.rs
+++ b/crates/ui-egui/tests/german.rs
@@ -31,7 +31,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: self.manage, reveal_label: "Show in Finder", self_update: self.manage }
+        Capabilities {
+            manage_apps: self.manage,
+            reveal_label: "Show in Finder",
+            self_update: self.manage,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -94,6 +99,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed: inst });
     }
diff --git a/crates/ui-egui/tests/hungarian.rs b/crates/ui-egui/tests/hungarian.rs
--- a/crates/ui-egui/tests/hungarian.rs
+++ b/crates/ui-egui/tests/hungarian.rs
@@ -28,7 +28,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Finder",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: self.os, arch: Arch::Arm64 })
@@ -77,6 +82,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/japanese.rs b/crates/ui-egui/tests/japanese.rs
--- a/crates/ui-egui/tests/japanese.rs
+++ b/crates/ui-egui/tests/japanese.rs
@@ -32,7 +32,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: self.manage, reveal_label: "Show in Finder", self_update: self.manage }
+        Capabilities {
+            manage_apps: self.manage,
+            reveal_label: "Show in Finder",
+            self_update: self.manage,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -95,6 +100,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed: inst });
     }
diff --git a/crates/ui-egui/tests/polish.rs b/crates/ui-egui/tests/polish.rs
--- a/crates/ui-egui/tests/polish.rs
+++ b/crates/ui-egui/tests/polish.rs
@@ -27,7 +27,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Finder",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -69,6 +74,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/portuguese.rs b/crates/ui-egui/tests/portuguese.rs
--- a/crates/ui-egui/tests/portuguese.rs
+++ b/crates/ui-egui/tests/portuguese.rs
@@ -25,7 +25,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Explorer", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Explorer",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::Windows, arch: Arch::X64 })
@@ -67,6 +72,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::Msi,
             location: format!("C:\\Program Files\\{}\\{}.exe", app.name, app.id),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/russian.rs b/crates/ui-egui/tests/russian.rs
--- a/crates/ui-egui/tests/russian.rs
+++ b/crates/ui-egui/tests/russian.rs
@@ -27,7 +27,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Finder",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -69,6 +74,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/spanish.rs b/crates/ui-egui/tests/spanish.rs
--- a/crates/ui-egui/tests/spanish.rs
+++ b/crates/ui-egui/tests/spanish.rs
@@ -27,7 +27,12 @@ impl Backend for Fake {
         std::mem::take(&mut self.events)
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
+        Capabilities {
+            manage_apps: true,
+            reveal_label: "Show in Finder",
+            self_update: true,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -69,6 +74,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed });
     }
diff --git a/crates/ui-egui/tests/ui.rs b/crates/ui-egui/tests/ui.rs
--- a/crates/ui-egui/tests/ui.rs
+++ b/crates/ui-egui/tests/ui.rs
@@ -13,7 +13,7 @@ use artcraft_launcher_core::protocol::{
 };
 use artcraft_launcher_core::release::{Asset, Release};
 use artcraft_launcher_core::status::InstallSource;
-use artcraft_launcher_core::{Arch, Installed, Os, Platform, SUITE, version};
+use artcraft_launcher_core::{Arch, Installed, Os, PackageKind, Platform, SUITE, version};
 use artcraft_launcher_ui_egui::settings::ViewMode;
 use artcraft_launcher_ui_egui::{Host, LauncherUi, Settings};
 use egui_kittest::Harness;
@@ -83,7 +83,12 @@ impl Backend for Fake {
         out
     }
     fn capabilities(&self) -> Capabilities {
-        Capabilities { manage_apps: self.manage, reveal_label: "Show in Finder", self_update: self.manage }
+        Capabilities {
+            manage_apps: self.manage,
+            reveal_label: "Show in Finder",
+            self_update: self.manage,
+            install_kinds: vec![artcraft_launcher_core::PackageKind::Dmg],
+        }
     }
     fn platform(&self) -> Option<Platform> {
         Some(Platform { os: Os::MacOs, arch: Arch::Arm64 })
@@ -146,6 +151,7 @@ fn events() -> Vec<Event> {
             source: InstallSource::MacApp,
             location: format!("/Applications/{}.app", app.name),
             package: None,
+            kind: None,
         });
         ev.push(Event::Detected { app: app.id.into(), installed: inst });
     }
@@ -304,6 +310,33 @@ fn grid_shows_every_status_and_installs_on_click() {
     assert!(installs.contains(&"photocraft".to_string()) && installs.contains(&"effectcraft".to_string()));
 }
 
+#[test]
+fn cards_and_rows_name_the_install_format() {
+    // Fixtures: MacApp installs of unknown format, dmg releases on this (mac) platform.
+    for view in [ViewMode::Grid, ViewMode::Table] {
+        let (mut h, _) = harness(view, egui::Theme::Dark, true);
+        h.run_steps(8);
+        // Installed: where the copy came from (the source, the record kind unknown).
+        assert!(h.query_all_by_label_contains("Applications folder").count() >= 1);
+        // Not installed: what Install would download (the release format for this platform).
+        assert!(h.query_all_by_label_contains("Disk image (.dmg)").count() >= 1);
+    }
+}
+
+#[test]
+fn an_uninstallable_preference_never_labels_the_download() {
+    // The user's exact bug: preferring a format this machine cannot install must not
+    // leak into labels; the installable format still shows.
+    let (mut h, _) = harness(ViewMode::Grid, egui::Theme::Dark, true);
+    h.run_steps(2);
+    if let Some(l) = h.state_mut().as_mut() {
+        l.settings.preferred_kinds = vec![PackageKind::PortableZip];
+    }
+    h.run_steps(8);
+    assert!(h.query_all_by_label_contains("Disk image (.dmg)").count() >= 1);
+    assert_eq!(h.query_all_by_label_contains("Portable (.zip)").count(), 0);
+}
+
 #[test]
 fn downloads_can_be_paused_resumed_and_discarded() {
     let (mut h, sent) = harness(ViewMode::Grid, egui::Theme::Dark, true);
