diff --git a/ROADMAP.md b/ROADMAP.md
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -200,6 +200,8 @@ Ranked; detail and the full milestone table in [docs/roadmap.md](docs/roadmap.md
 
 ## Progress log
 
+- **2026-10-27 (UI, #1619):** Help ▸ Report an Issue… opens a new GitHub issue with the version, OS and the open document's file type (`pdf`) filled in; never a file name, path or contents. English label (catalogues fall back to English).
+
 - **2026-10-27 (M10, OCR models):** Model staging downloads and verifies the ONNX pair after the upstream RTEN URL brownout; runtime discovery prefers complete ONNX pairs per directory, retains complete RTEN fallback and preserves directory precedence.
 - **2026-10-24 (M10, #4158 partial):** Word, HTML, RTF and PowerPoint export keep a block that continues another on its line (an italic case name, a link, a superscript) as a run in its own style inside that paragraph, with the source's word space, instead of a paragraph of its own. Style changes that wrap onto the next line still split paragraphs (the reading blocks keep style boundaries). Estimates unchanged.
 - **2026-10-24 (M3, window move on Wayland, #3970 follow-up):** After a move or resize by PdfCraft's own title bar or edges, the button release given back to egui goes before the pointer leaving the window, so hover no longer sticks at the old place until the pointer moves. Found by CodeRabbit in review of #3970; a unit test covers it. Estimates unchanged.
diff --git a/crates/engine/src/commands.rs b/crates/engine/src/commands.rs
--- a/crates/engine/src/commands.rs
+++ b/crates/engine/src/commands.rs
@@ -397,6 +397,7 @@ pub const COMMANDS: &[CommandSpec] = &[
     c("help.app_page", "PdfCraft web page", HELP, None, Nothing, "globe"),
     c("help.github", "PdfCraft on GitHub", HELP, None, Nothing, "code-xml"),
     c("help.website", "ArtCraft website", HELP, None, Nothing, "external-link"),
+    c("help.report_issue", "Report an Issue…", HELP, None, Nothing, "triangle-alert"),
     c("help.check_updates", "Check for updates…", HELP, None, Nothing, "cloud"),
     c("help.about", "About PdfCraft", HELP, None, Nothing, "info"),
 ];
diff --git a/crates/engine/src/links.rs b/crates/engine/src/links.rs
--- a/crates/engine/src/links.rs
+++ b/crates/engine/src/links.rs
@@ -30,6 +30,24 @@ pub const LINKS: &[Link] = &[
     Link { command: "help.website", label: "ArtCraft website", url: WEBSITE, icon: "external-link" },
 ];
 
+/// The new-issue address for Help ▸ Report an Issue…: `version`, `environment` and `os` are the
+/// bug form's field ids and `body` fills a blank issue. The document is described by its file
+/// extension alone, never a name, path or contents. Each value is cut to 16 characters, so the
+/// address stays well under [`MAX_DOCUMENT_URL`].
+pub fn report_issue_url(version: &str, os: &str, document_ext: Option<&str>) -> String {
+    let short = |s: &str| s.chars().filter(|c| !c.is_control()).take(16).collect::<String>();
+    let ext: String = document_ext.unwrap_or("none").chars().filter(char::is_ascii_alphanumeric).take(8).collect();
+    let (version, os) = (short(version), short(os));
+    let environment = format!("{os}; document: {ext}");
+    let encode = |s: &str| {
+        let keep = |b: &u8| b.is_ascii_alphanumeric() || b"-_.~".contains(b);
+        s.bytes().map(|b| if keep(&b) { char::from(b).to_string() } else { format!("%{b:02X}") }).collect::<String>()
+    };
+    let body = format!("PdfCraft {version}\n{environment}");
+    let (v, e, o, b) = (encode(&version), encode(&environment), encode(&os), encode(&body));
+    format!("{GITHUB}/issues/new?template=bug_report.yml&version={v}&environment={e}&os={o}&body={b}")
+}
+
 pub fn for_command(id: &str) -> Option<&'static Link> {
     LINKS.iter().find(|l| l.command == id)
 }
diff --git a/crates/engine/src/links/tests.rs b/crates/engine/src/links/tests.rs
--- a/crates/engine/src/links/tests.rs
+++ b/crates/engine/src/links/tests.rs
@@ -325,3 +325,15 @@ fn hosts_are_shown_as_the_browser_receives_them() {
         assert_eq!(document_url(bad), Err(B::Malformed), "{bad}");
     }
 }
+
+#[test]
+fn the_report_address_carries_version_and_system_only_and_stays_short() {
+    use super::report_issue_url as url;
+    let u = url("0.7.1", "linux x86_64", Some("pdf"));
+    assert!(u.starts_with("https://github.com/storytold/pdfcraft/issues/new?template=bug_report.yml&version=0.7.1&environment=linux%20x86_64%3B%20document%3A%20pdf&os=linux%20x86_64&body="), "{u}");
+    // Hostile text and an unusual extension can't add a parameter, leak, or grow the address.
+    let u = url(&"\u{1F600}".repeat(99), &"&#=".repeat(99), Some("x.y/Z"));
+    assert_eq!(u.matches('?').count() + u.matches('#').count(), 1, "{u}");
+    assert!(u.is_ascii() && u.contains("document%3A%20xyZ") && u.len() < super::MAX_DOCUMENT_URL, "{} bytes: {u}", u.len());
+    assert!(url("1", "w", None).contains("document%3A%20none"));
+}
diff --git a/crates/ui-egui/src/commands.rs b/crates/ui-egui/src/commands.rs
--- a/crates/ui-egui/src/commands.rs
+++ b/crates/ui-egui/src/commands.rs
@@ -213,6 +213,11 @@ impl PdfCraftApp {
                 }
                 self.dialog = Some(Dialog::NumberPages);
             }
+            "help.report_issue" => {
+                let os = format!("{} {}", std::env::consts::OS, std::env::consts::ARCH);
+                let ext = self.active_ids().map(|_| "pdf");
+                self.open_url(&pdfcraft_engine::links::report_issue_url(&pdfcraft_engine::build_info::version(), &os, ext));
+            }
             link if pdfcraft_engine::links::for_command(link).is_some() => {
                 if let Some(l) = pdfcraft_engine::links::for_command(link) {
                     self.open_url(l.url);
diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs
--- a/crates/ui-egui/src/menus.rs
+++ b/crates/ui-egui/src/menus.rs
@@ -221,8 +221,19 @@ const SIGN: &[&str] = &[
     "sign.panel",
 ];
 const WINDOW: &[&str] = &["view.next_tab", "view.previous_tab"];
-const HELP: &[&str] =
-    &["help.shortcuts", SEP, "help.app_page", "help.github", "help.website", "help.discord", SEP, "help.check_updates", SEP, "help.about"];
+const HELP: &[&str] = &[
+    "help.shortcuts",
+    SEP,
+    "help.app_page",
+    "help.github",
+    "help.website",
+    "help.discord",
+    "help.report_issue",
+    SEP,
+    "help.check_updates",
+    SEP,
+    "help.about",
+];
 
 /// A registry shortcut as a craft-keymap chord: `command` is ⌘ (Ctrl elsewhere) and `mac_ctrl`
 /// the Control key on macOS. `None` for a key craft-keymap doesn't name.
