From rails-toolkit
Use when auditing, reviewing, or doing a health-check of an existing/inherited Rails app — onboarding to a legacy codebase, assessing technical debt, or a pre-engagement code review. Orchestrates the deep-dive rails-* skills and produces a severity-ranked report. Triggers on: code audit, app review, legacy/inherited Rails app, technical debt assessment, 'review my Rails app'.
How this skill is triggered — by the user, by Claude, or both
Slash command
/rails-toolkit:rails-auditThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A top-level health-check for an **existing** Rails app — inheriting a legacy codebase,
A top-level health-check for an existing Rails app — inheriting a legacy codebase, onboarding to an unfamiliar project, or doing a pre-engagement review. This skill is the entry point for reviewing an app, the counterpart to [[rails-core]] which is the entry point for writing one.
It orchestrates: it owns the broad health-check items nothing else covers (version pinning, dependency CVEs, exposed secrets, seeds, tech-debt) and hands off the deep dives to the specialist skills ([[rails-database-performance]], [[rails-security]], [[rails-performance]], [[rails-testing]], [[rails-upgrade]]). Do not re-derive what those skills already do — run the cheap detection here, then delegate the fix.
The audit ends in a written, severity-ranked report (see Producing the Report).
Gemfile, app/, config/ present).file:line (the audit must point at real code, not generalities).A shared, explicit version is the baseline for reproducible builds. Check the version is pinned and still supported.
cat .ruby-version 2>/dev/null || echo "MISSING .ruby-version"
grep -nE '^\s*ruby\s+["'\'']' Gemfile
grep -nE '^\s*gem\s+["'\'']rails["'\'']' Gemfile
ruby -v; bin/rails -v 2>/dev/null
.ruby-version → 🟡 add one so every dev/CI uses the same interpreter.gem "rails" with no version, or a loose >=) → 🟡 a bundle update can silently jump majors. Lock it.head -1 Gemfile # source must be HTTPS
grep -nE 'cooldown' Gemfile .bundle/config 2>/dev/null # supply-chain cooldown set?
grep -nE 'group\s+:' Gemfile # dev/test gems grouped out of production?
source 'http://...' (not HTTPS) → 🔴.source "https://rubygems.org", cooldown: 4 so freshly-hijacked gem releases can't resolve for 4 days. Rationale and scope rules: [[rails-project-setup]].group :development, :test do … end, so a production deploy run with BUNDLE_WITHOUT=development:test (or bundle install --without development test) neither installs nor loads them: smaller image, faster boot, smaller attack surface.Don't flag missing per-gem version pins. With a committed
Gemfile.lock(andbundle install --deployment/BUNDLE_FROZEN=trueon deploy), every version is already frozen; loose constraints in theGemfileare fine.
Two free, fast scanners. Run both.
gem install bundler-audit 2>/dev/null; bundle exec bundler-audit check --update 2>/dev/null || bundler-audit check --update
gem install brakeman 2>/dev/null; bundle exec brakeman -q -A 2>/dev/null || brakeman -q -A
bundler-audit flags Gemfile.lock gems with known CVEs and the patched version → 🔴/🟡 by criticality. Record each advisory + the upgrade target.brakeman flags code-level issues (SQLi, mass-assignment, unsafe redirects, XSS). Triage each warning; confidence High first → 🔴.Secrets in the repo (or in git history) are the highest-impact, easiest-to-miss finding.
grep -rinE '(password|secret|api[_-]?key|access[_-]?key|token)\s*[:=]\s*["'\''][^"'\'' ]{6,}' config/ app/ lib/ 2>/dev/null
git log --oneline -- config/master.key config/credentials.yml.enc 2>/dev/null
grep -nE 'config/master.key|config/credentials.*\.key|\.env' .gitignore 2>/dev/null
config/environments/production.rb, initializers, or *.yml → 🔴. Move to encrypted credentials (bin/rails credentials:edit) or ENV.config/master.key or any .env NOT gitignored → 🔴. Modern Rails stores secrets in config/credentials.yml.enc (encrypted, committable) decrypted by master.key (which must stay out of git).A suite that nobody has touched in a year is a liability, not a safety net.
git log -1 --pretty=format:'%ci %s' -- test/ spec/ 2>/dev/null; echo
ls -d test spec 2>/dev/null
grep -c . <(find app -name '*.rb') ; find test spec -name '*_test.rb' -o -name '*_spec.rb' 2>/dev/null | wc -l
test//spec/ at all, or near-empty → 🔴 no regression safety net.Developers must be able to stand up a working local DB without a production dump.
test -s db/seeds.rb && echo "seeds.rb present ($(wc -l < db/seeds.rb) lines)" || echo "MISSING/empty db/seeds.rb"
grep -nE 'find_or_create_by|destroy_all|delete_all' db/seeds.rb 2>/dev/null
db/seeds.rb → 🟡 onboarding requires copying prod data (privacy + size risk).create! that dupes on re-run) → 🟢 prefer find_or_create_by so seeds can be loaded, cleared, and re-loaded cleanly.bundle exec rubocop --format offenses 2>/dev/null | tail -20 || bundle exec standardrb 2>/dev/null | tail -20
ls .rubocop.yml .standard.yml 2>/dev/null
rubocop-rails or standard for consistent style.rubocop --auto-gen-config to baseline, then fix incrementally.A fast smell test before the full schema audit. Foreign keys without indexes are the most common Rails performance bug.
echo "FK-ish columns:"; grep -E '_id' db/schema.rb | grep -v 'add_index\|t\.index' | wc -l
echo "indexes:"; grep -E 'add_index|t\.index' db/schema.rb | wc -l
grep -rnE '\.(each|map)\b' app/views/ app/controllers/ 2>/dev/null | head -20 # loops that may trigger per-row queries
grep -rnE '\.includes\(|\.preload\(|\.eager_load\(' app/ 2>/dev/null | wc -l # is eager loading used at all?
includes/preload → 🟡 probable N+1. Spot-check the dev log (or add prosopite — near-zero false positives, unlike bullet) to confirm.Production footguns — cheap greps for configurations that cause outages, not just slowness:
grep -nE 'puma_worker_killer|unicorn-worker-killer' Gemfile # memory-threshold worker killers
grep -rnE 'send_data|send_file' app/controllers/ | head # large files served from the web process
grep -rnE 'queue_adapter\s*=\s*:inline|Resque\.inline' config/ | grep -v development # inline jobs outside dev
grep -rnE 'timeout' config/initializers/*elastic* config/initializers/*search* config/initializers/*redis* 2>/dev/null # client timeouts set at all?
send_data of generated content (CSV/zip/PDF) → 🟡 memory bloat + blocked threads; move generation to a job, serve from storage. → [[rails-jobs]]:inline job adapter in test/production config → 🟡 → [[rails-testing]]Cheap size heuristics surface the files most likely to hide problems.
echo "Fattest models:"; wc -l app/models/**/*.rb 2>/dev/null | sort -rn | head -10
echo "Fattest controllers:"; wc -l app/controllers/**/*.rb 2>/dev/null | sort -rn | head -10
echo "Service-object sprawl:"; ls app/services 2>/dev/null | wc -l
grep -rnE '^\s*def ' app/controllers/ 2>/dev/null | grep -vE 'index|show|new|create|edit|update|destroy' | head # non-REST actions
app/services/ tree → 🟡 in 37signals-style Rails this is usually logic that belongs on rich models, not a service layer. Weigh against [[rails-philosophy]] before recommending more of it.grep -rinE 'todo|fixme|hack|xxx|deprecated' app/ lib/ 2>/dev/null | wc -l
grep -rinE 'todo|fixme|hack|xxx' app/ lib/ 2>/dev/null | head -40
grep -rnE '^\s*#\s*[a-z].*\b(def|end|do|=)\b' app/ lib/ 2>/dev/null | head # commented-out code
TODO/FIXME/HACK → 🟢/🟡. Decide per item: do it, ticket it, or delete the stale note.End the audit with a written report, grouped by severity (🔴 → 🟡 → 🟢). Each item:
### 🔴 <short title>
- **Where:** path/to/file.rb:42 (or: Gemfile, db/schema.rb)
- **Finding:** what's wrong, with the evidence (the grep hit / scanner line).
- **Impact:** why it matters (security / perf / maintainability / onboarding).
- **Fix:** the concrete change, and **→ which skill** to use for the deep fix.
Close with a one-paragraph summary: overall health, the top 3 things to fix first, and the recommended order (security & exposed secrets before refactors).
| # | Check | Command / signal | Deep-dive skill |
|---|---|---|---|
| 1 | Version pinning | .ruby-version, locked gem "rails", EOL? | [[rails-upgrade]] |
| 2 | Gemfile hygiene | HTTPS source, cooldown, dev/test groups | — |
| 3 | Vulnerabilities | bundler-audit, brakeman | [[rails-security]] |
| 4 | Exposed secrets | grep config/, master.key gitignored | [[rails-security]] |
| 5 | Test health | git log -1 -- test/ spec/, coverage | [[rails-testing]] |
| 6 | Seed data | db/seeds.rb present & idempotent | — |
| 7 | Lint/style | rubocop / standard offenses | [[rails-style]] |
| 8 | Schema/index | FK-count vs index-count | [[rails-database-performance]] |
| 9 | N+1/perf | loops without includes | [[rails-performance]] |
| 10 | Architecture | fat models/controllers, service sprawl | [[rails-philosophy]], [[rails-models]], [[rails-controllers]] |
| 11 | Tech debt | TODO/FIXME, dead code | — |
file:line. No evidence, no finding.Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub mickzijdel/rails-toolkit