agentleFS
mattsearsmattsears/rails-cto/skills/rails-cto-static-analysis/SKILL.md

rails-cto-static-analysis

Skill15 starsChanged 7 months agoMITView on GitHub

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.

The file

Show its rules and text

We split this skill into the rules it gives an agent

21 rules. About 0 are common, 14 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈14

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every .rb change is analyzed with Reek, Flog, and Flay before the work is considered done.

    line 13
  2. Distinctive:

    Before running any analysis, verify each tool is installed.

    line 19
  3. Distinctive:

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

    line 29
  4. Distinctive:

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

    line 39
  5. Distinctive:

    Check for a Reek configuration file:

    line 43
  6. Very specific:

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

    line 49
  7. Very specific:

    Every Ruby method must have a comment directly above the def line describing why it exists — not what it does (the code shows that).

    line 64
  8. Distinctive:

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

    line 88
  9. Very specific:

    Test methods (it, test, describe blocks)

    line 95
  10. Distinctive:

    Run Reek on each changed file individually:

    line 103
  11. Distinctive:

    Use this table to decide what to fix and how:

    line 125
  12. Distinctive:

    Refactor silently: when the fix is internal (Extract Method, rename, extract local variable).

    line 146
  13. Distinctive:

    Ask the user first: if the fix would rename a public method, change a method signature, or move a method to a different class.

    line 147
  14. Distinctive:

    After fixing, re-run Reek on the file to verify the smell is gone.

    line 148
  15. Distinctive:

    Run Flog on each changed file individually:

    line 152
  16. Distinctive:

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

    line 187
  17. Very specific:

    If the directory contains more than 20 .rb files, limit to the changed file plus the 10 most recently modified siblings:

    line 199
  18. Very specific:

    If only one .rb file exists in the directory, skip Flay for that file — duplication detection requires at least two files.

    line 203
  19. Distinctive:

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

    line 251
  20. Distinctive:

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

    line 255
  21. Very specific:

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

    line 274

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.