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.
In this repository17 other files it gives its agents.
- claude/CLAUDE.mdCLAUDE.md
- rails-cto-apiSkill
- rails-cto-architectSkill
- rails-cto-commitSkill
- rails-cto-engineerSkill
- rails-cto-erbSkill
- rails-cto-minitestSkill
- rails-cto-production-prSkill
- rails-cto-pull-requestSkill
- rails-cto-qaSkill
- rails-cto-restfulSkill
- rails-cto-securitySkill
- rails-ctoSkill
- rails-cto-stimulusSkill
- rails-cto-tailwindSkill
- rails-upgradeSkill
- rails-viewcomponentsSkill
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
- Very specific: line 13
Every .rb change is analyzed with Reek, Flog, and Flay before the work is considered done.
- Distinctive: line 19
Before running any analysis, verify each tool is installed.
- Distinctive: line 29
If a tool is not available, print this message and skip that tool's steps (but continue with the others):
- Distinctive: line 39
If none of the three tools are available, stop and inform the user that static analysis cannot run.
- Distinctive: line 43
Check for a Reek configuration file:
- Very specific: line 49
If .reek.yml does not exist, create it with the Rails-friendly defaults from the Configuration section below.
- Very specific: line 64
Every Ruby method must have a comment directly above the def line describing why it exists — not what it does (the code shows that).
- Distinctive: line 88
Do not add comments to trivial or framework-conventional methods where intent is self-evident:
- Very specific: line 95
Test methods (it, test, describe blocks)
- Distinctive: line 103
Run Reek on each changed file individually:
- Distinctive: line 125
Use this table to decide what to fix and how:
- Distinctive: line 146
Refactor silently: when the fix is internal (Extract Method, rename, extract local variable).
- Distinctive: line 147
Ask the user first: if the fix would rename a public method, change a method signature, or move a method to a different class.
- Distinctive: line 148
After fixing, re-run Reek on the file to verify the smell is gone.
- Distinctive: line 152
Run Flog on each changed file individually:
- Distinctive: line 187
If the score remains above 25 after one refactoring pass, report the method and its score to the user and move on.
- Very specific: line 199
If the directory contains more than 20 .rb files, limit to the changed file plus the 10 most recently modified siblings:
- Very specific: line 203
If only one .rb file exists in the directory, skip Flay for that file — duplication detection requires at least two files.
- Distinctive: line 251
If the duplication spans fundamentally different contexts where extraction would be forced or artificial, report it to the user instead of …
- Distinctive: line 255
After all three tools have run and fixes have been applied:
- Very specific: line 274
If the project has no .reek.yml, create this file in the project root:
≈ “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.
Files
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/nullNote: 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: falseThen 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/nullIf .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 -uCombine 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
endWhat to skip
Do not add comments to trivial or framework-conventional methods where intent is self-evident:
initializewith 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,describeblocks)
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.rbFor multiple changed files:
bundle exec reek app/models/user.rb app/commands/users/create.rb app/controllers/users_controller.rbInterpreting 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 statementsUse this table to decide what to fix and how:
| Smell | When it's real | Auto-fix |
TooManyStatements | > 10 statements in a non-migration method | Extract into private methods or a service/command object |
LongParameterList | > 4 parameters | Introduce keyword arguments or a parameter object |
FeatureEnvy | Method uses another object's data more than its own | Move the method to the object it references most |
DataClump | 3+ methods share the same parameter group | Extract a value object |
DuplicateMethodCall | Same call appears 3+ times in one method | Extract to a local variable |
UncommunicativeVariableName | Single-letter or cryptic names | Rename to something descriptive |
UncommunicativeMethodName | Single-letter or cryptic names | Rename to something descriptive |
NilCheck | Explicit nil? checks | Fix only if it masks a real nil-safety issue — often noise in Rails |
UtilityFunction | Method doesn't use self | Fix in models and services; ignore in helpers and decorators |
TooManyInstanceVariables | > 6 instance variables in a class | Extract a value object or split responsibilities |
TooManyMethods | > 20 methods in a class | Extract concerns or split into smaller classes |
ControlCouple | Method behavior depends on a boolean/flag arg | Replace with two methods or use polymorphism — ignore in controllers |
BooleanParameter | def 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.rbInterpreting 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-10Higher scores mean more complex, harder-to-maintain code.
| Score | Verdict | Action |
| ≤ 10 | Trivial | No action needed |
| 11–25 | Acceptable | No action needed |
| 26–60 | Too complex | Must refactor — extract methods, simplify conditionals, reduce nesting |
| > 60 | Severe | Stop and refactor immediately — this method is a maintenance hazard |
Auto-fix for high Flog scores
For methods scoring above 25:
- Identify complexity drivers — nested conditionals, long method chains, multiple responsibilities, deeply nested blocks.
- Apply Extract Method — pull cohesive blocks into private methods with descriptive names.
- Simplify conditionals — replace nested
if/elsewith guard clauses, early returns, orcasestatements. - Split responsibilities — if a method does more than one thing, extract a command or service object.
- 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:
- Identify the parent directory of the changed file (e.g.,
app/models/forapp/models/user.rb). - Collect all
.rbfiles in that directory. - If the directory contains more than 20
.rbfiles, limit to the changed file plus the 10 most recently modified siblings:ls -t app/models/*.rb | head -10 - If only one
.rbfile exists in the directory, skip Flay for that file — duplication detection requires at least two files.
Run Flay
bundle exec flay app/models/*.rbOr with a specific set of files:
bundle exec flay app/models/user.rb app/models/account.rb app/models/profile.rbInterpreting 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| Mass | Verdict | Action |
| < 16 | Insignificant | No action needed |
| 16–50 | Moderate duplication | Extract shared logic into a concern, module, or shared method |
| > 50 | Significant duplication | Must extract — this is copy-paste code that will drift |
Auto-fix for duplication
For nodes with mass ≥ 16:
- Read both locations — understand the duplicated structure.
- 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
- Models → shared concern in
- Extract the shared logic into the chosen target.
- Include the concern or module in both original locations.
- 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:
- Re-run all three tools on the changed files to confirm fixes took effect.
- 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 ATTENTIONPASS 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: falseThresholds summary
| Tool | Metric | Threshold | Action |
| Reek | Code smell | Any warning | Auto-fix per interpretation table |
| Flog | Method complexity | > 25 per method | Must refactor |
| Flog | Severe complexity | > 60 per method | Stop and refactor immediately |
| Flay | Structural duplication | Mass ≥ 16 | Extract shared logic |
Quick Reference
| Task | Command |
| Scan one file for smells | bundle exec reek path/to/file.rb |
| Scan one file for complexity | bundle exec flog path/to/file.rb |
| Scan directory for duplication | bundle exec flay path/to/dir/*.rb |
| Scan specific files for duplication | bundle exec flay file1.rb file2.rb |
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
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.

