agentsclimarketplace

Rails cto static analysis

Skill mattsears/rails-cto/skills/rails-cto-static-analysis

Run Reek, Flog, and Flay static analysis on changed Ruby files and auto-refactor when issues are found. Use after modifying any .rb file. Also use when the user mentions "reek", "flog", "flay", "code smells", "complexity", "duplication", "static analysis", or "refactor". Proactively invoke this skill after code changes, even if the user doesn't ask.From its SKILL.md

Install
npx -y skills add mattsears/rails-cto --skill rails-cto-static-analysis

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 14 stars14 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.1 KB, as published. Nobody here has run it

Static Analysis (Reek, Flog, Flay)

Every .rb change is analyzed with Reek, Flog, and Flay before the work is considered done. Code smells are fixed, complex methods are refactored, and duplication is eliminated. This skill runs before RuboCop and tests — refactor first, then lint and verify.

Pre-flight

Check tool availability

Before running any analysis, verify each tool is installed. Run all three checks:

bundle exec reek --version 2>/dev/null
bundle exec ruby -e "require 'flog'" 2>/dev/null
bundle exec flay --version 2>/dev/null

Note: Flog does not support a --version flag. Use require 'flog' to verify it's installed.

If a tool is not available, print this message and skip that tool's steps (but continue with the others):

[tool] is not installed. Add it to your Gemfile under :development:

gem "[tool]", require: false

Then run bundle install.

If none of the three tools are available, stop and inform the user that static analysis cannot run.

Install .reek.yml if missing

Check for a Reek configuration file:

ls .reek.yml 2>/dev/null

If .reek.yml does not exist, create it with the Rails-friendly defaults from the Configuration section below. If it already exists, leave it as-is.

Identify changed files

Collect all .rb files that have been created or modified:

git diff --name-only --diff-filter=ACMR HEAD 2>/dev/null | grep -E '\.rb$' | sort -u
git diff --name-only --diff-filter=ACMR 2>/dev/null | grep -E '\.rb$' | sort -u

Combine and deduplicate both lists. If no .rb files changed, skip all scans and report "No Ruby files changed — static analysis skipped."

Step 1: Method Documentation Check

Every Ruby method must have a comment directly above the def line describing why it exists — not what it does (the code shows that). Focus on intent, context, or the business reason.

Scan changed files

For each changed .rb file, scan for def declarations and verify a comment appears on the line(s) immediately above. If any methods are missing a comment, add one before proceeding.

What a good comment looks like

# Ensures the user sees their most relevant posts first,
# because recently active tags reflect current interests.
def prioritized_posts
  posts.joins(:tags).order("tags.updated_at DESC")
end

# Strips tracking parameters so we store clean URLs
# and don't leak referral data to downstream services.
def sanitize_url(url)
  URI.parse(url).tap { |u| u.query = nil }.to_s
end

What to skip

Do not add comments to trivial or framework-conventional methods where intent is self-evident:

  • initialize with simple assignment
  • Single-line delegation (delegate :name, to: :user)
  • Accessor-style methods (def name = @name)
  • Standard Rails callbacks already named descriptively (before_save :normalize_email)
  • Empty method stubs or super-only overrides
  • Test methods (it, test, describe blocks)

Auto-fix

For each undocumented method, read the method body and write a one-line comment explaining why the method exists. If the reason isn't clear from context, write what it does and flag it for the user to refine. After adding comments, move on to Reek.

Step 2: Reek — Code Smell Detection

Run Reek on each changed file individually:

bundle exec reek path/to/changed_file.rb

For multiple changed files:

bundle exec reek app/models/user.rb app/commands/users/create.rb app/controllers/users_controller.rb

Interpreting Reek output

Reek reports warnings in this format:

app/models/user.rb -- 2 warnings:
  [4]:UncommunicativeMethodName: User#x has the name 'x'
  [12]:TooManyStatements: User#process has approx 15 statements

Use this table to decide what to fix and how:

SmellWhen it's realAuto-fix
TooManyStatements> 10 statements in a non-migration methodExtract into private methods or a service/command object
LongParameterList> 4 parametersIntroduce keyword arguments or a parameter object
FeatureEnvyMethod uses another object's data more than its ownMove the method to the object it references most
DataClump3+ methods share the same parameter groupExtract a value object
DuplicateMethodCallSame call appears 3+ times in one methodExtract to a local variable
UncommunicativeVariableNameSingle-letter or cryptic namesRename to something descriptive
UncommunicativeMethodNameSingle-letter or cryptic namesRename to something descriptive
NilCheckExplicit nil? checksFix only if it masks a real nil-safety issue — often noise in Rails
UtilityFunctionMethod doesn't use selfFix in models and services; ignore in helpers and decorators
TooManyInstanceVariables> 6 instance variables in a classExtract a value object or split responsibilities
TooManyMethods> 20 methods in a classExtract concerns or split into smaller classes
ControlCoupleMethod behavior depends on a boolean/flag argReplace with two methods or use polymorphism — ignore in controllers
BooleanParameterdef method(flag = true)Replace with two methods — ignore in controllers and helpers

Auto-fix rules

  • For each Reek warning, apply the fix from the table above.
  • Refactor silently when the fix is internal (Extract Method, rename, extract local variable).
  • Ask the user first if the fix would rename a public method, change a method signature, or move a method to a different class.
  • After fixing, re-run Reek on the file to verify the smell is gone.

Step 3: Flog — Complexity Measurement

