diff --git a/crates/ui-egui/src/cmdline.rs b/crates/ui-egui/src/cmdline.rs
--- a/crates/ui-egui/src/cmdline.rs
+++ b/crates/ui-egui/src/cmdline.rs
@@ -387,7 +387,9 @@ pub fn submit(app: &mut CadApp) {
         }
         return;
     }
-    app.cmdline(&text);
+    // A partly typed command name runs the highlighted (first) AutoComplete suggestion.
+    let completion = if app.session.prompting() { None } else { suggestions(text.trim()).into_iter().next() };
+    app.cmdline_or(&text, completion.map(|s| s.id.to_ascii_lowercase()).as_deref());
 }
 
 fn visible_lines(app: &CadApp, canvas: Rect, bar: Rect) -> usize {
@@ -822,4 +824,39 @@ mod autocomplete_tests {
         tab(&mut app);
         assert_eq!(app.cmd.buffer, "RECTANG");
     }
+
+    fn app() -> CadApp {
+        let mut app = CadApp::new(cadcraft_engine::Session::empty(), crate::Services::default());
+        app.start("ui.sample");
+        app
+    }
+
+    #[test]
+    fn enter_on_a_partial_name_runs_the_highlighted_suggestion() {
+        let mut app = app();
+        app.cmd.buffer = "RECT".to_string();
+        submit(&mut app);
+        assert_eq!(app.session.running.as_ref().map(|r| r.id.as_str()), Some("rectang"));
+        assert!(!app.session.log.iter().any(|l| l.contains("unknown command")), "{:?}", app.session.log);
+    }
+
+    #[test]
+    fn enter_keeps_exact_names_and_reports_names_nothing_matches() {
+        let mut app = app();
+        // An exact alias is not replaced by a longer suggestion.
+        app.cmd.buffer = "l".to_string();
+        submit(&mut app);
+        assert_eq!(app.session.running.as_ref().map(|r| r.id.as_str()), Some("line"));
+        app.session.cancel();
+        // A system variable name still acts as SETVAR.
+        app.cmd.buffer = "orthomode".to_string();
+        submit(&mut app);
+        assert_eq!(app.session.running.as_ref().map(|r| r.id.as_str()), Some("setvar"));
+        app.session.cancel();
+        // No suggestion: still an unknown command.
+        app.cmd.buffer = "zzqx".to_string();
+        submit(&mut app);
+        assert!(app.session.running.is_none());
+        assert!(app.session.log.iter().any(|l| l.contains("unknown command")), "{:?}", app.session.log);
+    }
 }
diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs
--- a/crates/ui-egui/src/lib.rs
+++ b/crates/ui-egui/src/lib.rs
@@ -354,6 +354,13 @@ impl CadApp {
     /// Submit a line of command-line text. A refused line is echoed to the history; the error is
     /// also returned.
     pub fn cmdline(&mut self, text: &str) -> Option<String> {
+        self.cmdline_or(text, None)
+    }
+
+    /// [`CadApp::cmdline`], but a command name nothing knows (no command, alias, UI command, LISP
+    /// command or system variable) runs `fallback` instead: Enter on a partly typed name accepts
+    /// the highlighted AutoComplete suggestion.
+    pub fn cmdline_or(&mut self, text: &str, fallback: Option<&str>) -> Option<String> {
         if !self.session.prompting() {
             let first = text.split_whitespace().next().unwrap_or("");
             // `cmd {json}` is a programmatic call: the engine runs it with those parameters.
@@ -362,7 +369,11 @@ impl CadApp {
                 return None;
             }
         }
-        let e = self.session.cmdline(text).err()?.to_string();
+        let e = match (self.session.cmdline(text), fallback) {
+            (Ok(()), _) => return None,
+            (Err(cadcraft_engine::EngineError::UnknownCommand(_)), Some(f)) => return self.cmdline(f),
+            (Err(e), _) => e.to_string(),
+        };
         self.session.echo(e.clone());
         Some(e)
     }
