diff --git a/.reek.yml b/.reek.yml
index ad749c6..5d7fa4e 100644
--- a/.reek.yml
+++ b/.reek.yml
@@ -23,6 +23,8 @@ detectors:
     - initialize
     - Skunk::Cli::Application#execute
     - Skunk::Cli::Options::Argv#parse
+    - Skunk::Analysis#test_module?
+    - add_mock_methods_to_module
   TooManyInstanceVariables:
     exclude:
     - Skunk::Generator::Html::FileData
@@ -38,6 +40,8 @@ detectors:
     - Skunk::Command::StatusSharer#share_url_empty?
     - Skunk::Configuration#supported_format?
     - Skunk::Configuration#supported_formats
+    - Skunk::Analysis#test_module?
+    - Skunk::ConfigTest#setup
   ManualDispatch:
     exclude:
     - Skunk::Config#self.method_missing
@@ -45,3 +49,11 @@ detectors:
   BooleanParameter:
     exclude:
     - Skunk::Config#self.respond_to_missing?
+  DuplicateMethodCall:
+    exclude:
+    - Skunk::ConfigTest#test_add_format_ignores_duplicates
+  FeatureEnvy:
+    exclude:
+    - Skunk::Command::StatusReporter#table
+    - Skunk::Generator::HtmlReport#create_directories_and_files
+    - add_mock_methods_to_module
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index e101f19..cc7705f 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,6 +1,6 @@
 # This configuration was generated by
 # `rubocop --auto-gen-config`
-# on 2025-10-17 11:20:00 UTC using RuboCop version 1.81.1.
+# on 2025-10-17 16:20:40 UTC using RuboCop version 1.81.1.
 # The point is for the user to remove these configuration records
 # one by one as the offenses are removed from the code base.
 # Note that changes in the inspected code, or installation of new
@@ -36,11 +36,11 @@ Lint/MissingSuper:
 Metrics/AbcSize:
   Max: 18
 
-# Offense count: 8
+# Offense count: 12
 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
 # AllowedMethods: refine
 Metrics/BlockLength:
-  Max: 82
+  Max: 233
 
 # Offense count: 2
 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4cbe885..e6bc057 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## main [(unreleased)](https://github.com/fastruby/skunk/compare/v0.5.4...HEAD)
 