Run Flog on each changed file individually:

bundle exec flog path/to/changed_file.rb

Interpreting Flog output

Flog outputs a pain score per method, sorted by complexity:

    47.2: User#process          app/models/user.rb:12-45
    18.3: User#validate_email   app/models/user.rb:50-62
     6.1: User#name             app/models/user.rb:8-10

Higher scores mean more complex, harder-to-maintain code.

ScoreVerdictAction
≤ 10TrivialNo action needed
11–25AcceptableNo action needed
26–60Too complexMust refactor — extract methods, simplify conditionals, reduce nesting
> 60SevereStop and refactor immediately — this method is a maintenance hazard

Auto-fix for high Flog scores

For methods scoring above 25:

  1. Identify complexity drivers — nested conditionals, long method chains, multiple responsibilities, deeply nested blocks.
  2. Apply Extract Method — pull cohesive blocks into private methods with descriptive names.
  3. Simplify conditionals — replace nested if/else with guard clauses, early returns, or case statements.
  4. Split responsibilities — if a method does more than one thing, extract a command or service object.
  5. Re-run Flog to verify the score dropped below 25.

If the score remains above 25 after one refactoring pass, report the method and its score to the user and move on.

Step 4: Flay — Duplication Detection

Flay identifies structural similarities in code, ignoring surface-level differences like variable names, literal values, and whitespace.

Determine scan scope

For each changed .rb file, collect its sibling files:

  1. Identify the parent directory of the changed file (e.g., app/models/ for app/models/user.rb).
  2. Collect all .rb files in that directory.
  3. If the directory contains more than 20 .rb files, limit to the changed file plus the 10 most recently modified siblings:
    ls -t app/models/*.rb | head -10
    
  4. If only one .rb file exists in the directory, skip Flay for that file — duplication detection requires at least two files.

Run Flay

bundle exec flay app/models/*.rb

Or with a specific set of files:

bundle exec flay app/models/user.rb app/models/account.rb app/models/profile.rb

Interpreting Flay output

Flay reports structural duplication with a mass score:

1) IDENTICAL code found in :defn (mass = 72)
  app/models/user.rb:15
  app/models/account.rb:22

2) Similar code found in :defn (mass = 32)
  app/controllers/users_controller.rb:10
  app/controllers/accounts_controller.rb:12
MassVerdictAction
< 16InsignificantNo action needed
16–50Moderate duplicationExtract shared logic into a concern, module, or shared method
> 50Significant duplicationMust extract — this is copy-paste code that will drift

Auto-fix for duplication

For nodes with mass ≥ 16:

  1. Read both locations — understand the duplicated structure.
  2. Choose an extraction target:
    • Models → shared concern in app/models/concerns/
    • Controllers → controller concern in app/controllers/concerns/
    • Commands/services → shared module or base class
    • Same file → private method
  3. Extract the shared logic into the chosen target.
  4. Include the concern or module in both original locations.
  5. Re-run Flay to verify the mass dropped below 16.

If the duplication spans fundamentally different contexts where extraction would be forced or artificial, report it to the user instead of extracting.

Verify and summarize

After all three tools have run and fixes have been applied:

  1. Re-run all three tools on the changed files to confirm fixes took effect.
  2. Produce a brief summary:
**Static Analysis Summary**
- Reek: N smells found, N fixed, N remaining
- Flog: N methods above threshold (25), N refactored
- Flay: N duplications (mass ≥ 16), N extracted
- Status: PASS / NEEDS ATTENTION

PASS means all issues were resolved or no issues were found. NEEDS ATTENTION means some issues remain that require manual intervention — list them with file, line, and description.

Configuration

.reek.yml — Rails-friendly defaults

If the project has no .reek.yml, create this file in the project root:

---
# Rails-friendly Reek configuration
# Generated by rails-cto-static-analysis

detectors:
  IrresponsibleModule:
    enabled: false
  InstanceVariableAssumption:
    enabled: false
  TooManyStatements:
    max_statements: 10
  ControlCouple:
    exclude:
      - !ruby/regexp /app\/controllers/
  BooleanParameter:
    exclude:
      - !ruby/regexp /app\/controllers/
      - !ruby/regexp /app\/helpers/
  FeatureEnvy:
    exclude:
      - !ruby/regexp /app\/helpers/
      - !ruby/regexp /app\/decorators/
  UtilityFunction:
    exclude:
      - !ruby/regexp /app\/helpers/
      - !ruby/regexp /app\/decorators/
  UncommunicativeMethodName:
    accept:
      - e
      - t
      - q
      - x
      - y
  LongParameterList:
    max_params: 4
  TooManyInstanceVariables:
    max_instance_variables: 6
  TooManyMethods:
    max_methods: 20

directories:
  "test":
    enabled: false
  "db/migrate":
    TooManyStatements:
      enabled: false
    FeatureEnvy:
      enabled: false

Thresholds summary

ToolMetricThresholdAction
ReekCode smellAny warningAuto-fix per interpretation table
FlogMethod complexity> 25 per methodMust refactor
FlogSevere complexity> 60 per methodStop and refactor immediately
FlayStructural duplicationMass ≥ 16Extract shared logic

Quick Reference

TaskCommand
Scan one file for smellsbundle exec reek path/to/file.rb
Scan one file for complexitybundle exec flog path/to/file.rb
Scan directory for duplicationbundle exec flay path/to/dir/*.rb
Scan specific files for duplicationbundle exec flay file1.rb file2.rb

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.