v0.2.0 · public · MIT

Runnable Rails
checker skills.

A collection of deterministic, CI-friendly linters that run alongside the dte-skills toolchain — fast, exact checks you can gate in CI.

The deterministic layer

Most of a Rails AI toolchain is LLM-driven — coders, reviewers. These are the other half: fast, exact, reproducible, gate-able in CI. They also run as a grounding pre-pass for the LLM reviewers in dte-skills before its lenses fire.

This repo is a staging home. Checkers land here first; once a category can stand on its own it graduates into a focused plugin — the way the Hotwire checkers became hotwire-rails-toolkit.

Skills

Five shipped. Each script runs standalone against any Rails app and exits non-zero on findings.

layer-boundary-lint

Rails layering violations the architecture books describe but no tool gates:

  • Current. read in models
  • request/params in the domain layer (services and interactors)
  • raw .where/.order/.joins in controllers/views
  • mailer/HTTP I/O in after_* callbacks
  • off-layer Current writes · oversized Current
Ships lint_layer_boundaries.sh (bash + python3) · reference guide

rails-test-smell-checker

Test smells across Minitest and RSpec:

  • sleep in system tests
  • missing WebMock.disable_net_connect!
  • stubbing the system under test
  • has_css?/has_content? inside an assertion
  • caveated heuristics (Mystery Guest)
Ships lint_test_smells.sh (python3) · reference guide

rails-n1-guardrail-check

Asserts N+1 defenses exist — not a general detector (Bullet/Prosopite own that):

  • no strict_loading / detection gem wired
  • .count on an association in views/loops
  • relation-breakers (.order/.first/.pluck) inside .each
Ships lint_n1_guardrails.sh (bash + python3) · reference guide

rails-csv-io

CSV import/export footguns, plus a streaming importer + exporter template:

  • whole-file CSV.read / parse(File.read (memory)
  • missing encoding: / BOM handling
  • bang-persist in a row loop — no transaction, no per-row error reporting
Ships lint_csv_io.sh (bash + python3) · template · reference guide

cable-stream-security

ActionCable / Turbo-Stream hardening:

  • stream_from without authorizing / reject
  • constantize on client-supplied params/dataset
  • missing allowed_request_origins
  • absent CSP connect-src
Ships lint_cable_security.sh (bash + python3) · reference guide

Install

As standalone tools, or as a Claude Code plugin.

run the scripts directly
# exits non-zero on findings — CI-friendly
skills/layer-boundary-lint/scripts/lint_layer_boundaries.sh app/
skills/rails-test-smell-checker/scripts/lint_test_smells.sh app/
as a Claude Code plugin
claude plugin marketplace add davidteren/dte-rails-toolkit
claude plugin install dte-rails-toolkit@dte-rails-toolkit-marketplace

layer-boundary-lint: rules are individually skippable by label; STRICT=1 fails on advisories; CURRENT_ATTR_MAX tunes the threshold. rails-test-smell-checker: high-confidence smells fail; heuristics only fail under --strict.

The bar for adding a checker

Three rules. A checker ships only if it clears all three.

Deterministic, names its ceiling

Heuristic text/AST scans, not full parsers — each script says so. A clean run is a gate, not a proof.

Verified both ways

Run against a real app (must be truthful — no false positives) and a synthetic broken case (must flag it).

False positives are the failure mode

A rule that can't be made high-confidence cheaply is demoted to a caveated heuristic or dropped — never shipped loose.

Backlog

Candidate checkers distilled from a review of 8 Rails reference books. The v0.2.0 batch (rails-n1-guardrail-check, rails-csv-io, cable-stream-security) shipped — see Skills above. ◐ parked

  • ◐
    geocoding-guard / ruby-hotspot-finder — likely fold into existing skills (performance-reviewer / rails-testing) rather than ship standalone. Not a TODO.