+* [REFACTOR: Centralize Skunk analysis into RubyCritic module](https://github.com/fastruby/skunk/pull/127)
 * [FEATURE: Add Skunk HTML Report](https://github.com/fastruby/skunk/pull/123)
 * [FEATURE: Add Skunk::Config class](https://github.com/fastruby/skunk/pull/123)
 * [FEATURE: Add Ruby 3.4 compatibility](https://github.com/fastruby/skunk/pull/124)
diff --git a/lib/skunk/commands/status_reporter.rb b/lib/skunk/commands/status_reporter.rb
index be43eef..315347a 100644
--- a/lib/skunk/commands/status_reporter.rb
+++ b/lib/skunk/commands/status_reporter.rb
@@ -10,6 +10,10 @@ module Command
     class StatusReporter < RubyCritic::Command::StatusReporter
       attr_accessor :analysed_modules
 
+      def initialize(options = {})
+        super(options)
+      end
+
       HEADINGS = %w[file skunk_score churn_times_cost churn cost coverage].freeze
       HEADINGS_WITHOUT_FILE = HEADINGS - %w[file]
       HEADINGS_WITHOUT_FILE_WIDTH = HEADINGS_WITHOUT_FILE.size * 17 # padding
@@ -38,36 +42,27 @@ def update_status_message
       private
 
       def analysed_modules_count
-        @analysed_modules_count ||= non_test_modules.count
-      end
-
-      def non_test_modules
-        @non_test_modules ||= analysed_modules.reject do |a_module|
-          module_path = a_module.pathname.dirname.to_s
-          module_path.start_with?("test", "spec") || module_path.end_with?("test", "spec")
-        end
+        analysed_modules.analysed_modules_count
       end
 
       def worst
-        @worst ||= sorted_modules.first
+        analysed_modules.worst_module
       end
 
       def sorted_modules
-        @sorted_modules ||= non_test_modules.sort_by(&:skunk_score).reverse!
+        analysed_modules.sorted_modules
       end
 
       def total_skunk_score
-        @total_skunk_score ||= non_test_modules.sum(&:skunk_score)
+        analysed_modules.skunk_score_total
       end
 
       def total_churn_times_cost
-        non_test_modules.sum(&:churn_times_cost)
+        analysed_modules.total_churn_times_cost
       end
 
       def skunk_score_average
-        return 0 if analysed_modules_count.zero?
-
-        (total_skunk_score.to_d / analysed_modules_count).to_f.round(2)
+        analysed_modules.skunk_score_average
       end
 
       def table_options
diff --git a/lib/skunk/generators/html/overview.rb b/lib/skunk/generators/html/overview.rb
index 1accdfe..78e7d2b 100644
--- a/lib/skunk/generators/html/overview.rb
+++ b/lib/skunk/generators/html/overview.rb
@@ -3,7 +3,8 @@
 require "rubycritic/generators/html/base"
 
 require "skunk/generators/html/path_truncator"
-require "skunk/generators/html/skunk_data"
+require "skunk/generators/html/file_data"
+require "skunk/rubycritic/analysed_modules_collection"
 
 module Skunk
   module Generator
@@ -19,7 +20,8 @@ def self.erb_template(template_path)
 
         def initialize(analysed_modules)
           @analysed_modules = analysed_modules
-          @data = SkunkData.new(analysed_modules)
+          @generated_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
+          @skunk_version = Skunk::VERSION
         end
 
         def file_name
@@ -29,6 +31,24 @@ def file_name
         def render
           TEMPLATE.result(binding)
         end
+
+        def analysed_modules_count
+          @analysed_modules.analysed_modules_count
+        end
+
+        def skunk_score_total
+          @analysed_modules.skunk_score_total
+        end
+
+        def skunk_score_average
+          @analysed_modules.skunk_score_average
+        end
+
+        def files
+          @files ||= @analysed_modules.sorted_modules.map do |module_data|
+            FileData.new(module_data)
+          end
+        end
       end
     end
   end
diff --git a/lib/skunk/generators/html/skunk_data.rb b/lib/skunk/generators/html/skunk_data.rb
deleted file mode 100644
index 19eadb0..0000000
--- a/lib/skunk/generators/html/skunk_data.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-require "skunk/generators/html/file_data"
-require "skunk/generators/html/path_truncator"
-
-module Skunk
-  module Generator
-    module Html
-      # Data object for the HTML overview report
-      class SkunkData
-        attr_reader :generated_at, :skunk_version,
-                    :analysed_modules_count, :skunk_score_total, :skunk_score_average,
-                    :worst_pathname, :worst_score, :files
-
-        def initialize(analysed_modules)
-          @analysed_modules = analysed_modules
-          @generated_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
-          @skunk_version = Skunk::VERSION
-
-          @analysed_modules_count = non_test_modules.count
-          @skunk_score_total = non_test_modules.sum(&:skunk_score)
-          @skunk_score_average = calculate_average
-          @worst_pathname = PathTruncator.truncate(find_worst_module&.pathname)
-          @worst_score = find_worst_module&.skunk_score
-          @files = build_files
-        end
-
-        private
-
-        def non_test_modules
-          @non_test_modules ||= @analysed_modules.reject do |a_module|
-            module_path = a_module.pathname.dirname.to_s
-            module_path.start_with?("test", "spec") || module_path.end_with?("test", "spec")
-          end
-        end
-
-        def calculate_average
-          return 0 if @analysed_modules_count.zero?
-
-          (@skunk_score_total.to_d / @analysed_modules_count).round(2)
-        end
-
-        def find_worst_module
-          @find_worst_module ||= sorted_modules.first
-        end
-
-        def sorted_modules
-          @sorted_modules ||= non_test_modules.sort_by(&:skunk_score).reverse!
-        end
-
-        def build_files
-          @build_files ||= sorted_modules.map do |module_data|
-            FileData.new(module_data)
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/skunk/generators/html/templates/skunk_overview.html.erb b/lib/skunk/generators/html/templates/skunk_overview.html.erb
index 9fea17e..cee421a 100644
--- a/lib/skunk/generators/html/templates/skunk_overview.html.erb
+++ b/lib/skunk/generators/html/templates/skunk_overview.html.erb
@@ -242,15 +242,15 @@