diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs
index 28581fb92090a4..fc3ab5dc259073 100644
--- a/crates/ruff_cli/src/args.rs
+++ b/crates/ruff_cli/src/args.rs
@@ -9,6 +9,7 @@ use ruff_linter::logging::LogLevel;
 use ruff_linter::registry::Rule;
 use ruff_linter::settings::types::{
     FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
+    UnsafeFixes,
 };
 use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
 use ruff_workspace::configuration::{Configuration, RuleSelection};
@@ -76,12 +77,18 @@ pub enum Command {
 pub struct CheckCommand {
     /// List of files or directories to check.
     pub files: Vec<PathBuf>,
-    /// Attempt to automatically fix lint violations.
-    /// Use `--no-fix` to disable.
+    /// Apply fixes to resolve lint violations.
+    /// Use `--no-fix` to disable or `--unsafe-fixes` to include unsafe fixes.
     #[arg(long, overrides_with("no_fix"))]
     fix: bool,
     #[clap(long, overrides_with("fix"), hide = true)]
     no_fix: bool,
+    /// Include fixes that may not retain the original intent of the code.
+    /// Use `--no-unsafe-fixes` to disable.
+    #[arg(long, overrides_with("no_unsafe_fixes"))]
+    unsafe_fixes: bool,
+    #[arg(long, overrides_with("unsafe_fixes"), hide = true)]
+    no_unsafe_fixes: bool,
     /// Show violations with source code.
     /// Use `--no-show-source` to disable.
     #[arg(long, overrides_with("no_show_source"))]
@@ -100,8 +107,8 @@ pub struct CheckCommand {
     /// Run in watch mode by re-running whenever files change.
     #[arg(short, long)]
     pub watch: bool,
-    /// Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`.
-    /// Use `--no-fix-only` to disable.
+    /// Apply fixes to resolve lint violations, but don't report on leftover violations. Implies `--fix`.
+    /// Use `--no-fix-only` to disable or `--unsafe-fixes` to include unsafe fixes.
     #[arg(long, overrides_with("no_fix_only"))]
     fix_only: bool,
     #[clap(long, overrides_with("fix_only"), hide = true)]
@@ -497,6 +504,8 @@ impl CheckCommand {
                 cache_dir: self.cache_dir,
                 fix: resolve_bool_arg(self.fix, self.no_fix),
                 fix_only: resolve_bool_arg(self.fix_only, self.no_fix_only),
+                unsafe_fixes: resolve_bool_arg(self.unsafe_fixes, self.no_unsafe_fixes)
+                    .map(UnsafeFixes::from),
                 force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
                 output_format: self.output_format.or(self.format),
                 show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
@@ -599,6 +608,7 @@ pub struct CliOverrides {
     pub cache_dir: Option<PathBuf>,
     pub fix: Option<bool>,
     pub fix_only: Option<bool>,
+    pub unsafe_fixes: Option<UnsafeFixes>,
     pub force_exclude: Option<bool>,
     pub output_format: Option<SerializationFormat>,
     pub show_fixes: Option<bool>,
@@ -624,6 +634,9 @@ impl ConfigurationTransformer for CliOverrides {
         if let Some(fix_only) = &self.fix_only {
             config.fix_only = Some(*fix_only);
         }
+        if self.unsafe_fixes.is_some() {
+            config.unsafe_fixes = self.unsafe_fixes;
+        }
         config.lint.rule_selections.push(RuleSelection {
             select: self.select.clone(),
             ignore: self
diff --git a/crates/ruff_cli/src/cache.rs b/crates/ruff_cli/src/cache.rs
index 3a2b851451f6ea..f6595c43370a52 100644
--- a/crates/ruff_cli/src/cache.rs
+++ b/crates/ruff_cli/src/cache.rs
@@ -338,6 +338,7 @@ pub(crate) fn init(path: &Path) -> Result<()> {
 #[cfg(test)]
 mod tests {
     use filetime::{set_file_mtime, FileTime};
+    use ruff_linter::settings::types::UnsafeFixes;
     use std::env::temp_dir;
     use std::fs;
     use std::io;
@@ -410,6 +411,7 @@ mod tests {
                     Some(&cache),
                     flags::Noqa::Enabled,
                     flags::FixMode::Generate,
+                    UnsafeFixes::Enabled,
                 )
                 .unwrap();
                 if diagnostics
@@ -455,6 +457,7 @@ mod tests {
                 Some(&cache),
                 flags::Noqa::Enabled,
                 flags::FixMode::Generate,
+                UnsafeFixes::Enabled,
             )
             .unwrap();
         }
@@ -712,6 +715,7 @@ mod tests {
                 Some(cache),
                 flags::Noqa::Enabled,
                 flags::FixMode::Generate,
+                UnsafeFixes::Enabled,
             )
         }
     }
diff --git a/crates/ruff_cli/src/commands/check.rs b/crates/ruff_cli/src/commands/check.rs
index f19c8d80d4c11c..a6ecb66d5d2f71 100644
--- a/crates/ruff_cli/src/commands/check.rs
+++ b/crates/ruff_cli/src/commands/check.rs
@@ -11,6 +11,7 @@ use itertools::Itertools;
 use log::{debug, error, warn};
 #[cfg(not(target_family = "wasm"))]
 use rayon::prelude::*;
+use ruff_linter::settings::types::UnsafeFixes;
 use rustc_hash::FxHashMap;
 
 use ruff_diagnostics::Diagnostic;
@@ -36,6 +37,7 @@ pub(crate) fn check(
     cache: flags::Cache,
     noqa: flags::Noqa,
     fix_mode: flags::FixMode,
+    unsafe_fixes: UnsafeFixes,
 ) -> Result<Diagnostics> {
     // Collect all the Python files to check.
     let start = Instant::now();
@@ -119,7 +121,16 @@ pub(crate) fn check(
                         }
                     });
 
-                    lint_path(path, package, &settings.linter, cache, noqa, fix_mode).map_err(|e| {
+                    lint_path(
+                        path,
+                        package,
+                        &settings.linter,
+                        cache,
+                        noqa,
+                        fix_mode,
+                        unsafe_fixes,
+                    )
+                    .map_err(|e| {
                         (Some(path.to_owned()), {
                             let mut error = e.to_string();
                             for cause in e.chain() {
@@ -199,9 +210,10 @@ fn lint_path(
     cache: Option<&Cache>,
     noqa: flags::Noqa,
     fix_mode: flags::FixMode,
+    unsafe_fixes: UnsafeFixes,
 ) -> Result<Diagnostics> {
     let result = catch_unwind(|| {
-        crate::diagnostics::lint_path(path, package, settings, cache, noqa, fix_mode)
+        crate::diagnostics::lint_path(path, package, settings, cache, noqa, fix_mode, unsafe_fixes)
     });
 
     match result {
@@ -233,6 +245,8 @@ mod test {
     use std::os::unix::fs::OpenOptionsExt;
 
     use anyhow::Result;
+
+    use ruff_linter::settings::types::UnsafeFixes;
     use rustc_hash::FxHashMap;
     use tempfile::TempDir;
 
@@ -285,6 +299,7 @@ mod test {
             flags::Cache::Disabled,
             flags::Noqa::Disabled,
             flags::FixMode::Generate,
+            UnsafeFixes::Enabled,
         )
         .unwrap();
         let mut output = Vec::new();
diff --git a/crates/ruff_cli/src/diagnostics.rs b/crates/ruff_cli/src/diagnostics.rs
index f228d09c4bda0e..c4ea03c55ba817 100644
--- a/crates/ruff_cli/src/diagnostics.rs
+++ b/crates/ruff_cli/src/diagnostics.rs
@@ -11,6 +11,7 @@ use anyhow::{Context, Result};
 use colored::Colorize;
 use filetime::FileTime;
 use log::{debug, error, warn};
+use ruff_linter::settings::types::UnsafeFixes;
 use rustc_hash::FxHashMap;
 
 use ruff_diagnostics::Diagnostic;
@@ -168,6 +169,7 @@ pub(crate) fn lint_path(
     cache: Option<&Cache>,
     noqa: flags::Noqa,
     fix_mode: flags::FixMode,
+    unsafe_fixes: UnsafeFixes,
 ) -> Result<Diagnostics> {
     // Check the cache.
     // TODO(charlie): `fixer::Mode::Apply` and `fixer::Mode::Diff` both have
@@ -244,8 +246,15 @@ pub(crate) fn lint_path(
             result,
             transformed,
             fixed,
-        }) = lint_fix(path, package, noqa, settings, &source_kind, source_type)
-        {
+        }) = lint_fix(
+            path,
+            package,
+            noqa,
+            unsafe_fixes,
+            settings,
+            &source_kind,
+            source_type,
+        ) {
             if !fixed.is_empty() {
                 match fix_mode {
                     flags::FixMode::Apply => transformed.write(&mut File::create(path)?)?,
@@ -355,6 +364,7 @@ pub(crate) fn lint_stdin(
             path.unwrap_or_else(|| Path::new("-")),
             package,
             noqa,
+            settings.unsafe_fixes,
             &settings.linter,
             &source_kind,
             source_type,
diff --git a/crates/ruff_cli/src/lib.rs b/crates/ruff_cli/src/lib.rs
index f9dbb164df0d35..c74279392b564d 100644
--- a/crates/ruff_cli/src/lib.rs
+++ b/crates/ruff_cli/src/lib.rs
@@ -10,7 +10,7 @@ use log::warn;
 use notify::{recommended_watcher, RecursiveMode, Watcher};
 
 use ruff_linter::logging::{set_up_logging, LogLevel};
-use ruff_linter::settings::flags;
+use ruff_linter::settings::flags::FixMode;
 use ruff_linter::settings::types::SerializationFormat;
 use ruff_linter::{fs, warn_user, warn_user_once};
 use ruff_workspace::Settings;
@@ -228,6 +228,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
     let Settings {
         fix,
         fix_only,
+        unsafe_fixes,
         output_format,
         show_fixes,
         show_source,
@@ -236,17 +237,20 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
 
     // Fix rules are as follows:
     // - By default, generate all fixes, but don't apply them to the filesystem.
-    // - If `--fix` or `--fix-only` is set, always apply fixes to the filesystem (or
+    // - If `--fix` or `--fix-only` is set, apply applicable fixes to the filesystem (or
     //   print them to stdout, if we're reading from stdin).
-    // - If `--diff` or `--fix-only` are set, don't print any violations (only
-    //   fixes).
+    // - If `--diff` or `--fix-only` are set, don't print any violations (only applicable fixes)
+    // - By default, applicable fixes only include [`Applicablility::Automatic`], but if
+    //   `--unsafe-fixes` is set, then [`Applicablility::Suggested`] fixes are included.
+
     let fix_mode = if cli.diff {
-        flags::FixMode::Diff
+        FixMode::Diff
     } else if fix || fix_only {
-        flags::FixMode::Apply
+        FixMode::Apply
     } else {
-        flags::FixMode::Generate
+        FixMode::Generate
     };
+
     let cache = !cli.no_cache;
     let noqa = !cli.ignore_noqa;
     let mut printer_flags = PrinterFlags::empty();
@@ -290,7 +294,13 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
         return Ok(ExitStatus::Success);
     }
 
-    let printer = Printer::new(output_format, log_level, fix_mode, printer_flags);
+    let printer = Printer::new(
+        output_format,
+        log_level,
+        fix_mode,
+        unsafe_fixes,
+        printer_flags,
+    );
 
     if cli.watch {
         if output_format != SerializationFormat::Text {
@@ -318,6 +328,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
             cache.into(),
             noqa.into(),
             fix_mode,
+            unsafe_fixes,
         )?;
         printer.write_continuously(&mut writer, &messages)?;
 
@@ -350,6 +361,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
                         cache.into(),
                         noqa.into(),
                         fix_mode,
+                        unsafe_fixes,
                     )?;
                     printer.write_continuously(&mut writer, &messages)?;
                 }
@@ -376,13 +388,14 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
                 cache.into(),
                 noqa.into(),
                 fix_mode,
+                unsafe_fixes,
             )?
         };
 
         // Always try to print violations (the printer itself may suppress output),
         // unless we're writing fixes via stdin (in which case, the transformed
         // source code goes to stdout).
-        if !(is_stdin && matches!(fix_mode, flags::FixMode::Apply | flags::FixMode::Diff)) {
+        if !(is_stdin && matches!(fix_mode, FixMode::Apply | FixMode::Diff)) {
             if cli.statistics {
                 printer.write_statistics(&diagnostics, &mut writer)?;
             } else {
diff --git a/crates/ruff_cli/src/printer.rs b/crates/ruff_cli/src/printer.rs
index 7700df97494661..d1d5c36a84175e 100644
--- a/crates/ruff_cli/src/printer.rs
+++ b/crates/ruff_cli/src/printer.rs
@@ -19,8 +19,8 @@ use ruff_linter::message::{
 };
 use ruff_linter::notify_user;
 use ruff_linter::registry::{AsRule, Rule};
-use ruff_linter::settings::flags;
-use ruff_linter::settings::types::SerializationFormat;
+use ruff_linter::settings::flags::{self};
+use ruff_linter::settings::types::{SerializationFormat, UnsafeFixes};
 
 use crate::diagnostics::Diagnostics;
 
@@ -73,6 +73,7 @@ pub(crate) struct Printer {
     format: SerializationFormat,
     log_level: LogLevel,
     fix_mode: flags::FixMode,
+    unsafe_fixes: UnsafeFixes,
     flags: Flags,
 }
 
@@ -81,12 +82,14 @@ impl Printer {
         format: SerializationFormat,
         log_level: LogLevel,
         fix_mode: flags::FixMode,
+        unsafe_fixes: UnsafeFixes,
         flags: Flags,
     ) -> Self {
         Self {
             format,
             log_level,
             fix_mode,
+            unsafe_fixes,
             flags,
         }
     }
@@ -118,19 +121,8 @@ impl Printer {
                     writeln!(writer, "Found {remaining} error{s}.")?;
                 }
 
-                if show_fix_status(self.fix_mode) {
-                    let num_fixable = diagnostics
-                        .messages
-                        .iter()
-                        .filter(|message| message.fix.is_some())
-                        .count();
-                    if num_fixable > 0 {
-                        writeln!(
-                            writer,
-                            "[{}] {num_fixable} potentially fixable with the --fix option.",
-                            "*".cyan(),
-                        )?;
-                    }
+                if let Some(fixables) = FixableSummary::try_from(diagnostics, self.unsafe_fixes) {
+                    writeln!(writer, "{fixables}")?;
                 }
             } else {
                 let fixed = diagnostics
@@ -178,6 +170,7 @@ impl Printer {
         }
 
         let context = EmitterContext::new(&diagnostics.notebook_indexes);
+        let fixables = FixableSummary::try_from(diagnostics, self.unsafe_fixes);
 
         match self.format {
             SerializationFormat::Json => {
@@ -191,9 +184,10 @@ impl Printer {
             }
             SerializationFormat::Text => {
                 TextEmitter::default()
-                    .with_show_fix_status(show_fix_status(self.fix_mode))
+                    .with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
                     .with_show_fix_diff(self.flags.intersects(Flags::SHOW_FIX_DIFF))
                     .with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
+                    .with_unsafe_fixes(self.unsafe_fixes)
                     .emit(writer, &diagnostics.messages, &context)?;
 
                 if self.flags.intersects(Flags::SHOW_FIX_SUMMARY) {
@@ -209,7 +203,8 @@ impl Printer {
             SerializationFormat::Grouped => {
                 GroupedEmitter::default()
                     .with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
-                    .with_show_fix_status(show_fix_status(self.fix_mode))
+                    .with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
+                    .with_unsafe_fixes(self.unsafe_fixes)
                     .emit(writer, &diagnostics.messages, &context)?;
 
                 if self.flags.intersects(Flags::SHOW_FIX_SUMMARY) {
@@ -359,6 +354,8 @@ impl Printer {
             );
         }
 
+        let fixables = FixableSummary::try_from(diagnostics, self.unsafe_fixes);
+
         if !diagnostics.messages.is_empty() {
             if self.log_level >= LogLevel::Default {
                 writeln!(writer)?;
@@ -366,8 +363,9 @@ impl Printer {
 
             let context = EmitterContext::new(&diagnostics.notebook_indexes);
             TextEmitter::default()
-                .with_show_fix_status(show_fix_status(self.fix_mode))
+                .with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
                 .with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
+                .with_unsafe_fixes(self.unsafe_fixes)
                 .emit(writer, &diagnostics.messages, &context)?;
         }
         writer.flush()?;
@@ -390,13 +388,13 @@ fn num_digits(n: usize) -> usize {
 }
 
 /// Return `true` if the [`Printer`] should indicate that a rule is fixable.
-const fn show_fix_status(fix_mode: flags::FixMode) -> bool {
+fn show_fix_status(fix_mode: flags::FixMode, fixables: Option<&FixableSummary>) -> bool {
     // If we're in application mode, avoid indicating that a rule is fixable.
     // If the specific violation were truly fixable, it would've been fixed in
     // this pass! (We're occasionally unable to determine whether a specific
     // violation is fixable without trying to fix it, so if fix is not
     // enabled, we may inadvertently indicate that a rule is fixable.)
-    !fix_mode.is_apply()
+    (!fix_mode.is_apply()) && fixables.is_some_and(FixableSummary::any_applicable_fixes)
 }
 
 fn print_fix_summary(writer: &mut dyn Write, fixed: &FxHashMap<String, FixTable>) -> Result<()> {
@@ -439,3 +437,80 @@ fn print_fix_summary(writer: &mut dyn Write, fixed: &FxHashMap<String, FixTable>
     }
     Ok(())
 }
+
+/// Summarizes [applicable][ruff_diagnostics::Applicability] fixes.
+#[derive(Debug)]
+struct FixableSummary {
+    applicable: u32,
+    unapplicable: u32,
+    unsafe_fixes: UnsafeFixes,
+}
+
+impl FixableSummary {
+    fn try_from(diagnostics: &Diagnostics, unsafe_fixes: UnsafeFixes) -> Option<Self> {
+        let mut applicable = 0;
+        let mut unapplicable = 0;
+
+        for message in &diagnostics.messages {
+            if let Some(fix) = &message.fix {
+                if fix.applies(unsafe_fixes.required_applicability()) {
+                    applicable += 1;
+                } else {
+                    unapplicable += 1;
+                }
+            }
+        }
+
+        if applicable == 0 && unapplicable == 0 {
+            None
+        } else {
+            Some(Self {
+                applicable,
+                unapplicable,
+                unsafe_fixes,
+            })
+        }
+    }
+
+    fn any_applicable_fixes(&self) -> bool {
+        self.applicable > 0
+    }
+}
+
+impl Display for FixableSummary {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let fix_prefix = format!("[{}]", "*".cyan());
+
+        if self.unsafe_fixes.is_enabled() {
+            write!(
+                f,
+                "{fix_prefix} {} fixable with the --fix option.",
+                self.applicable
+            )
+        } else {
+            if self.applicable > 0 && self.unapplicable > 0 {
+                let es = if self.unapplicable == 1 { "" } else { "es" };
+                write!(
+                    f,
+                    "{fix_prefix} {} fixable with the `--fix` option ({} hidden fix{es} can be enabled with the `--unsafe-fixes` option).",
+                    self.applicable, self.unapplicable
+                )
+            } else if self.applicable > 0 {
+                // Only applicable fixes
+                write!(
+                    f,
+                    "{fix_prefix} {} fixable with the `--fix` option.",
+                    self.applicable,
+                )
+            } else {
+                // Only unapplicable fixes
+                let es = if self.unapplicable == 1 { "" } else { "es" };
+                write!(
+                    f,
+                    "{} hidden fix{es} can be enabled with the `--unsafe-fixes` option.",
+                    self.unapplicable
+                )
+            }
+        }
+    }
+}
diff --git a/crates/ruff_cli/tests/integration_test.rs b/crates/ruff_cli/tests/integration_test.rs
index a47a974d8175be..28a34d7453c47c 100644
--- a/crates/ruff_cli/tests/integration_test.rs
+++ b/crates/ruff_cli/tests/integration_test.rs
@@ -46,16 +46,16 @@ fn stdin_success() {
 fn stdin_error() {
     assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
         .args(STDIN_BASE_OPTIONS)
-        .pass_stdin("import os\n"), @r#"
+        .pass_stdin("import os\n"), @r###"
     success: false
     exit_code: 1
     ----- stdout -----
     -:1:8: F401 [*] `os` imported but unused
     Found 1 error.
-    [*] 1 potentially fixable with the --fix option.
+    [*] 1 fixable with the `--fix` option.
 
     ----- stderr -----
-    "#);
+    "###);
 }
 
 #[test]
@@ -69,7 +69,7 @@ fn stdin_filename() {
     ----- stdout -----
     F401.py:1:8: F401 [*] `os` imported but unused
     Found 1 error.
-    [*] 1 potentially fixable with the --fix option.
+    [*] 1 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
@@ -87,7 +87,7 @@ fn stdin_source_type_py() {
     ----- stdout -----
     TCH.py:1:8: F401 [*] `os` imported but unused
     Found 1 error.
-    [*] 1 potentially fixable with the --fix option.
+    [*] 1 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
@@ -861,7 +861,7 @@ fn check_input_from_argfile() -> Result<()> {
         ----- stdout -----
         /path/to/a.py:1:8: F401 [*] `os` imported but unused
         Found 1 error.
-        [*] 1 potentially fixable with the --fix option.
+        [*] 1 fixable with the `--fix` option.
 
         ----- stderr -----
         "###);
@@ -869,3 +869,239 @@ fn check_input_from_argfile() -> Result<()> {
 
     Ok(())
 }
+
+#[test]
+fn check_hints_hidden_unsafe_fixes() {
+    assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
+        .args([
+            "-",
+            "--output-format=text",
+            "--isolated",
+            "--select",
+            "F601,UP034",
+            "--no-cache",
+        ])
+        .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+        @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    -:1:14: F601 Dictionary key literal `'a'` repeated
+    -:2:7: UP034 [*] Avoid extraneous parentheses
+    Found 2 errors.
+    [*] 1 fixable with the `--fix` option (1 hidden fix can be enabled with the `--unsafe-fixes` option).
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn check_hints_hidden_unsafe_fixes_with_no_safe_fixes() {
+    assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
+        .args(["-", "--output-format", "text", "--no-cache", "--isolated", "--select", "F601"])
+        .pass_stdin("x = {'a': 1, 'a': 1}\n"),
+        @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    -:1:14: F601 Dictionary key literal `'a'` repeated
+    Found 1 error.
+    1 hidden fix can be enabled with the `--unsafe-fixes` option.
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn check_shows_unsafe_fixes_with_opt_in() {
+    assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
+        .args([
+            "-",
+            "--output-format=text",
+            "--isolated",
+            "--select",
+            "F601,UP034",
+            "--no-cache",
+            "--unsafe-fixes",
+        ])
+        .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+        @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    -:1:14: F601 [*] Dictionary key literal `'a'` repeated
+    -:2:7: UP034 [*] Avoid extraneous parentheses
+    Found 2 errors.
+    [*] 2 fixable with the --fix option.
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn fix_applies_safe_fixes_by_default() {
+    assert_cmd_snapshot!(
+        Command::new(get_cargo_bin(BIN_NAME))
+            .args([
+                "-",
+                "--output-format",
+                "text",
+                "--isolated",
+                "--no-cache", 
+                "--select",
+                "F601,UP034",
+                "--fix",
+            ])
+            .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+            @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    x = {'a': 1, 'a': 1}
+    print('foo')
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn fix_applies_unsafe_fixes_with_opt_in() {
+    assert_cmd_snapshot!(
+        Command::new(get_cargo_bin(BIN_NAME))
+            .args([
+                "-",
+                "--output-format",
+                "text",
+                "--isolated",
+                "--no-cache", 
+                "--select",
+                "F601,UP034",
+                "--fix",
+                "--unsafe-fixes",
+            ])
+            .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+            @r###"
+    success: true
+    exit_code: 0
+    ----- stdout -----
+    x = {'a': 1}
+    print('foo')
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn fix_only_flag_applies_safe_fixes_by_default() {
+    assert_cmd_snapshot!(
+        Command::new(get_cargo_bin(BIN_NAME))
+            .args([
+                "-",
+                "--output-format",
+                "text",
+                "--isolated",
+                "--no-cache", 
+                "--select",
+                "F601,UP034",
+                "--fix-only",
+            ])
+            .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+            @r###"
+    success: true
+    exit_code: 0
+    ----- stdout -----
+    x = {'a': 1, 'a': 1}
+    print('foo')
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn fix_only_flag_applies_unsafe_fixes_with_opt_in() {
+    assert_cmd_snapshot!(
+        Command::new(get_cargo_bin(BIN_NAME))
+            .args([
+                "-",
+                "--output-format",
+                "text",
+                "--isolated",
+                "--no-cache", 
+                "--select",
+                "F601,UP034",
+                "--fix-only",
+                "--unsafe-fixes",
+            ])
+            .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+            @r###"
+    success: true
+    exit_code: 0
+    ----- stdout -----
+    x = {'a': 1}
+    print('foo')
+
+    ----- stderr -----
+    "###);
+}
+
+#[test]
+fn diff_shows_safe_fixes_by_default() {
+    assert_cmd_snapshot!(
+    Command::new(get_cargo_bin(BIN_NAME))
+        .args([
+            "-",
+            "--output-format",
+            "text",
+            "--isolated",
+            "--no-cache",
+            "--select",
+            "F601,UP034",
+            "--diff",
+        ])
+        .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+        @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    @@ -1,2 +1,2 @@
+     x = {'a': 1, 'a': 1}
+    -print('foo')
+    +print(('foo'))
+
+
+    ----- stderr -----
+    "###
+    );
+}
+
+#[test]
+fn diff_shows_unsafe_fixes_with_opt_in() {
+    assert_cmd_snapshot!(
+        Command::new(get_cargo_bin(BIN_NAME))
+            .args([
+                "-",
+                "--output-format",
+                "text",
+                "--isolated",
+                "--no-cache",
+                "--select",
+                "F601,UP034",
+                "--diff",
+                "--unsafe-fixes",
+            ])
+            .pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\n"),
+            @r###"
+    success: false
+    exit_code: 1
+    ----- stdout -----
+    @@ -1,2 +1,2 @@
+    -x = {'a': 1}
+    -print('foo')
+    +x = {'a': 1, 'a': 1}
+    +print(('foo'))
+
+
+    ----- stderr -----
+    "###
+    );
+}
diff --git a/crates/ruff_cli/tests/lint.rs b/crates/ruff_cli/tests/lint.rs
index 2cfae9668738cf..bef1cb7f261752 100644
--- a/crates/ruff_cli/tests/lint.rs
+++ b/crates/ruff_cli/tests/lint.rs
@@ -40,7 +40,7 @@ inline-quotes = "single"
     -:1:5: B005 Using `.strip()` with multi-character strings is misleading
     -:1:19: Q000 [*] Double quotes found but single quotes preferred
     Found 3 errors.
-    [*] 2 potentially fixable with the --fix option.
+    [*] 2 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
@@ -75,7 +75,7 @@ inline-quotes = "single"
     -:1:5: B005 Using `.strip()` with multi-character strings is misleading
     -:1:19: Q000 [*] Double quotes found but single quotes preferred
     Found 3 errors.
-    [*] 2 potentially fixable with the --fix option.
+    [*] 2 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
@@ -110,7 +110,7 @@ inline-quotes = "single"
     -:1:5: B005 Using `.strip()` with multi-character strings is misleading
     -:1:19: Q000 [*] Double quotes found but single quotes preferred
     Found 3 errors.
-    [*] 2 potentially fixable with the --fix option.
+    [*] 2 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
@@ -149,7 +149,7 @@ inline-quotes = "single"
     -:1:5: B005 Using `.strip()` with multi-character strings is misleading
     -:1:19: Q000 [*] Double quotes found but single quotes preferred
     Found 3 errors.
-    [*] 2 potentially fixable with the --fix option.
+    [*] 2 fixable with the `--fix` option.
 
     ----- stderr -----
     "###);
diff --git a/crates/ruff_diagnostics/src/fix.rs b/crates/ruff_diagnostics/src/fix.rs
index 5979286256ddbd..cbc6995b370987 100644
--- a/crates/ruff_diagnostics/src/fix.rs
+++ b/crates/ruff_diagnostics/src/fix.rs
@@ -6,21 +6,21 @@ use ruff_text_size::{Ranged, TextSize};
 use crate::edit::Edit;
 
 /// Indicates if a fix can be applied.
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
 pub enum Applicability {
-    /// The fix is safe and can always be applied.
-    /// The fix is definitely what the user intended, or it maintains the exact meaning of the code.
-    Always,
+    /// The fix is unsafe and should only be manually applied by the user.
+    /// The fix is likely to be incorrect or the resulting code may have invalid syntax.
+    Never,
 
     /// The fix is unsafe and should only be applied with user opt-in.
     /// The fix may be what the user intended, but it is uncertain; the resulting code will have valid syntax.
     Sometimes,
 
-    /// The fix is unsafe and should only be manually applied by the user.
-    /// The fix is likely to be incorrect or the resulting code may have invalid syntax.
-    Never,
+    /// The fix is safe and can always be applied.
+    /// The fix is definitely what the user intended, or it maintains the exact meaning of the code.
+    Always,
 }
 
 /// Indicates the level of isolation required to apply a fix.
@@ -133,4 +133,9 @@ impl Fix {
         self.isolation_level = isolation;
         self
     }
+
+    /// Return [`true`] if this [`Fix`] should be applied with at a given [`Applicability`].
+    pub fn applies(&self, applicability: Applicability) -> bool {
+        self.applicability >= applicability
+    }
 }
diff --git a/crates/ruff_linter/src/fix/mod.rs b/crates/ruff_linter/src/fix/mod.rs
index 770631e9f7c574..09b9a2def7fcdd 100644
--- a/crates/ruff_linter/src/fix/mod.rs
+++ b/crates/ruff_linter/src/fix/mod.rs
@@ -9,6 +9,7 @@ use ruff_source_file::Locator;
 
 use crate::linter::FixTable;
 use crate::registry::{AsRule, Rule};
+use crate::settings::types::UnsafeFixes;
 
 pub(crate) mod codemods;
 pub(crate) mod edits;
@@ -23,11 +24,22 @@ pub(crate) struct FixResult {
     pub(crate) source_map: SourceMap,
 }
 
-/// Auto-fix errors in a file, and write the fixed source code to disk.
-pub(crate) fn fix_file(diagnostics: &[Diagnostic], locator: &Locator) -> Option<FixResult> {
+/// Fix errors in a file, and write the fixed source code to disk.
+pub(crate) fn fix_file(
+    diagnostics: &[Diagnostic],
+    locator: &Locator,
+    unsafe_fixes: UnsafeFixes,
+) -> Option<FixResult> {
+    let required_applicability = unsafe_fixes.required_applicability();
+
     let mut with_fixes = diagnostics
         .iter()
-        .filter(|diag| diag.fix.is_some())
+        .filter(|diagnostic| {
+            diagnostic
+                .fix
+                .as_ref()
+                .map_or(false, |fix| fix.applies(required_applicability))
+        })
         .peekable();
 
     if with_fixes.peek().is_none() {
diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs
index 69b466cbb3d3b4..9219bfa8ef7748 100644
--- a/crates/ruff_linter/src/linter.rs
+++ b/crates/ruff_linter/src/linter.rs
@@ -32,6 +32,7 @@ use crate::message::Message;
 use crate::noqa::add_noqa;
 use crate::registry::{AsRule, Rule};
 use crate::rules::pycodestyle;
+use crate::settings::types::UnsafeFixes;
 use crate::settings::{flags, LinterSettings};
 use crate::source_kind::SourceKind;
 use crate::{directives, fs};
@@ -415,10 +416,12 @@ fn diagnostics_to_messages(
 
 /// Generate `Diagnostic`s from source code content, iteratively fixing
 /// until stable.
+#[allow(clippy::too_many_arguments)]
 pub fn lint_fix<'a>(
     path: &Path,
     package: Option<&Path>,
     noqa: flags::Noqa,
+    unsafe_fixes: UnsafeFixes,
     settings: &LinterSettings,
     source_kind: &'a SourceKind,
     source_type: PySourceType,
@@ -494,7 +497,7 @@ pub fn lint_fix<'a>(
             code: fixed_contents,
             fixes: applied,
             source_map,
-        }) = fix_file(&result.data.0, &locator)
+        }) = fix_file(&result.data.0, &locator, unsafe_fixes)
         {
             if iterations < MAX_ITERATIONS {
                 // Count the number of fixed errors.
diff --git a/crates/ruff_linter/src/message/grouped.rs b/crates/ruff_linter/src/message/grouped.rs
index 41e3f52cd118f5..df01b8a9a41079 100644
--- a/crates/ruff_linter/src/message/grouped.rs
+++ b/crates/ruff_linter/src/message/grouped.rs
@@ -13,11 +13,13 @@ use crate::message::text::{MessageCodeFrame, RuleCodeAndBody};
 use crate::message::{
     group_messages_by_filename, Emitter, EmitterContext, Message, MessageWithLocation,
 };
+use crate::settings::types::UnsafeFixes;
 
 #[derive(Default)]
 pub struct GroupedEmitter {
     show_fix_status: bool,
     show_source: bool,
+    unsafe_fixes: UnsafeFixes,
 }
 
 impl GroupedEmitter {
@@ -32,6 +34,12 @@ impl GroupedEmitter {
         self.show_source = show_source;
         self
     }
+
+    #[must_use]
+    pub fn with_unsafe_fixes(mut self, unsafe_fixes: UnsafeFixes) -> Self {
+        self.unsafe_fixes = unsafe_fixes;
+        self
+    }
 }
 
 impl Emitter for GroupedEmitter {
@@ -68,6 +76,7 @@ impl Emitter for GroupedEmitter {
                         notebook_index: context.notebook_index(message.filename()),
                         message,
                         show_fix_status: self.show_fix_status,
+                        unsafe_fixes: self.unsafe_fixes,
                         show_source: self.show_source,
                         row_length,
                         column_length,
@@ -89,6 +98,7 @@ impl Emitter for GroupedEmitter {
 struct DisplayGroupedMessage<'a> {
     message: MessageWithLocation<'a>,
     show_fix_status: bool,
+    unsafe_fixes: UnsafeFixes,
     show_source: bool,
     row_length: NonZeroUsize,
     column_length: NonZeroUsize,
@@ -138,7 +148,8 @@ impl Display for DisplayGroupedMessage<'_> {
             ),
             code_and_body = RuleCodeAndBody {
                 message,
-                show_fix_status: self.show_fix_status
+                show_fix_status: self.show_fix_status,
+                unsafe_fixes: self.unsafe_fixes
             },
         )?;
 
@@ -196,6 +207,7 @@ mod tests {
 
     use crate::message::tests::{capture_emitter_output, create_messages};
     use crate::message::GroupedEmitter;
+    use crate::settings::types::UnsafeFixes;
 
     #[test]
     fn default() {
@@ -222,4 +234,15 @@ mod tests {
 
         assert_snapshot!(content);
     }
+
+    #[test]
+    fn fix_status_unsafe() {
+        let mut emitter = GroupedEmitter::default()
+            .with_show_fix_status(true)
+            .with_show_source(true)
+            .with_unsafe_fixes(UnsafeFixes::Enabled);
+        let content = capture_emitter_output(&mut emitter, &create_messages());
+
+        assert_snapshot!(content);
+    }
 }
diff --git a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status.snap b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status.snap
index 453cf1eda49e2b..37344ef4884d37 100644
--- a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status.snap
+++ b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status.snap
@@ -3,14 +3,14 @@ source: crates/ruff_linter/src/message/grouped.rs
 expression: content
 ---
 fib.py:
-  1:8 F401 [*] `os` imported but unused
+  1:8 F401 `os` imported but unused
     |
   1 | import os
     |        ^^ F401
     |
     = help: Remove unused import: `os`
   
-  6:5 F841 [*] Local variable `x` is assigned to but never used
+  6:5 F841 Local variable `x` is assigned to but never used
     |
   4 | def fibonacci(n):
   5 |     """Compute the nth number in the Fibonacci sequence."""
diff --git a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status_unsafe.snap b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status_unsafe.snap
new file mode 100644
index 00000000000000..453cf1eda49e2b
--- /dev/null
+++ b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__grouped__tests__fix_status_unsafe.snap
@@ -0,0 +1,31 @@
+---
+source: crates/ruff_linter/src/message/grouped.rs
+expression: content
+---
+fib.py:
+  1:8 F401 [*] `os` imported but unused
+    |
+  1 | import os
+    |        ^^ F401
+    |
+    = help: Remove unused import: `os`
+  
+  6:5 F841 [*] Local variable `x` is assigned to but never used
+    |
+  4 | def fibonacci(n):
+  5 |     """Compute the nth number in the Fibonacci sequence."""
+  6 |     x = 1
+    |     ^ F841
+  7 |     if n == 0:
+  8 |         return 0
+    |
+    = help: Remove assignment to unused variable `x`
+  
+undef.py:
+  1:4 F821 Undefined name `a`
+    |
+  1 | if a == 1: pass
+    |    ^ F821
+    |
+  
+
diff --git a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status.snap b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status.snap
index a53420329c119c..77cd92056a7dee 100644
--- a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status.snap
+++ b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status.snap
@@ -2,14 +2,14 @@
 source: crates/ruff_linter/src/message/text.rs
 expression: content
 ---
-fib.py:1:8: F401 [*] `os` imported but unused
+fib.py:1:8: F401 `os` imported but unused
   |
 1 | import os
   |        ^^ F401
   |
   = help: Remove unused import: `os`
 
-fib.py:6:5: F841 [*] Local variable `x` is assigned to but never used
+fib.py:6:5: F841 Local variable `x` is assigned to but never used
   |
 4 | def fibonacci(n):
 5 |     """Compute the nth number in the Fibonacci sequence."""
diff --git a/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status_unsafe.snap b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status_unsafe.snap
new file mode 100644
index 00000000000000..a53420329c119c
--- /dev/null
+++ b/crates/ruff_linter/src/message/snapshots/ruff_linter__message__text__tests__fix_status_unsafe.snap
@@ -0,0 +1,29 @@
+---
+source: crates/ruff_linter/src/message/text.rs
+expression: content
+---
+fib.py:1:8: F401 [*] `os` imported but unused
+  |
+1 | import os
+  |        ^^ F401
+  |
+  = help: Remove unused import: `os`
+
+fib.py:6:5: F841 [*] Local variable `x` is assigned to but never used
+  |
+4 | def fibonacci(n):
+5 |     """Compute the nth number in the Fibonacci sequence."""
+6 |     x = 1
+  |     ^ F841
+7 |     if n == 0:
+8 |         return 0
+  |
+  = help: Remove assignment to unused variable `x`
+
+undef.py:1:4: F821 Undefined name `a`
+  |
+1 | if a == 1: pass
+  |    ^ F821
+  |
+
+
diff --git a/crates/ruff_linter/src/message/text.rs b/crates/ruff_linter/src/message/text.rs
index ee22415d4a47a8..867f92bc031deb 100644
--- a/crates/ruff_linter/src/message/text.rs
+++ b/crates/ruff_linter/src/message/text.rs
@@ -16,22 +16,24 @@ use crate::line_width::{LineWidthBuilder, TabSize};
 use crate::message::diff::Diff;
 use crate::message::{Emitter, EmitterContext, Message};
 use crate::registry::AsRule;
+use crate::settings::types::UnsafeFixes;
 
 bitflags! {
     #[derive(Default)]
     struct EmitterFlags: u8 {
         /// Whether to show the fix status of a diagnostic.
-        const SHOW_FIX_STATUS = 0b0000_0001;
+        const SHOW_FIX_STATUS    = 0b0000_0001;
         /// Whether to show the diff of a fix, for diagnostics that have a fix.
-        const SHOW_FIX_DIFF   = 0b0000_0010;
+        const SHOW_FIX_DIFF      = 0b0000_0010;
         /// Whether to show the source code of a diagnostic.
-        const SHOW_SOURCE     = 0b0000_0100;
+        const SHOW_SOURCE        = 0b0000_0100;
     }
 }
 
 #[derive(Default)]
 pub struct TextEmitter {
     flags: EmitterFlags,
+    unsafe_fixes: UnsafeFixes,
 }
 
 impl TextEmitter {
@@ -53,6 +55,12 @@ impl TextEmitter {
         self.flags.set(EmitterFlags::SHOW_SOURCE, show_source);
         self
     }
+
+    #[must_use]
+    pub fn with_unsafe_fixes(mut self, unsafe_fixes: UnsafeFixes) -> Self {
+        self.unsafe_fixes = unsafe_fixes;
+        self
+    }
 }
 
 impl Emitter for TextEmitter {
@@ -105,7 +113,8 @@ impl Emitter for TextEmitter {
                 sep = ":".cyan(),
                 code_and_body = RuleCodeAndBody {
                     message,
-                    show_fix_status: self.flags.intersects(EmitterFlags::SHOW_FIX_STATUS)
+                    show_fix_status: self.flags.intersects(EmitterFlags::SHOW_FIX_STATUS),
+                    unsafe_fixes: self.unsafe_fixes,
                 }
             )?;
 
@@ -134,28 +143,33 @@ impl Emitter for TextEmitter {
 pub(super) struct RuleCodeAndBody<'a> {
     pub(crate) message: &'a Message,
     pub(crate) show_fix_status: bool,
+    pub(crate) unsafe_fixes: UnsafeFixes,
 }
 
 impl Display for RuleCodeAndBody<'_> {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
         let kind = &self.message.kind;
+        if self.show_fix_status {
+            if let Some(fix) = self.message.fix.as_ref() {
+                // Do not display an indicator for unapplicable fixes
+                if fix.applies(self.unsafe_fixes.required_applicability()) {
+                    return write!(
+                        f,
+                        "{code} {fix}{body}",
+                        code = kind.rule().noqa_code().to_string().red().bold(),
+                        fix = format_args!("[{}] ", "*".cyan()),
+                        body = kind.body,
+                    );
+                }
+            }
+        };
 
-        if self.show_fix_status && self.message.fix.is_some() {
-            write!(
-                f,
-                "{code} {fix}{body}",
-                code = kind.rule().noqa_code().to_string().red().bold(),
-                fix = format_args!("[{}] ", "*".cyan()),
-                body = kind.body,
-            )
-        } else {
-            write!(
-                f,
-                "{code} {body}",
-                code = kind.rule().noqa_code().to_string().red().bold(),
-                body = kind.body,
-            )
-        }
+        write!(
+            f,
+            "{code} {body}",
+            code = kind.rule().noqa_code().to_string().red().bold(),
+            body = kind.body,
+        )
     }
 }
 
@@ -341,6 +355,7 @@ mod tests {
 
     use crate::message::tests::{capture_emitter_output, create_messages};
     use crate::message::TextEmitter;
+    use crate::settings::types::UnsafeFixes;
 
     #[test]
     fn default() {
@@ -359,4 +374,15 @@ mod tests {
 
         assert_snapshot!(content);
     }
+
+    #[test]
+    fn fix_status_unsafe() {
+        let mut emitter = TextEmitter::default()
+            .with_show_fix_status(true)
+            .with_show_source(true)
+            .with_unsafe_fixes(UnsafeFixes::Enabled);
+        let content = capture_emitter_output(&mut emitter, &create_messages());
+
+        assert_snapshot!(content);
+    }
 }
diff --git a/crates/ruff_linter/src/rules/eradicate/snapshots/ruff_linter__rules__eradicate__tests__ERA001_ERA001.py.snap b/crates/ruff_linter/src/rules/eradicate/snapshots/ruff_linter__rules__eradicate__tests__ERA001_ERA001.py.snap
index c33d3b09789787..ae9b9588724c8c 100644
--- a/crates/ruff_linter/src/rules/eradicate/snapshots/ruff_linter__rules__eradicate__tests__ERA001_ERA001.py.snap
+++ b/crates/ruff_linter/src/rules/eradicate/snapshots/ruff_linter__rules__eradicate__tests__ERA001_ERA001.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/eradicate/mod.rs
 ---
-ERA001.py:1:1: ERA001 [*] Found commented-out code
+ERA001.py:1:1: ERA001 Found commented-out code
   |
 1 | #import os
   | ^^^^^^^^^^ ERA001
@@ -16,7 +16,7 @@ ERA001.py:1:1: ERA001 [*] Found commented-out code
 3 2 | #a = 3
 4 3 | a = 4
 
-ERA001.py:2:1: ERA001 [*] Found commented-out code
+ERA001.py:2:1: ERA001 Found commented-out code
   |
 1 | #import os
 2 | # from foo import junk
@@ -33,7 +33,7 @@ ERA001.py:2:1: ERA001 [*] Found commented-out code
 4 3 | a = 4
 5 4 | #foo(1, 2, 3)
 
-ERA001.py:3:1: ERA001 [*] Found commented-out code
+ERA001.py:3:1: ERA001 Found commented-out code
   |
 1 | #import os
 2 | # from foo import junk
@@ -52,7 +52,7 @@ ERA001.py:3:1: ERA001 [*] Found commented-out code
 5 4 | #foo(1, 2, 3)
 6 5 | 
 
-ERA001.py:5:1: ERA001 [*] Found commented-out code
+ERA001.py:5:1: ERA001 Found commented-out code
   |
 3 | #a = 3
 4 | a = 4
@@ -72,7 +72,7 @@ ERA001.py:5:1: ERA001 [*] Found commented-out code
 7 6 | def foo(x, y, z):
 8 7 |     content = 1 # print('hello')
 
-ERA001.py:13:5: ERA001 [*] Found commented-out code
+ERA001.py:13:5: ERA001 Found commented-out code
    |
 11 |     # This is a real comment.
 12 |     # # This is a (nested) comment.
@@ -91,7 +91,7 @@ ERA001.py:13:5: ERA001 [*] Found commented-out code
 15 14 | 
 16 15 | #import os  # noqa: ERA001
 
-ERA001.py:21:5: ERA001 [*] Found commented-out code
+ERA001.py:21:5: ERA001 Found commented-out code
    |
 19 | class A():
 20 |     pass
@@ -109,7 +109,7 @@ ERA001.py:21:5: ERA001 [*] Found commented-out code
 23 22 | 
 24 23 | dictionary = {
 
-ERA001.py:26:5: ERA001 [*] Found commented-out code
+ERA001.py:26:5: ERA001 Found commented-out code
    |
 24 | dictionary = {
 25 |     # "key1": 123,  # noqa: ERA001
@@ -129,7 +129,7 @@ ERA001.py:26:5: ERA001 [*] Found commented-out code
 28 27 | }
 29 28 | 
 
-ERA001.py:27:5: ERA001 [*] Found commented-out code
+ERA001.py:27:5: ERA001 Found commented-out code
    |
 25 |     # "key1": 123,  # noqa: ERA001
 26 |     # "key2": 456,
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_1.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_1.py.snap
index 5bf88bfe614de8..35b0a379d0b5bc 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_1.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_1.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_1.py:3:22: B006 [*] Do not use mutable data structures for argument defaults
+B006_1.py:3:22: B006 Do not use mutable data structures for argument defaults
   |
 1 | # Docstring followed by a newline
 2 | 
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_2.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_2.py.snap
index 5cf776a5985f93..c925bc5c88a8a1 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_2.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_2.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_2.py:4:22: B006 [*] Do not use mutable data structures for argument defaults
+B006_2.py:4:22: B006 Do not use mutable data structures for argument defaults
   |
 2 | # Regression test for https://github.com/astral-sh/ruff/issues/7155
 3 | 
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_3.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_3.py.snap
index aed13094fb8042..2c821d54165614 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_3.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_3.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_3.py:4:22: B006 [*] Do not use mutable data structures for argument defaults
+B006_3.py:4:22: B006 Do not use mutable data structures for argument defaults
   |
 4 | def foobar(foor, bar={}):    
   |                      ^^ B006
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_4.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_4.py.snap
index d1452087066df9..bc73ff2c98b22b 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_4.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_4.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_4.py:7:26: B006 [*] Do not use mutable data structures for argument defaults
+B006_4.py:7:26: B006 Do not use mutable data structures for argument defaults
   |
 6 | class FormFeedIndent:
 7 |    def __init__(self, a=[]):
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap
index d741dc3258eba5..85fce0a1884205 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_5.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_5.py:5:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:5:49: B006 Do not use mutable data structures for argument defaults
   |
 5 | def import_module_wrong(value: dict[str, str] = {}):
   |                                                 ^^ B006
@@ -22,7 +22,7 @@ B006_5.py:5:49: B006 [*] Do not use mutable data structures for argument default
 8 10 | 
 9 11 | def import_module_with_values_wrong(value: dict[str, str] = {}):
 
-B006_5.py:9:61: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:9:61: B006 Do not use mutable data structures for argument defaults
    |
  9 | def import_module_with_values_wrong(value: dict[str, str] = {}):
    |                                                             ^^ B006
@@ -44,7 +44,7 @@ B006_5.py:9:61: B006 [*] Do not use mutable data structures for argument default
 13 15 | 
 14 16 | 
 
-B006_5.py:15:50: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:15:50: B006 Do not use mutable data structures for argument defaults
    |
 15 | def import_modules_wrong(value: dict[str, str] = {}):
    |                                                  ^^ B006
@@ -68,7 +68,7 @@ B006_5.py:15:50: B006 [*] Do not use mutable data structures for argument defaul
 20 22 | 
 21 23 | def from_import_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:21:54: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:21:54: B006 Do not use mutable data structures for argument defaults
    |
 21 | def from_import_module_wrong(value: dict[str, str] = {}):
    |                                                      ^^ B006
@@ -89,7 +89,7 @@ B006_5.py:21:54: B006 [*] Do not use mutable data structures for argument defaul
 24 26 | 
 25 27 | def from_imports_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:25:55: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:25:55: B006 Do not use mutable data structures for argument defaults
    |
 25 | def from_imports_module_wrong(value: dict[str, str] = {}):
    |                                                       ^^ B006
@@ -112,7 +112,7 @@ B006_5.py:25:55: B006 [*] Do not use mutable data structures for argument defaul
 29 31 | 
 30 32 | def import_and_from_imports_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:30:66: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:30:66: B006 Do not use mutable data structures for argument defaults
    |
 30 | def import_and_from_imports_module_wrong(value: dict[str, str] = {}):
    |                                                                  ^^ B006
@@ -135,7 +135,7 @@ B006_5.py:30:66: B006 [*] Do not use mutable data structures for argument defaul
 34 36 | 
 35 37 | def import_docstring_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:35:59: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:35:59: B006 Do not use mutable data structures for argument defaults
    |
 35 | def import_docstring_module_wrong(value: dict[str, str] = {}):
    |                                                           ^^ B006
@@ -158,7 +158,7 @@ B006_5.py:35:59: B006 [*] Do not use mutable data structures for argument defaul
 39 41 | 
 40 42 | def import_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:40:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:40:49: B006 Do not use mutable data structures for argument defaults
    |
 40 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
@@ -181,7 +181,7 @@ B006_5.py:40:49: B006 [*] Do not use mutable data structures for argument defaul
 44 46 | 
 45 47 | def import_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:45:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:45:49: B006 Do not use mutable data structures for argument defaults
    |
 45 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
@@ -203,7 +203,7 @@ B006_5.py:45:49: B006 [*] Do not use mutable data structures for argument defaul
 48 50 | 
 49 51 | 
 
-B006_5.py:50:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:50:49: B006 Do not use mutable data structures for argument defaults
    |
 50 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
@@ -226,7 +226,7 @@ B006_5.py:50:49: B006 [*] Do not use mutable data structures for argument defaul
 54 56 | 
 55 57 | def import_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:55:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:55:49: B006 Do not use mutable data structures for argument defaults
    |
 55 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
@@ -247,7 +247,7 @@ B006_5.py:55:49: B006 [*] Do not use mutable data structures for argument defaul
 58 60 | 
 59 61 | def import_module_wrong(value: dict[str, str] = {}):
 
-B006_5.py:59:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:59:49: B006 Do not use mutable data structures for argument defaults
    |
 59 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
@@ -267,7 +267,7 @@ B006_5.py:59:49: B006 [*] Do not use mutable data structures for argument defaul
 61 63 | 
 62 64 | 
 
-B006_5.py:63:49: B006 [*] Do not use mutable data structures for argument defaults
+B006_5.py:63:49: B006 Do not use mutable data structures for argument defaults
    |
 63 | def import_module_wrong(value: dict[str, str] = {}):
    |                                                 ^^ B006
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_6.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_6.py.snap
index f1af067d82f64f..f858253ec8d072 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_6.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_6.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_6.py:4:22: B006 [*] Do not use mutable data structures for argument defaults
+B006_6.py:4:22: B006 Do not use mutable data structures for argument defaults
   |
 2 | # Same as B006_2.py, but import instead of docstring
 3 | 
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_7.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_7.py.snap
index fbe42a7285e853..b5418395f5505c 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_7.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_7.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_7.py:4:22: B006 [*] Do not use mutable data structures for argument defaults
+B006_7.py:4:22: B006 Do not use mutable data structures for argument defaults
   |
 2 | # Same as B006_3.py, but import instead of docstring
 3 | 
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap
index 6f868ac491c64e..2f8e3285bb24a2 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__B006_B006_B008.py.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_B008.py:63:25: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:63:25: B006 Do not use mutable data structures for argument defaults
    |
 63 | def this_is_wrong(value=[1, 2, 3]):
    |                         ^^^^^^^^^ B006
@@ -21,7 +21,7 @@ B006_B008.py:63:25: B006 [*] Do not use mutable data structures for argument def
 65 67 | 
 66 68 | 
 
-B006_B008.py:67:30: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:67:30: B006 Do not use mutable data structures for argument defaults
    |
 67 | def this_is_also_wrong(value={}):
    |                              ^^ B006
@@ -41,7 +41,7 @@ B006_B008.py:67:30: B006 [*] Do not use mutable data structures for argument def
 69 71 | 
 70 72 | 
 
-B006_B008.py:73:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:73:52: B006 Do not use mutable data structures for argument defaults
    |
 71 | class Foo:
 72 |     @staticmethod
@@ -63,7 +63,7 @@ B006_B008.py:73:52: B006 [*] Do not use mutable data structures for argument def
 75 77 | 
 76 78 | 
 
-B006_B008.py:77:31: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:77:31: B006 Do not use mutable data structures for argument defaults
    |
 77 |   def multiline_arg_wrong(value={
    |  _______________________________^
@@ -97,7 +97,7 @@ B006_B008.py:82:36: B006 Do not use mutable data structures for argument default
    |
    = help: Replace with `None`; initialize within function
 
-B006_B008.py:85:20: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:85:20: B006 Do not use mutable data structures for argument defaults
    |
 85 | def and_this(value=set()):
    |                    ^^^^^ B006
@@ -117,7 +117,7 @@ B006_B008.py:85:20: B006 [*] Do not use mutable data structures for argument def
 87 89 | 
 88 90 | 
 
-B006_B008.py:89:20: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:89:20: B006 Do not use mutable data structures for argument defaults
    |
 89 | def this_too(value=collections.OrderedDict()):
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
@@ -137,7 +137,7 @@ B006_B008.py:89:20: B006 [*] Do not use mutable data structures for argument def
 91 93 | 
 92 94 | 
 
-B006_B008.py:93:32: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:93:32: B006 Do not use mutable data structures for argument defaults
    |
 93 | async def async_this_too(value=collections.defaultdict()):
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^ B006
@@ -157,7 +157,7 @@ B006_B008.py:93:32: B006 [*] Do not use mutable data structures for argument def
 95 97 | 
 96 98 | 
 
-B006_B008.py:97:26: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:97:26: B006 Do not use mutable data structures for argument defaults
    |
 97 | def dont_forget_me(value=collections.deque()):
    |                          ^^^^^^^^^^^^^^^^^^^ B006
@@ -177,7 +177,7 @@ B006_B008.py:97:26: B006 [*] Do not use mutable data structures for argument def
 99  101 | 
 100 102 | 
 
-B006_B008.py:102:46: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:102:46: B006 Do not use mutable data structures for argument defaults
     |
 101 | # N.B. we're also flagging the function call in the comprehension
 102 | def list_comprehension_also_not_okay(default=[i**2 for i in range(3)]):
@@ -198,7 +198,7 @@ B006_B008.py:102:46: B006 [*] Do not use mutable data structures for argument de
 104 106 | 
 105 107 | 
 
-B006_B008.py:106:46: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:106:46: B006 Do not use mutable data structures for argument defaults
     |
 106 | def dict_comprehension_also_not_okay(default={i: i**2 for i in range(3)}):
     |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ B006
@@ -218,7 +218,7 @@ B006_B008.py:106:46: B006 [*] Do not use mutable data structures for argument de
 108 110 | 
 109 111 | 
 
-B006_B008.py:110:45: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:110:45: B006 Do not use mutable data structures for argument defaults
     |
 110 | def set_comprehension_also_not_okay(default={i**2 for i in range(3)}):
     |                                             ^^^^^^^^^^^^^^^^^^^^^^^^ B006
@@ -238,7 +238,7 @@ B006_B008.py:110:45: B006 [*] Do not use mutable data structures for argument de
 112 114 | 
 113 115 | 
 
-B006_B008.py:114:33: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:114:33: B006 Do not use mutable data structures for argument defaults
     |
 114 | def kwonlyargs_mutable(*, value=[]):
     |                                 ^^ B006
@@ -258,7 +258,7 @@ B006_B008.py:114:33: B006 [*] Do not use mutable data structures for argument de
 116 118 | 
 117 119 | 
 
-B006_B008.py:239:20: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:239:20: B006 Do not use mutable data structures for argument defaults
     |
 237 | # B006 and B008
 238 | # We should handle arbitrary nesting of these B008.
@@ -280,7 +280,7 @@ B006_B008.py:239:20: B006 [*] Do not use mutable data structures for argument de
 241 243 | 
 242 244 | 
 
-B006_B008.py:276:27: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:276:27: B006 Do not use mutable data structures for argument defaults
     |
 275 | def mutable_annotations(
 276 |     a: list[int] | None = [],
@@ -306,7 +306,7 @@ B006_B008.py:276:27: B006 [*] Do not use mutable data structures for argument de
 282 284 | 
 283 285 | 
 
-B006_B008.py:277:35: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:277:35: B006 Do not use mutable data structures for argument defaults
     |
 275 | def mutable_annotations(
 276 |     a: list[int] | None = [],
@@ -332,7 +332,7 @@ B006_B008.py:277:35: B006 [*] Do not use mutable data structures for argument de
 282 284 | 
 283 285 | 
 
-B006_B008.py:278:62: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:278:62: B006 Do not use mutable data structures for argument defaults
     |
 276 |     a: list[int] | None = [],
 277 |     b: Optional[Dict[int, int]] = {},
@@ -357,7 +357,7 @@ B006_B008.py:278:62: B006 [*] Do not use mutable data structures for argument de
 282 284 | 
 283 285 | 
 
-B006_B008.py:279:80: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:279:80: B006 Do not use mutable data structures for argument defaults
     |
 277 |     b: Optional[Dict[int, int]] = {},
 278 |     c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
@@ -381,7 +381,7 @@ B006_B008.py:279:80: B006 [*] Do not use mutable data structures for argument de
 282 284 | 
 283 285 | 
 
-B006_B008.py:284:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:284:52: B006 Do not use mutable data structures for argument defaults
     |
 284 | def single_line_func_wrong(value: dict[str, str] = {}):
     |                                                    ^^ B006
@@ -402,7 +402,7 @@ B006_B008.py:284:52: B006 [*] Do not use mutable data structures for argument de
 287 289 | 
 288 290 | def single_line_func_wrong(value: dict[str, str] = {}):
 
-B006_B008.py:288:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:288:52: B006 Do not use mutable data structures for argument defaults
     |
 288 | def single_line_func_wrong(value: dict[str, str] = {}):
     |                                                    ^^ B006
@@ -424,7 +424,7 @@ B006_B008.py:288:52: B006 [*] Do not use mutable data structures for argument de
 291 293 | 
 292 294 | 
 
-B006_B008.py:293:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:293:52: B006 Do not use mutable data structures for argument defaults
     |
 293 | def single_line_func_wrong(value: dict[str, str] = {}):
     |                                                    ^^ B006
@@ -444,7 +444,7 @@ B006_B008.py:293:52: B006 [*] Do not use mutable data structures for argument de
 295 297 | 
 296 298 | 
 
-B006_B008.py:297:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:297:52: B006 Do not use mutable data structures for argument defaults
     |
 297 | def single_line_func_wrong(value: dict[str, str] = {}):
     |                                                    ^^ B006
@@ -465,7 +465,7 @@ B006_B008.py:297:52: B006 [*] Do not use mutable data structures for argument de
 299 301 |         ...
 300 302 | 
 
-B006_B008.py:302:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:302:52: B006 Do not use mutable data structures for argument defaults
     |
 302 |   def single_line_func_wrong(value: dict[str, str] = {
     |  ____________________________________________________^
@@ -500,7 +500,7 @@ B006_B008.py:308:52: B006 Do not use mutable data structures for argument defaul
     |
     = help: Replace with `None`; initialize within function
 
-B006_B008.py:313:52: B006 [*] Do not use mutable data structures for argument defaults
+B006_B008.py:313:52: B006 Do not use mutable data structures for argument defaults
     |
 313 | def single_line_func_wrong(value: dict[str, str] = {}):
     |                                                    ^^ B006
diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__extend_immutable_calls_arg_annotation.snap b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__extend_immutable_calls_arg_annotation.snap
index d191804dd6772c..82d3a1f8a543f5 100644
--- a/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__extend_immutable_calls_arg_annotation.snap
+++ b/crates/ruff_linter/src/rules/flake8_bugbear/snapshots/ruff_linter__rules__flake8_bugbear__tests__extend_immutable_calls_arg_annotation.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
 ---
-B006_extended.py:17:55: B006 [*] Do not use mutable data structures for argument defaults
+B006_extended.py:17:55: B006 Do not use mutable data structures for argument defaults
    |
 17 | def error_due_to_missing_import(foo: ImmutableTypeA = []):
    |                                                       ^^ B006
diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
index ce00ec0a9a768c..b8456517e9faf5 100644
--- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
+++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E731_E731.py.snap
@@ -100,7 +100,7 @@ E731.py:24:5: E731 [*] Do not assign a `lambda` expression, use a `def`
 26 27 | 
 27 28 | def scope():
 
-E731.py:57:5: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:57:5: E731 Do not assign a `lambda` expression, use a `def`
    |
 55 | class Scope:
 56 |     # E731
@@ -120,7 +120,7 @@ E731.py:57:5: E731 [*] Do not assign a `lambda` expression, use a `def`
 59 60 | 
 60 61 | class Scope:
 
-E731.py:64:5: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:64:5: E731 Do not assign a `lambda` expression, use a `def`
    |
 63 |     # E731
 64 |     f: Callable[[int], int] = lambda x: 2 * x
@@ -139,7 +139,7 @@ E731.py:64:5: E731 [*] Do not assign a `lambda` expression, use a `def`
 66 67 | 
 67 68 | def scope():
 
-E731.py:73:9: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:73:9: E731 Do not assign a `lambda` expression, use a `def`
    |
 71 |     x: Callable[[int], int]
 72 |     if True:
@@ -161,7 +161,7 @@ E731.py:73:9: E731 [*] Do not assign a `lambda` expression, use a `def`
 75 76 |         x = lambda: 2
 76 77 |     return x
 
-E731.py:75:9: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:75:9: E731 Do not assign a `lambda` expression, use a `def`
    |
 73 |         x = lambda: 1
 74 |     else:
@@ -322,7 +322,7 @@ E731.py:135:5: E731 [*] Do not assign a `lambda` expression, use a `def`
 137 138 | 
 138 139 | class TemperatureScales(Enum):
 
-E731.py:139:5: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:139:5: E731 Do not assign a `lambda` expression, use a `def`
     |
 138 | class TemperatureScales(Enum):
 139 |     CELSIUS = (lambda deg_c: deg_c)
@@ -342,7 +342,7 @@ E731.py:139:5: E731 [*] Do not assign a `lambda` expression, use a `def`
 141 142 | 
 142 143 | 
 
-E731.py:140:5: E731 [*] Do not assign a `lambda` expression, use a `def`
+E731.py:140:5: E731 Do not assign a `lambda` expression, use a `def`
     |
 138 | class TemperatureScales(Enum):
 139 |     CELSIUS = (lambda deg_c: deg_c)
diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_5.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_5.snap
index 0808aaab058fe8..6e2ade02471e95 100644
--- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_5.snap
+++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__ruf100_5.snap
@@ -1,7 +1,7 @@
 ---
 source: crates/ruff_linter/src/rules/ruff/mod.rs
 ---
-RUF100_5.py:7:5: ERA001 [*] Found commented-out code
+RUF100_5.py:7:5: ERA001 Found commented-out code
   |
 5 |     # "key1": 123,  # noqa: ERA001
 6 |     # "key2": 456,  # noqa
@@ -20,7 +20,7 @@ RUF100_5.py:7:5: ERA001 [*] Found commented-out code
 9 8 | 
 10 9 | 
 
-RUF100_5.py:11:1: ERA001 [*] Found commented-out code
+RUF100_5.py:11:1: ERA001 Found commented-out code
    |
 11 | #import os  # noqa: E501
    | ^^^^^^^^^^^^^^^^^^^^^^^^ ERA001
diff --git a/crates/ruff_linter/src/settings/mod.rs b/crates/ruff_linter/src/settings/mod.rs
index 48fdf907f8db03..881611cfc8d528 100644
--- a/crates/ruff_linter/src/settings/mod.rs
+++ b/crates/ruff_linter/src/settings/mod.rs
@@ -60,6 +60,7 @@ pub struct LinterSettings {
     pub tab_size: TabSize,
     pub task_tags: Vec<String>,
     pub typing_modules: Vec<String>,
+
     // Plugins
     pub flake8_annotations: flake8_annotations::settings::Settings,
     pub flake8_bandit: flake8_bandit::settings::Settings,
diff --git a/crates/ruff_linter/src/settings/types.rs b/crates/ruff_linter/src/settings/types.rs
index dc8a1e0f4ffd11..0bdc8b9d587cff 100644
--- a/crates/ruff_linter/src/settings/types.rs
+++ b/crates/ruff_linter/src/settings/types.rs
@@ -7,6 +7,7 @@ use std::string::ToString;
 use anyhow::{bail, Result};
 use globset::{Glob, GlobSet, GlobSetBuilder};
 use pep440_rs::{Version as Pep440Version, VersionSpecifiers};
+use ruff_diagnostics::Applicability;
 use serde::{de, Deserialize, Deserializer, Serialize};
 use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
@@ -99,7 +100,7 @@ impl PythonVersion {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, CacheKey, is_macro::Is)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, CacheKey, is_macro::Is)]
 pub enum PreviewMode {
     #[default]
     Disabled,
@@ -116,6 +117,32 @@ impl From<bool> for PreviewMode {
     }
 }
 
+#[derive(Debug, Copy, Clone, CacheKey, Default, PartialEq, Eq, is_macro::Is)]
+pub enum UnsafeFixes {
+    #[default]
+    Disabled,
+    Enabled,
+}
+
+impl From<bool> for UnsafeFixes {
+    fn from(version: bool) -> Self {
+        if version {
+            UnsafeFixes::Enabled
+        } else {
+            UnsafeFixes::Disabled
+        }
+    }
+}
+
+impl UnsafeFixes {
+    pub fn required_applicability(&self) -> Applicability {
+        match self {
+            Self::Enabled => Applicability::Sometimes,
+            Self::Disabled => Applicability::Always,
+        }
+    }
+}
+
 #[derive(Debug, Clone, CacheKey, PartialEq, PartialOrd, Eq, Ord)]
 pub enum FilePattern {
     Builtin(&'static str),
diff --git a/crates/ruff_linter/src/test.rs b/crates/ruff_linter/src/test.rs
index 75de40cd2e0d7c..27c94224d9d92d 100644
--- a/crates/ruff_linter/src/test.rs
+++ b/crates/ruff_linter/src/test.rs
@@ -26,6 +26,7 @@ use crate::message::{Emitter, EmitterContext, Message, TextEmitter};
 use crate::packaging::detect_package_root;
 use crate::registry::AsRule;
 use crate::rules::pycodestyle::rules::syntax_error;
+use crate::settings::types::UnsafeFixes;
 use crate::settings::{flags, LinterSettings};
 use crate::source_kind::SourceKind;
 use ruff_notebook::Notebook;
@@ -155,8 +156,11 @@ pub(crate) fn test_contents<'a>(
             code: fixed_contents,
             source_map,
             ..
-        }) = fix_file(&diagnostics, &Locator::new(transformed.source_code()))
-        {
+        }) = fix_file(
+            &diagnostics,
+            &Locator::new(transformed.source_code()),
+            UnsafeFixes::Enabled,
+        ) {
             if iterations < max_iterations() {
                 iterations += 1;
             } else {
@@ -294,6 +298,7 @@ pub(crate) fn print_jupyter_messages(
         .with_show_fix_status(true)
         .with_show_fix_diff(true)
         .with_show_source(true)
+        .with_unsafe_fixes(UnsafeFixes::Enabled)
         .emit(
             &mut output,
             messages,
@@ -314,6 +319,7 @@ pub(crate) fn print_messages(messages: &[Message]) -> String {
         .with_show_fix_status(true)
         .with_show_fix_diff(true)
         .with_show_source(true)
+        .with_unsafe_fixes(UnsafeFixes::Enabled)
         .emit(
             &mut output,
             messages,
diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs
index ad350a33463550..9733bbf197bdfd 100644
--- a/crates/ruff_workspace/src/configuration.rs
+++ b/crates/ruff_workspace/src/configuration.rs
@@ -24,7 +24,7 @@ use ruff_linter::rule_selector::{PreviewOptions, Specificity};
 use ruff_linter::settings::rule_table::RuleTable;
 use ruff_linter::settings::types::{
     FilePattern, FilePatternSet, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
-    Version,
+    UnsafeFixes, Version,
 };
 use ruff_linter::settings::{
     resolve_per_file_ignores, LinterSettings, DUMMY_VARIABLE_RGX, PREFIXES, TASK_TAGS,
@@ -64,6 +64,7 @@ pub struct Configuration {
     pub extend: Option<PathBuf>,
     pub fix: Option<bool>,
     pub fix_only: Option<bool>,
+    pub unsafe_fixes: Option<UnsafeFixes>,
     pub output_format: Option<SerializationFormat>,
     pub preview: Option<PreviewMode>,
     pub required_version: Option<Version>,
@@ -137,6 +138,7 @@ impl Configuration {
                 .unwrap_or_else(|| cache_dir(project_root)),
             fix: self.fix.unwrap_or(false),
             fix_only: self.fix_only.unwrap_or(false),
+            unsafe_fixes: self.unsafe_fixes.unwrap_or_default(),
             output_format: self.output_format.unwrap_or_default(),
             show_fixes: self.show_fixes.unwrap_or(false),
             show_source: self.show_source.unwrap_or(false),
@@ -365,6 +367,7 @@ impl Configuration {
             }),
             fix: options.fix,
             fix_only: options.fix_only,
+            unsafe_fixes: options.unsafe_fixes.map(UnsafeFixes::from),
             output_format: options.output_format.or_else(|| {
                 options
                     .format
@@ -418,6 +421,7 @@ impl Configuration {
             include: self.include.or(config.include),
             fix: self.fix.or(config.fix),
             fix_only: self.fix_only.or(config.fix_only),
+            unsafe_fixes: self.unsafe_fixes.or(config.unsafe_fixes),
             output_format: self.output_format.or(config.output_format),
             force_exclude: self.force_exclude.or(config.force_exclude),
             line_length: self.line_length.or(config.line_length),
diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs
index a376aea45ff116..1a79575c52ae49 100644
--- a/crates/ruff_workspace/src/options.rs
+++ b/crates/ruff_workspace/src/options.rs
@@ -89,9 +89,18 @@ pub struct Options {
 
     /// Enable fix behavior by-default when running `ruff` (overridden
     /// by the `--fix` and `--no-fix` command-line flags).
+    /// Only includes automatic fixes unless `--unsafe-fixes` is provided.
     #[option(default = "false", value_type = "bool", example = "fix = true")]
     pub fix: Option<bool>,
 
+    /// Enable application of unsafe fixes.
+    #[option(
+        default = "false",
+        value_type = "bool",
+        example = "unsafe-fixes = true"
+    )]
+    pub unsafe_fixes: Option<bool>,
+
     /// Like `fix`, but disables reporting on leftover violation. Implies `fix`.
     #[option(default = "false", value_type = "bool", example = "fix-only = true")]
     pub fix_only: Option<bool>,
diff --git a/crates/ruff_workspace/src/settings.rs b/crates/ruff_workspace/src/settings.rs
index 0e069a58c01dd1..ec4b2834d70f6a 100644
--- a/crates/ruff_workspace/src/settings.rs
+++ b/crates/ruff_workspace/src/settings.rs
@@ -1,7 +1,7 @@
 use path_absolutize::path_dedot;
 use ruff_cache::cache_dir;
 use ruff_formatter::{FormatOptions, IndentStyle, LineWidth};
-use ruff_linter::settings::types::{FilePattern, FilePatternSet, SerializationFormat};
+use ruff_linter::settings::types::{FilePattern, FilePatternSet, SerializationFormat, UnsafeFixes};
 use ruff_linter::settings::LinterSettings;
 use ruff_macros::CacheKey;
 use ruff_python_ast::PySourceType;
@@ -19,6 +19,8 @@ pub struct Settings {
     #[cache_key(ignore)]
     pub fix_only: bool,
     #[cache_key(ignore)]
+    pub unsafe_fixes: UnsafeFixes,
+    #[cache_key(ignore)]
     pub output_format: SerializationFormat,
     #[cache_key(ignore)]
     pub show_fixes: bool,
@@ -40,6 +42,7 @@ impl Default for Settings {
             output_format: SerializationFormat::default(),
             show_fixes: false,
             show_source: false,
+            unsafe_fixes: UnsafeFixes::default(),
             linter: LinterSettings::new(project_root),
             file_resolver: FileResolverSettings::new(project_root),
             formatter: FormatterSettings::default(),
diff --git a/docs/configuration.md b/docs/configuration.md
index e97374b62014af..e963c310e6000a 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -193,7 +193,9 @@ Arguments:
 
 Options:
       --fix
-          Attempt to automatically fix lint violations. Use `--no-fix` to disable
+          Apply fixes to resolve lint violations. Use `--no-fix` to disable or `--unsafe-fixes` to include unsafe fixes
+      --unsafe-fixes
+          Include fixes that may not retain the original intent of the code. Use `--no-unsafe-fixes` to disable
       --show-source
           Show violations with source code. Use `--no-show-source` to disable
       --show-fixes
@@ -203,7 +205,7 @@ Options:
   -w, --watch
           Run in watch mode by re-running whenever files change
       --fix-only
-          Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`. Use `--no-fix-only` to disable
+          Apply fixes to resolve lint violations, but don't report on leftover violations. Implies `--fix`. Use `--no-fix-only` to disable or `--unsafe-fixes` to include unsafe fixes
       --ignore-noqa
           Ignore any `# noqa` comments
       --output-format <OUTPUT_FORMAT>
diff --git a/ruff.schema.json b/ruff.schema.json
index 20199a2bd93046..de0bf5807ed9d4 100644
--- a/ruff.schema.json
+++ b/ruff.schema.json
@@ -128,7 +128,7 @@
       }
     },
     "fix": {
-      "description": "Enable fix behavior by-default when running `ruff` (overridden by the `--fix` and `--no-fix` command-line flags).",
+      "description": "Enable fix behavior by-default when running `ruff` (overridden by the `--fix` and `--no-fix` command-line flags). Only includes automatic fixes unless `--unsafe-fixes` is provided.",
       "type": [
         "boolean",
         "null"
@@ -637,6 +637,13 @@
       "items": {
         "$ref": "#/definitions/RuleSelector"
       }
+    },
+    "unsafe-fixes": {
+      "description": "Enable application of unsafe fixes.",
+      "type": [
+        "boolean",
+        "null"
+      ]
     }
   },
   "additionalProperties": false,